Rollup merge of #144668 - daltenty:daltenty/runmake-llvm-components, r=jieyouxu
[test][run-make] add needs-llvm-components
Add some constraints to run-make tests that require specific target support and will fail without them.
diff --git a/Cargo.lock b/Cargo.lock
index b7fc2de..c1076f0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -443,20 +443,6 @@
[[package]]
name = "cargo_metadata"
-version = "0.19.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
-dependencies = [
- "camino",
- "cargo-platform 0.1.9",
- "semver",
- "serde",
- "serde_json",
- "thiserror 2.0.12",
-]
-
-[[package]]
-name = "cargo_metadata"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cfca2aaa699835ba88faf58a06342a314a950d2b9686165e038286c30316868"
@@ -480,6 +466,8 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
dependencies = [
+ "jobserver",
+ "libc",
"shlex",
]
@@ -670,6 +658,26 @@
]
[[package]]
+name = "cmake"
+version = "0.1.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "codespan-reporting"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
+dependencies = [
+ "serde",
+ "termcolor",
+ "unicode-width 0.2.1",
+]
+
+[[package]]
name = "collect-license-metadata"
version = "0.1.0"
dependencies = [
@@ -928,6 +936,68 @@
]
[[package]]
+name = "cxx"
+version = "1.0.161"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3523cc02ad831111491dd64b27ad999f1ae189986728e477604e61b81f828df"
+dependencies = [
+ "cc",
+ "cxxbridge-cmd",
+ "cxxbridge-flags",
+ "cxxbridge-macro",
+ "foldhash",
+ "link-cplusplus",
+]
+
+[[package]]
+name = "cxx-build"
+version = "1.0.161"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "212b754247a6f07b10fa626628c157593f0abf640a3dd04cce2760eca970f909"
+dependencies = [
+ "cc",
+ "codespan-reporting",
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "scratch",
+ "syn 2.0.104",
+]
+
+[[package]]
+name = "cxxbridge-cmd"
+version = "1.0.161"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f426a20413ec2e742520ba6837c9324b55ffac24ead47491a6e29f933c5b135a"
+dependencies = [
+ "clap",
+ "codespan-reporting",
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
+[[package]]
+name = "cxxbridge-flags"
+version = "1.0.161"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a258b6069020b4e5da6415df94a50ee4f586a6c38b037a180e940a43d06a070d"
+
+[[package]]
+name = "cxxbridge-macro"
+version = "1.0.161"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8dec184b52be5008d6eaf7e62fc1802caf1ad1227d11b3b7df2c409c7ffc3f4"
+dependencies = [
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn 2.0.104",
+]
+
+[[package]]
name = "darling"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1364,7 +1434,7 @@
dependencies = [
"anyhow",
"askama",
- "cargo_metadata 0.18.1",
+ "cargo_metadata 0.21.0",
"serde",
"serde_json",
"thiserror 1.0.69",
@@ -1388,6 +1458,17 @@
]
[[package]]
+name = "genmc-sys"
+version = "0.1.0"
+dependencies = [
+ "cc",
+ "cmake",
+ "cxx",
+ "cxx-build",
+ "git2",
+]
+
+[[package]]
name = "getopts"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1442,6 +1523,21 @@
]
[[package]]
+name = "git2"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110"
+dependencies = [
+ "bitflags",
+ "libc",
+ "libgit2-sys",
+ "log",
+ "openssl-probe",
+ "openssl-sys",
+ "url",
+]
+
+[[package]]
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1890,16 +1986,16 @@
[[package]]
name = "ipc-channel"
-version = "0.20.0"
+version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b1c98b70019c830a1fc39cecfe1f60ff99c4122f0a189697c810c90ec545c14"
+checksum = "1700f6b8b9f00cdd675f32fbb3a5be882213140dfe045805273221ca266c43f8"
dependencies = [
"bincode",
"crossbeam-channel",
"fnv",
"libc",
"mio",
- "rand 0.9.1",
+ "rand 0.9.2",
"serde",
"tempfile",
"uuid",
@@ -2075,6 +2171,19 @@
]
[[package]]
+name = "libgit2-sys"
+version = "0.18.2+1.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222"
+dependencies = [
+ "cc",
+ "libc",
+ "libz-sys",
+ "openssl-sys",
+ "pkg-config",
+]
+
+[[package]]
name = "libloading"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2114,6 +2223,15 @@
]
[[package]]
+name = "link-cplusplus"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212"
+dependencies = [
+ "cc",
+]
+
+[[package]]
name = "linkchecker"
version = "0.1.0"
dependencies = [
@@ -2322,6 +2440,7 @@
"chrono-tz",
"colored 3.0.0",
"directories",
+ "genmc-sys",
"getrandom 0.3.3",
"ipc-channel",
"libc",
@@ -2329,7 +2448,7 @@
"libloading",
"measureme",
"nix",
- "rand 0.9.1",
+ "rand 0.9.2",
"regex",
"rustc_version",
"serde",
@@ -2962,9 +3081,9 @@
[[package]]
name = "rand"
-version = "0.9.1"
+version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.3",
@@ -3048,9 +3167,9 @@
[[package]]
name = "redox_syscall"
-version = "0.5.13"
+version = "0.5.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
+checksum = "7251471db004e509f4e75a62cca9435365b5ec7bcdff530d612ac7c87c44a792"
dependencies = [
"bitflags",
]
@@ -3245,7 +3364,7 @@
version = "0.0.0"
dependencies = [
"bitflags",
- "rand 0.9.1",
+ "rand 0.9.2",
"rand_xoshiro",
"rustc_data_structures",
"rustc_hashes",
@@ -3880,7 +3999,7 @@
name = "rustc_incremental"
version = "0.0.0"
dependencies = [
- "rand 0.9.1",
+ "rand 0.9.2",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
@@ -4255,6 +4374,7 @@
"rustc-literal-escaper",
"rustc_ast",
"rustc_ast_pretty",
+ "rustc_attr_parsing",
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
@@ -4492,7 +4612,7 @@
"bitflags",
"getopts",
"libc",
- "rand 0.9.1",
+ "rand 0.9.2",
"rustc_abi",
"rustc_ast",
"rustc_data_structures",
@@ -4563,7 +4683,10 @@
"rustc_macros",
"rustc_serialize",
"rustc_span",
+ "serde",
+ "serde_derive",
"serde_json",
+ "serde_path_to_error",
"tracing",
]
@@ -4574,7 +4697,7 @@
"crossbeam-deque",
"crossbeam-utils",
"libc",
- "rand 0.9.1",
+ "rand 0.9.2",
"rand_xorshift",
"scoped-tls",
"smallvec",
@@ -4888,6 +5011,12 @@
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
+name = "scratch"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52"
+
+[[package]]
name = "self_cell"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4956,6 +5085,16 @@
]
[[package]]
+name = "serde_path_to_error"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a"
+dependencies = [
+ "itoa",
+ "serde",
+]
+
+[[package]]
name = "serde_spanned"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5270,7 +5409,7 @@
dependencies = [
"indicatif",
"num",
- "rand 0.9.1",
+ "rand 0.9.2",
"rand_chacha 0.9.0",
"rayon",
]
@@ -5356,7 +5495,7 @@
version = "0.1.0"
dependencies = [
"build_helper",
- "cargo_metadata 0.19.2",
+ "cargo_metadata 0.21.0",
"fluent-syntax",
"ignore",
"miropt-test-tools",
diff --git a/bootstrap.example.toml b/bootstrap.example.toml
index 73e93cc..ef49113 100644
--- a/bootstrap.example.toml
+++ b/bootstrap.example.toml
@@ -475,6 +475,9 @@
# Note that if any value is manually given to bootstrap such as
# `./x test tidy --extra-checks=js`, this value is ignored.
# Use `--extra-checks=''` to temporarily disable all extra checks.
+#
+# Automatically enabled in the "tools" profile.
+# Set to the empty string to force disable (recommeded for hdd systems).
#build.tidy-extra-checks = ""
# Indicates whether ccache is used when building certain artifacts (e.g. LLVM).
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 80b44e4..c240555 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -1,3 +1,4 @@
+use std::collections::BTreeSet;
use std::fmt::{self, Write};
use std::ops::{Bound, Deref};
use std::{cmp, iter};
@@ -5,7 +6,7 @@
use rustc_hashes::Hash64;
use rustc_index::Idx;
use rustc_index::bit_set::BitMatrix;
-use tracing::debug;
+use tracing::{debug, trace};
use crate::{
AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
@@ -313,7 +314,6 @@ pub fn layout_of_struct_or_enum<
scalar_valid_range: (Bound<u128>, Bound<u128>),
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
- dont_niche_optimize_enum: bool,
always_sized: bool,
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
let (present_first, present_second) = {
@@ -352,13 +352,7 @@ pub fn layout_of_struct_or_enum<
// structs. (We have also handled univariant enums
// that allow representation optimization.)
assert!(is_enum);
- self.layout_of_enum(
- repr,
- variants,
- discr_range_of_repr,
- discriminants,
- dont_niche_optimize_enum,
- )
+ self.layout_of_enum(repr, variants, discr_range_of_repr, discriminants)
}
}
@@ -599,7 +593,6 @@ fn layout_of_enum<
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
- dont_niche_optimize_enum: bool,
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
// Until we've decided whether to use the tagged or
// niche filling LayoutData, we don't want to intern the
@@ -618,7 +611,7 @@ struct TmpLayout<FieldIdx: Idx, VariantIdx: Idx> {
}
let calculate_niche_filling_layout = || -> Option<TmpLayout<FieldIdx, VariantIdx>> {
- if dont_niche_optimize_enum {
+ if repr.inhibit_enum_layout_opt() {
return None;
}
@@ -774,30 +767,63 @@ struct TmpLayout<FieldIdx: Idx, VariantIdx: Idx> {
let niche_filling_layout = calculate_niche_filling_layout();
- let (mut min, mut max) = (i128::MAX, i128::MIN);
let discr_type = repr.discr_type();
- let bits = Integer::from_attr(dl, discr_type).size().bits();
- for (i, mut val) in discriminants {
- if !repr.c() && variants[i].iter().any(|f| f.is_uninhabited()) {
- continue;
- }
- if discr_type.is_signed() {
- // sign extend the raw representation to be an i128
- val = (val << (128 - bits)) >> (128 - bits);
- }
- if val < min {
- min = val;
- }
- if val > max {
- max = val;
- }
- }
- // We might have no inhabited variants, so pretend there's at least one.
- if (min, max) == (i128::MAX, i128::MIN) {
- min = 0;
- max = 0;
- }
- assert!(min <= max, "discriminant range is {min}...{max}");
+ let discr_int = Integer::from_attr(dl, discr_type);
+ // Because we can only represent one range of valid values, we'll look for the
+ // largest range of invalid values and pick everything else as the range of valid
+ // values.
+
+ // First we need to sort the possible discriminant values so that we can look for the largest gap:
+ let valid_discriminants: BTreeSet<i128> = discriminants
+ .filter(|&(i, _)| repr.c() || variants[i].iter().all(|f| !f.is_uninhabited()))
+ .map(|(_, val)| {
+ if discr_type.is_signed() {
+ // sign extend the raw representation to be an i128
+ // FIXME: do this at the discriminant iterator creation sites
+ discr_int.size().sign_extend(val as u128)
+ } else {
+ val
+ }
+ })
+ .collect();
+ trace!(?valid_discriminants);
+ let discriminants = valid_discriminants.iter().copied();
+ //let next_discriminants = discriminants.clone().cycle().skip(1);
+ let next_discriminants =
+ discriminants.clone().chain(valid_discriminants.first().copied()).skip(1);
+ // Iterate over pairs of each discriminant together with the next one.
+ // Since they were sorted, we can now compute the niche sizes and pick the largest.
+ let discriminants = discriminants.zip(next_discriminants);
+ let largest_niche = discriminants.max_by_key(|&(start, end)| {
+ trace!(?start, ?end);
+ // If this is a wraparound range, the niche size is `MAX - abs(diff)`, as the diff between
+ // the two end points is actually the size of the valid discriminants.
+ let dist = if start > end {
+ // Overflow can happen for 128 bit discriminants if `end` is negative.
+ // But in that case casting to `u128` still gets us the right value,
+ // as the distance must be positive if the lhs of the subtraction is larger than the rhs.
+ let dist = start.wrapping_sub(end);
+ if discr_type.is_signed() {
+ discr_int.signed_max().wrapping_sub(dist) as u128
+ } else {
+ discr_int.size().unsigned_int_max() - dist as u128
+ }
+ } else {
+ // Overflow can happen for 128 bit discriminants if `start` is negative.
+ // But in that case casting to `u128` still gets us the right value,
+ // as the distance must be positive if the lhs of the subtraction is larger than the rhs.
+ end.wrapping_sub(start) as u128
+ };
+ trace!(?dist);
+ dist
+ });
+ trace!(?largest_niche);
+
+ // `max` is the last valid discriminant before the largest niche
+ // `min` is the first valid discriminant after the largest niche
+ let (max, min) = largest_niche
+ // We might have no inhabited variants, so pretend there's at least one.
+ .unwrap_or((0, 0));
let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max);
let mut align = dl.aggregate_align;
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 5bd7350..14e256b 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1205,6 +1205,19 @@ pub fn signed_max(self) -> i128 {
}
}
+ /// Returns the smallest signed value that can be represented by this Integer.
+ #[inline]
+ pub fn signed_min(self) -> i128 {
+ use Integer::*;
+ match self {
+ I8 => i8::MIN as i128,
+ I16 => i16::MIN as i128,
+ I32 => i32::MIN as i128,
+ I64 => i64::MIN as i128,
+ I128 => i128::MIN,
+ }
+ }
+
/// Finds the smallest Integer type which can represent the signed value.
#[inline]
pub fn fit_signed(x: i128) -> Integer {
@@ -1376,6 +1389,28 @@ pub fn contains(&self, v: u128) -> bool {
}
}
+ /// Returns `true` if all the values in `other` are contained in this range,
+ /// when the values are considered as having width `size`.
+ #[inline(always)]
+ pub fn contains_range(&self, other: Self, size: Size) -> bool {
+ if self.is_full_for(size) {
+ true
+ } else {
+ let trunc = |x| size.truncate(x);
+
+ let delta = self.start;
+ let max = trunc(self.end.wrapping_sub(delta));
+
+ let other_start = trunc(other.start.wrapping_sub(delta));
+ let other_end = trunc(other.end.wrapping_sub(delta));
+
+ // Having shifted both input ranges by `delta`, now we only need to check
+ // whether `0..=max` contains `other_start..=other_end`, which can only
+ // happen if the other doesn't wrap since `self` isn't everything.
+ (other_start <= other_end) && (other_end <= max)
+ }
+ }
+
/// Returns `self` with replaced `start`
#[inline(always)]
fn with_start(mut self, start: u128) -> Self {
diff --git a/compiler/rustc_abi/src/tests.rs b/compiler/rustc_abi/src/tests.rs
index d993012..d49c2d4 100644
--- a/compiler/rustc_abi/src/tests.rs
+++ b/compiler/rustc_abi/src/tests.rs
@@ -5,3 +5,66 @@ fn align_constants() {
assert_eq!(Align::ONE, Align::from_bytes(1).unwrap());
assert_eq!(Align::EIGHT, Align::from_bytes(8).unwrap());
}
+
+#[test]
+fn wrapping_range_contains_range() {
+ let size16 = Size::from_bytes(16);
+
+ let a = WrappingRange { start: 10, end: 20 };
+ assert!(a.contains_range(a, size16));
+ assert!(a.contains_range(WrappingRange { start: 11, end: 19 }, size16));
+ assert!(a.contains_range(WrappingRange { start: 10, end: 10 }, size16));
+ assert!(a.contains_range(WrappingRange { start: 20, end: 20 }, size16));
+ assert!(!a.contains_range(WrappingRange { start: 10, end: 21 }, size16));
+ assert!(!a.contains_range(WrappingRange { start: 9, end: 20 }, size16));
+ assert!(!a.contains_range(WrappingRange { start: 4, end: 6 }, size16));
+ assert!(!a.contains_range(WrappingRange { start: 24, end: 26 }, size16));
+
+ assert!(!a.contains_range(WrappingRange { start: 16, end: 14 }, size16));
+
+ let b = WrappingRange { start: 20, end: 10 };
+ assert!(b.contains_range(b, size16));
+ assert!(b.contains_range(WrappingRange { start: 20, end: 20 }, size16));
+ assert!(b.contains_range(WrappingRange { start: 10, end: 10 }, size16));
+ assert!(b.contains_range(WrappingRange { start: 0, end: 10 }, size16));
+ assert!(b.contains_range(WrappingRange { start: 20, end: 30 }, size16));
+ assert!(b.contains_range(WrappingRange { start: 20, end: 9 }, size16));
+ assert!(b.contains_range(WrappingRange { start: 21, end: 10 }, size16));
+ assert!(b.contains_range(WrappingRange { start: 999, end: 9999 }, size16));
+ assert!(b.contains_range(WrappingRange { start: 999, end: 9 }, size16));
+ assert!(!b.contains_range(WrappingRange { start: 19, end: 19 }, size16));
+ assert!(!b.contains_range(WrappingRange { start: 11, end: 11 }, size16));
+ assert!(!b.contains_range(WrappingRange { start: 19, end: 11 }, size16));
+ assert!(!b.contains_range(WrappingRange { start: 11, end: 19 }, size16));
+
+ let f = WrappingRange { start: 0, end: u128::MAX };
+ assert!(f.contains_range(WrappingRange { start: 10, end: 20 }, size16));
+ assert!(f.contains_range(WrappingRange { start: 20, end: 10 }, size16));
+
+ let g = WrappingRange { start: 2, end: 1 };
+ assert!(g.contains_range(WrappingRange { start: 10, end: 20 }, size16));
+ assert!(g.contains_range(WrappingRange { start: 20, end: 10 }, size16));
+
+ let size1 = Size::from_bytes(1);
+ let u8r = WrappingRange { start: 0, end: 255 };
+ let i8r = WrappingRange { start: 128, end: 127 };
+ assert!(u8r.contains_range(i8r, size1));
+ assert!(i8r.contains_range(u8r, size1));
+ assert!(!u8r.contains_range(i8r, size16));
+ assert!(i8r.contains_range(u8r, size16));
+
+ let boolr = WrappingRange { start: 0, end: 1 };
+ assert!(u8r.contains_range(boolr, size1));
+ assert!(i8r.contains_range(boolr, size1));
+ assert!(!boolr.contains_range(u8r, size1));
+ assert!(!boolr.contains_range(i8r, size1));
+
+ let cmpr = WrappingRange { start: 255, end: 1 };
+ assert!(u8r.contains_range(cmpr, size1));
+ assert!(i8r.contains_range(cmpr, size1));
+ assert!(!cmpr.contains_range(u8r, size1));
+ assert!(!cmpr.contains_range(i8r, size1));
+
+ assert!(!boolr.contains_range(cmpr, size1));
+ assert!(cmpr.contains_range(boolr, size1));
+}
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 97e0709..984b280 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2849,7 +2849,7 @@ pub fn reg(&self) -> Option<&InlineAsmRegOrRegClass> {
}
}
-#[derive(Clone, Copy, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
+#[derive(Clone, Copy, Encodable, Decodable, Debug, HashStable_Generic, Walkable, PartialEq, Eq)]
pub enum AsmMacro {
/// The `asm!` macro
Asm,
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index c3222b7..2cc0769 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -95,7 +95,7 @@ fn impl_trait_in_bindings_ctxt(&self, position: ImplTraitPosition) -> ImplTraitC
fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> {
// Let statements are allowed to have impl trait in bindings.
- let super_ = l.super_;
+ let super_ = l.super_.map(|span| self.lower_span(span));
let ty = l.ty.as_ref().map(|t| {
self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
});
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 15e7362..657792c 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -282,9 +282,11 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
ExprKind::Field(el, ident) => {
hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident))
}
- ExprKind::Index(el, er, brackets_span) => {
- hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er), *brackets_span)
- }
+ ExprKind::Index(el, er, brackets_span) => hir::ExprKind::Index(
+ self.lower_expr(el),
+ self.lower_expr(er),
+ self.lower_span(*brackets_span),
+ ),
ExprKind::Range(e1, e2, lims) => {
self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims)
}
@@ -334,7 +336,9 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
ExprKind::Struct(se) => {
let rest = match &se.rest {
StructRest::Base(e) => hir::StructTailExpr::Base(self.lower_expr(e)),
- StructRest::Rest(sp) => hir::StructTailExpr::DefaultFields(*sp),
+ StructRest::Rest(sp) => {
+ hir::StructTailExpr::DefaultFields(self.lower_span(*sp))
+ }
StructRest::None => hir::StructTailExpr::None,
};
hir::ExprKind::Struct(
@@ -678,6 +682,14 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
hir::Arm { hir_id, pat, guard, body, span }
}
+ fn lower_capture_clause(&mut self, capture_clause: CaptureBy) -> CaptureBy {
+ match capture_clause {
+ CaptureBy::Ref => CaptureBy::Ref,
+ CaptureBy::Use { use_kw } => CaptureBy::Use { use_kw: self.lower_span(use_kw) },
+ CaptureBy::Value { move_kw } => CaptureBy::Value { move_kw: self.lower_span(move_kw) },
+ }
+ }
+
/// Lower/desugar a coroutine construct.
///
/// In particular, this creates the correct async resume argument and `_task_context`.
@@ -769,7 +781,7 @@ pub(super) fn make_desugared_coroutine_expr(
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
def_id: closure_def_id,
binder: hir::ClosureBinder::Default,
- capture_clause,
+ capture_clause: self.lower_capture_clause(capture_clause),
bound_generic_params: &[],
fn_decl,
body,
@@ -1035,7 +1047,7 @@ fn make_lowered_await(
}
fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
- hir::ExprKind::Use(self.lower_expr(expr), use_kw_span)
+ hir::ExprKind::Use(self.lower_expr(expr), self.lower_span(use_kw_span))
}
fn lower_expr_closure(
@@ -1083,7 +1095,7 @@ fn lower_expr_closure(
let c = self.arena.alloc(hir::Closure {
def_id: closure_def_id,
binder: binder_clause,
- capture_clause,
+ capture_clause: self.lower_capture_clause(capture_clause),
bound_generic_params,
fn_decl,
body: body_id,
@@ -1197,7 +1209,7 @@ fn lower_expr_coroutine_closure(
let c = self.arena.alloc(hir::Closure {
def_id: closure_def_id,
binder: binder_clause,
- capture_clause,
+ capture_clause: self.lower_capture_clause(capture_clause),
bound_generic_params,
fn_decl,
body,
@@ -2101,7 +2113,7 @@ fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> {
fn expr_uint(&mut self, sp: Span, ty: ast::UintTy, value: u128) -> hir::Expr<'hir> {
let lit = hir::Lit {
- span: sp,
+ span: self.lower_span(sp),
node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ty)),
};
self.expr(sp, hir::ExprKind::Lit(lit))
@@ -2120,7 +2132,10 @@ pub(super) fn expr_u16(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> {
}
pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> {
- let lit = hir::Lit { span: sp, node: ast::LitKind::Str(value, ast::StrStyle::Cooked) };
+ let lit = hir::Lit {
+ span: self.lower_span(sp),
+ node: ast::LitKind::Str(value, ast::StrStyle::Cooked),
+ };
self.expr(sp, hir::ExprKind::Lit(lit))
}
@@ -2206,7 +2221,7 @@ pub(super) fn expr_ident_mut(
self.arena.alloc(hir::Path {
span: self.lower_span(span),
res,
- segments: arena_vec![self; hir::PathSegment::new(ident, hir_id, res)],
+ segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
}),
));
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
index 5b1dcab..ec9d26e 100644
--- a/compiler/rustc_ast_lowering/src/format.rs
+++ b/compiler/rustc_ast_lowering/src/format.rs
@@ -402,6 +402,8 @@ fn expand_format_args<'hir>(
fmt: &FormatArgs,
allow_const: bool,
) -> hir::ExprKind<'hir> {
+ let macsp = ctx.lower_span(macsp);
+
let mut incomplete_lit = String::new();
let lit_pieces =
ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| {
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 1ef64f5..5b63206 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -164,11 +164,11 @@ fn visit_param(&mut self, param: &'hir Param<'hir>) {
fn visit_item(&mut self, i: &'hir Item<'hir>) {
debug_assert_eq!(i.owner_id, self.owner);
self.with_parent(i.hir_id(), |this| {
- if let ItemKind::Struct(_, _, struct_def) = &i.kind {
+ if let ItemKind::Struct(_, _, struct_def) = &i.kind
// If this is a tuple or unit-like struct, register the constructor.
- if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
- this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
- }
+ && let Some(ctor_hir_id) = struct_def.ctor_hir_id()
+ {
+ this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
}
intravisit::walk_item(this, i);
});
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index ddf01b6..1899dcd 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -627,6 +627,7 @@ fn lower_use_tree(
} else {
// For non-empty lists we can just drop all the data, the prefix is already
// present in HIR as a part of nested imports.
+ let span = self.lower_span(span);
self.arena.alloc(hir::UsePath { res: PerNS::default(), segments: &[], span })
};
hir::ItemKind::Use(path, hir::UseKind::ListStem)
@@ -1567,7 +1568,7 @@ pub(super) fn lower_fn_header(
attrs: &[hir::Attribute],
) -> hir::FnHeader {
let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind {
- hir::IsAsync::Async(span)
+ hir::IsAsync::Async(self.lower_span(span))
} else {
hir::IsAsync::NotAsync
};
@@ -1804,7 +1805,7 @@ pub(super) fn lower_generic_bound_predicate(
let res = Res::Def(DefKind::TyParam, def_id);
let ident = self.lower_ident(ident);
let ty_path = self.arena.alloc(hir::Path {
- span: param_span,
+ span: self.lower_span(param_span),
res,
segments: self
.arena
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 9aef189..189c82b6 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2368,7 +2368,17 @@ fn lower_trait_bound_modifiers(
&mut self,
modifiers: TraitBoundModifiers,
) -> hir::TraitBoundModifiers {
- hir::TraitBoundModifiers { constness: modifiers.constness, polarity: modifiers.polarity }
+ let constness = match modifiers.constness {
+ BoundConstness::Never => BoundConstness::Never,
+ BoundConstness::Always(span) => BoundConstness::Always(self.lower_span(span)),
+ BoundConstness::Maybe(span) => BoundConstness::Maybe(self.lower_span(span)),
+ };
+ let polarity = match modifiers.polarity {
+ BoundPolarity::Positive => BoundPolarity::Positive,
+ BoundPolarity::Negative(span) => BoundPolarity::Negative(self.lower_span(span)),
+ BoundPolarity::Maybe(span) => BoundPolarity::Maybe(self.lower_span(span)),
+ };
+ hir::TraitBoundModifiers { constness, polarity }
}
// Helper methods for building HIR.
@@ -2414,6 +2424,7 @@ fn stmt_super_let_pat(
init: Option<&'hir hir::Expr<'hir>>,
) -> hir::Stmt<'hir> {
let hir_id = self.next_id();
+ let span = self.lower_span(span);
let local = hir::LetStmt {
super_: Some(span),
hir_id,
@@ -2421,7 +2432,7 @@ fn stmt_super_let_pat(
pat,
els: None,
source: hir::LocalSource::Normal,
- span: self.lower_span(span),
+ span,
ty: None,
};
self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local)))
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index a08dae1..895a457 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -640,16 +640,16 @@ fn check_c_variadic_type(&self, fk: FnKind<'a>) {
return;
}
- if let Some(header) = fk.header() {
- if let Const::Yes(const_span) = header.constness {
- let mut spans = variadic_spans.clone();
- spans.push(const_span);
- self.dcx().emit_err(errors::ConstAndCVariadic {
- spans,
- const_span,
- variadic_spans: variadic_spans.clone(),
- });
- }
+ if let Some(header) = fk.header()
+ && let Const::Yes(const_span) = header.constness
+ {
+ let mut spans = variadic_spans.clone();
+ spans.push(const_span);
+ self.dcx().emit_err(errors::ConstAndCVariadic {
+ spans,
+ const_span,
+ variadic_spans: variadic_spans.clone(),
+ });
}
match (fk.ctxt(), fk.header()) {
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 8114733..662357c 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -630,16 +630,11 @@ fn check_incompatible_features(sess: &Session, features: &Features) {
.iter()
.filter(|(f1, f2)| features.enabled(*f1) && features.enabled(*f2))
{
- if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1) {
- if let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2)
- {
- let spans = vec![f1_span, f2_span];
- sess.dcx().emit_err(errors::IncompatibleFeatures {
- spans,
- f1: f1_name,
- f2: f2_name,
- });
- }
+ if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1)
+ && let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2)
+ {
+ let spans = vec![f1_span, f2_span];
+ sess.dcx().emit_err(errors::IncompatibleFeatures { spans, f1: f1_name, f2: f2_name });
}
}
}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index def0cb74..f0cf0c1 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -572,10 +572,10 @@ fn next_comment(&mut self) -> Option<Comment> {
}
fn maybe_print_trailing_comment(&mut self, span: rustc_span::Span, next_pos: Option<BytePos>) {
- if let Some(cmnts) = self.comments_mut() {
- if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
- self.print_comment(cmnt);
- }
+ if let Some(cmnts) = self.comments_mut()
+ && let Some(cmnt) = cmnts.trailing_comment(span, next_pos)
+ {
+ self.print_comment(cmnt);
}
}
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 1e2576b..55019cd 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -110,18 +110,10 @@ pub enum DeprecatedSince {
Err,
}
-#[derive(
- Copy,
- Debug,
- Eq,
- PartialEq,
- Encodable,
- Decodable,
- Clone,
- HashStable_Generic,
- PrintAttribute
-)]
-pub enum CoverageStatus {
+/// Successfully-parsed value of a `#[coverage(..)]` attribute.
+#[derive(Copy, Debug, Eq, PartialEq, Encodable, Decodable, Clone)]
+#[derive(HashStable_Generic, PrintAttribute)]
+pub enum CoverageAttrKind {
On,
Off,
}
@@ -304,8 +296,8 @@ pub enum AttributeKind {
/// Represents `#[const_trait]`.
ConstTrait(Span),
- /// Represents `#[coverage]`.
- Coverage(Span, CoverageStatus),
+ /// Represents `#[coverage(..)]`.
+ Coverage(Span, CoverageAttrKind),
///Represents `#[rustc_deny_explicit_impl]`.
DenyExplicitImpl(Span),
@@ -416,12 +408,24 @@ pub enum AttributeKind {
/// Represents `#[pointee]`
Pointee(Span),
+ /// Represents `#[proc_macro]`
+ ProcMacro(Span),
+
+ /// Represents `#[proc_macro_attribute]`
+ ProcMacroAttribute(Span),
+
+ /// Represents `#[proc_macro_derive]`
+ ProcMacroDerive { trait_name: Symbol, helper_attrs: ThinVec<Symbol>, span: Span },
+
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
PubTransparent(Span),
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span },
+ /// Represents `#[rustc_builtin_macro]`.
+ RustcBuiltinMacro { builtin_name: Option<Symbol>, helper_attrs: ThinVec<Symbol>, span: Span },
+
/// Represents `#[rustc_layout_scalar_valid_range_end]`.
RustcLayoutScalarValidRangeEnd(Box<u128>, Span),
diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
index 159b807..af2d46d 100644
--- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
+++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
@@ -61,8 +61,12 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
PassByValue(..) => Yes,
Path(..) => No,
Pointee(..) => No,
+ ProcMacro(..) => No,
+ ProcMacroAttribute(..) => No,
+ ProcMacroDerive { .. } => No,
PubTransparent(..) => Yes,
Repr { .. } => No,
+ RustcBuiltinMacro { .. } => Yes,
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
RustcObjectLifetimeDefault => No,
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index bb28121..afa9abe 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -1,4 +1,4 @@
-use rustc_attr_data_structures::{AttributeKind, CoverageStatus, OptimizeAttr, UsedBy};
+use rustc_attr_data_structures::{AttributeKind, CoverageAttrKind, OptimizeAttr, UsedBy};
use rustc_feature::{AttributeTemplate, template};
use rustc_session::parse::feature_err;
use rustc_span::{Span, Symbol, sym};
@@ -78,16 +78,16 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<At
return None;
};
- let status = match arg.path().word_sym() {
- Some(sym::off) => CoverageStatus::Off,
- Some(sym::on) => CoverageStatus::On,
+ let kind = match arg.path().word_sym() {
+ Some(sym::off) => CoverageAttrKind::Off,
+ Some(sym::on) => CoverageAttrKind::On,
None | Some(_) => {
fail_incorrect_argument(arg.span());
return None;
}
};
- Some(AttributeKind::Coverage(cx.attr_span, status))
+ Some(AttributeKind::Coverage(cx.attr_span, kind))
}
}
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 15b90bd..0c10517 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -41,6 +41,7 @@
pub(crate) mod no_implicit_prelude;
pub(crate) mod non_exhaustive;
pub(crate) mod path;
+pub(crate) mod proc_macro_attrs;
pub(crate) mod repr;
pub(crate) mod rustc_internal;
pub(crate) mod semantics;
diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
new file mode 100644
index 0000000..4de77dc
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
@@ -0,0 +1,139 @@
+use rustc_attr_data_structures::AttributeKind;
+use rustc_feature::{AttributeTemplate, template};
+use rustc_span::{Span, Symbol, sym};
+use thin_vec::ThinVec;
+
+use crate::attributes::{
+ AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
+};
+use crate::context::{AcceptContext, Stage};
+use crate::parser::ArgParser;
+
+pub(crate) struct ProcMacroParser;
+impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser {
+ const PATH: &[Symbol] = &[sym::proc_macro];
+ const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+ const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacro;
+}
+
+pub(crate) struct ProcMacroAttributeParser;
+impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroAttributeParser {
+ const PATH: &[Symbol] = &[sym::proc_macro_attribute];
+ const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+ const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacroAttribute;
+}
+
+pub(crate) struct ProcMacroDeriveParser;
+impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser {
+ const PATH: &[Symbol] = &[sym::proc_macro_derive];
+ const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+ const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+ const TEMPLATE: AttributeTemplate =
+ template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
+
+ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+ let (trait_name, helper_attrs) = parse_derive_like(cx, args, true)?;
+ Some(AttributeKind::ProcMacroDerive {
+ trait_name: trait_name.expect("Trait name is mandatory, so it is present"),
+ helper_attrs,
+ span: cx.attr_span,
+ })
+ }
+}
+
+pub(crate) struct RustcBuiltinMacroParser;
+impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser {
+ const PATH: &[Symbol] = &[sym::rustc_builtin_macro];
+ const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+ const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+ const TEMPLATE: AttributeTemplate =
+ template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
+
+ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+ let (builtin_name, helper_attrs) = parse_derive_like(cx, args, false)?;
+ Some(AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, span: cx.attr_span })
+ }
+}
+
+fn parse_derive_like<S: Stage>(
+ cx: &mut AcceptContext<'_, '_, S>,
+ args: &ArgParser<'_>,
+ trait_name_mandatory: bool,
+) -> Option<(Option<Symbol>, ThinVec<Symbol>)> {
+ let Some(list) = args.list() else {
+ // For #[rustc_builtin_macro], it is permitted to leave out the trait name
+ if args.no_args().is_ok() && !trait_name_mandatory {
+ return Some((None, ThinVec::new()));
+ }
+ cx.expected_list(cx.attr_span);
+ return None;
+ };
+ let mut items = list.mixed();
+
+ // Parse the name of the trait that is derived.
+ let Some(trait_attr) = items.next() else {
+ cx.expected_at_least_one_argument(list.span);
+ return None;
+ };
+ let Some(trait_attr) = trait_attr.meta_item() else {
+ cx.unexpected_literal(trait_attr.span());
+ return None;
+ };
+ let Some(trait_ident) = trait_attr.path().word() else {
+ cx.expected_identifier(trait_attr.path().span());
+ return None;
+ };
+ if !trait_ident.name.can_be_raw() {
+ cx.expected_identifier(trait_ident.span);
+ return None;
+ }
+ if let Err(e) = trait_attr.args().no_args() {
+ cx.expected_no_args(e);
+ return None;
+ };
+
+ // Parse optional attributes
+ let mut attributes = ThinVec::new();
+ if let Some(attrs) = items.next() {
+ let Some(attr_list) = attrs.meta_item() else {
+ cx.expected_list(attrs.span());
+ return None;
+ };
+ if !attr_list.path().word_is(sym::attributes) {
+ cx.expected_specific_argument(attrs.span(), vec!["attributes"]);
+ return None;
+ }
+ let Some(attr_list) = attr_list.args().list() else {
+ cx.expected_list(attrs.span());
+ return None;
+ };
+
+ // Parse item in `attributes(...)` argument
+ for attr in attr_list.mixed() {
+ let Some(attr) = attr.meta_item() else {
+ cx.expected_identifier(attr.span());
+ return None;
+ };
+ if let Err(e) = attr.args().no_args() {
+ cx.expected_no_args(e);
+ return None;
+ };
+ let Some(ident) = attr.path().word() else {
+ cx.expected_identifier(attr.path().span());
+ return None;
+ };
+ if !ident.name.can_be_raw() {
+ cx.expected_identifier(ident.span);
+ return None;
+ }
+ attributes.push(ident.name);
+ }
+ }
+
+ // If anything else is specified, we should reject it
+ if let Some(next) = items.next() {
+ cx.expected_no_args(next.span());
+ }
+
+ Some((Some(trait_ident.name), attributes))
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 5933774..c54fc6b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -74,8 +74,15 @@ impl<S: Stage> AttributeParser<S> for StabilityParser {
template!(NameValueStr: "deprecation message"),
|this, cx, args| {
reject_outside_std!(cx);
- this.allowed_through_unstable_modules =
- args.name_value().and_then(|i| i.value_as_str())
+ let Some(nv) = args.name_value() else {
+ cx.expected_name_value(cx.attr_span, None);
+ return;
+ };
+ let Some(value_str) = nv.value_as_str() else {
+ cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
+ return;
+ };
+ this.allowed_through_unstable_modules = Some(value_str);
},
),
];
@@ -247,7 +254,12 @@ pub(crate) fn parse_stability<S: Stage>(
let mut feature = None;
let mut since = None;
- for param in args.list()?.mixed() {
+ let ArgParser::List(list) = args else {
+ cx.expected_list(cx.attr_span);
+ return None;
+ };
+
+ for param in list.mixed() {
let param_span = param.span();
let Some(param) = param.meta_item() else {
cx.emit_err(session_diagnostics::UnsupportedLiteral {
@@ -322,7 +334,13 @@ pub(crate) fn parse_unstability<S: Stage>(
let mut is_soft = false;
let mut implied_by = None;
let mut old_name = None;
- for param in args.list()?.mixed() {
+
+ let ArgParser::List(list) = args else {
+ cx.expected_list(cx.attr_span);
+ return None;
+ };
+
+ for param in list.mixed() {
let Some(param) = param.meta_item() else {
cx.emit_err(session_diagnostics::UnsupportedLiteral {
span: param.span(),
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 45bfe34..9b86d10 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -38,6 +38,9 @@
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
use crate::attributes::non_exhaustive::NonExhaustiveParser;
use crate::attributes::path::PathParser as PathAttributeParser;
+use crate::attributes::proc_macro_attrs::{
+ ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
+};
use crate::attributes::repr::{AlignParser, ReprParser};
use crate::attributes::rustc_internal::{
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
@@ -154,6 +157,8 @@ mod late {
Single<MustUseParser>,
Single<OptimizeParser>,
Single<PathAttributeParser>,
+ Single<ProcMacroDeriveParser>,
+ Single<RustcBuiltinMacroParser>,
Single<RustcForceInlineParser>,
Single<RustcLayoutScalarValidRangeEnd>,
Single<RustcLayoutScalarValidRangeStart>,
@@ -186,6 +191,8 @@ mod late {
Single<WithoutArgs<ParenSugarParser>>,
Single<WithoutArgs<PassByValueParser>>,
Single<WithoutArgs<PointeeParser>>,
+ Single<WithoutArgs<ProcMacroAttributeParser>>,
+ Single<WithoutArgs<ProcMacroParser>>,
Single<WithoutArgs<PubTransparentParser>>,
Single<WithoutArgs<SpecializationTraitParser>>,
Single<WithoutArgs<StdInternalSymbolParser>>,
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 040a060..be8b3f0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1290,6 +1290,58 @@ pub(crate) fn suggest_cloning(
span,
format!("if `{ty}` implemented `Clone`, you could clone the value"),
);
+ } else if let ty::Adt(_, _) = ty.kind()
+ && let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()
+ {
+ // For cases like `Option<NonClone>`, where `Option<T>: Clone` if `T: Clone`, we point
+ // at the types that should be `Clone`.
+ let ocx = ObligationCtxt::new_with_diagnostics(self.infcx);
+ let cause = ObligationCause::misc(expr.span, self.mir_def_id());
+ ocx.register_bound(cause, self.infcx.param_env, ty, clone_trait);
+ let errors = ocx.select_all_or_error();
+ if errors.iter().all(|error| {
+ match error.obligation.predicate.as_clause().and_then(|c| c.as_trait_clause()) {
+ Some(clause) => match clause.self_ty().skip_binder().kind() {
+ ty::Adt(def, _) => def.did().is_local() && clause.def_id() == clone_trait,
+ _ => false,
+ },
+ None => false,
+ }
+ }) {
+ let mut type_spans = vec![];
+ let mut types = FxIndexSet::default();
+ for clause in errors
+ .iter()
+ .filter_map(|e| e.obligation.predicate.as_clause())
+ .filter_map(|c| c.as_trait_clause())
+ {
+ let ty::Adt(def, _) = clause.self_ty().skip_binder().kind() else { continue };
+ type_spans.push(self.infcx.tcx.def_span(def.did()));
+ types.insert(
+ self.infcx
+ .tcx
+ .short_string(clause.self_ty().skip_binder(), &mut err.long_ty_path()),
+ );
+ }
+ let mut span: MultiSpan = type_spans.clone().into();
+ for sp in type_spans {
+ span.push_span_label(sp, "consider implementing `Clone` for this type");
+ }
+ span.push_span_label(expr.span, "you could clone this value");
+ let types: Vec<_> = types.into_iter().collect();
+ let msg = match &types[..] {
+ [only] => format!("`{only}`"),
+ [head @ .., last] => format!(
+ "{} and `{last}`",
+ head.iter().map(|t| format!("`{t}`")).collect::<Vec<_>>().join(", ")
+ ),
+ [] => unreachable!(),
+ };
+ err.span_note(
+ span,
+ format!("if {msg} implemented `Clone`, you could clone the value"),
+ );
+ }
}
}
@@ -2332,7 +2384,7 @@ fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
if let Some(body_expr) = finder.body_expr
&& let Some(loop_span) = finder.loop_span
&& let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id)
- && let Some(trait_did) = tcx.trait_of_item(def_id)
+ && let Some(trait_did) = tcx.trait_of_assoc(def_id)
&& tcx.is_diagnostic_item(sym::Iterator, trait_did)
{
if let Some(loop_bind) = finder.loop_bind {
@@ -2481,13 +2533,13 @@ fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
// Check that the parent of the closure is a method call,
// with receiver matching with local's type (modulo refs)
- if let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_expr.hir_id) {
- if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind {
- let recv_ty = typeck_results.expr_ty(recv);
+ if let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_expr.hir_id)
+ && let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind
+ {
+ let recv_ty = typeck_results.expr_ty(recv);
- if recv_ty.peel_refs() != local_ty {
- return;
- }
+ if recv_ty.peel_refs() != local_ty {
+ return;
}
}
@@ -2753,16 +2805,16 @@ fn describe_place_for_conflicting_borrow(
// With the place of a union and a field access into it, we traverse the second
// borrowed place and look for an access to a different field of the same union.
for (place_base, elem) in second_borrowed_place.iter_projections().rev() {
- if let ProjectionElem::Field(field, _) = elem {
- if let Some(union_ty) = union_ty(place_base) {
- if field != target_field && place_base == target_base {
- return Some((
- self.describe_any_place(place_base),
- self.describe_any_place(first_borrowed_place.as_ref()),
- self.describe_any_place(second_borrowed_place.as_ref()),
- union_ty.to_string(),
- ));
- }
+ if let ProjectionElem::Field(field, _) = elem
+ && let Some(union_ty) = union_ty(place_base)
+ {
+ if field != target_field && place_base == target_base {
+ return Some((
+ self.describe_any_place(place_base),
+ self.describe_any_place(first_borrowed_place.as_ref()),
+ self.describe_any_place(second_borrowed_place.as_ref()),
+ union_ty.to_string(),
+ ));
}
}
}
@@ -2949,16 +3001,15 @@ fn report_local_value_does_not_live_long_enough(
from_closure: false,
..
} = explanation
- {
- if let Err(diag) = self.try_report_cannot_return_reference_to_local(
+ && let Err(diag) = self.try_report_cannot_return_reference_to_local(
borrow,
borrow_span,
span,
category,
opt_place_desc.as_ref(),
- ) {
- return diag;
- }
+ )
+ {
+ return diag;
}
let name = format!("`{name}`");
@@ -3720,30 +3771,30 @@ pub(crate) fn report_illegal_mutation_of_borrowed(
let loan_span = loan_spans.args_or_use();
let descr_place = self.describe_any_place(place.as_ref());
- if let BorrowKind::Fake(_) = loan.kind {
- if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
- let mut err = self.cannot_mutate_in_immutable_section(
- span,
- loan_span,
- &descr_place,
- section,
- "assign",
- );
+ if let BorrowKind::Fake(_) = loan.kind
+ && let Some(section) = self.classify_immutable_section(loan.assigned_place)
+ {
+ let mut err = self.cannot_mutate_in_immutable_section(
+ span,
+ loan_span,
+ &descr_place,
+ section,
+ "assign",
+ );
- loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| {
- use crate::session_diagnostics::CaptureVarCause::*;
- match kind {
- hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
- hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
- BorrowUseInClosure { var_span }
- }
+ loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| {
+ use crate::session_diagnostics::CaptureVarCause::*;
+ match kind {
+ hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
+ hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
+ BorrowUseInClosure { var_span }
}
- });
+ }
+ });
- self.buffer_error(err);
+ self.buffer_error(err);
- return;
- }
+ return;
}
let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
@@ -3996,119 +4047,116 @@ fn annotate_argument_and_return_for_borrow(
"annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
target, stmt
);
- if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
- if let Some(assigned_to) = place.as_local() {
- debug!(
- "annotate_argument_and_return_for_borrow: assigned_to={:?} \
+ if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind
+ && let Some(assigned_to) = place.as_local()
+ {
+ debug!(
+ "annotate_argument_and_return_for_borrow: assigned_to={:?} \
rvalue={:?}",
- assigned_to, rvalue
- );
- // Check if our `target` was captured by a closure.
- if let Rvalue::Aggregate(
- box AggregateKind::Closure(def_id, args),
- operands,
- ) = rvalue
- {
- let def_id = def_id.expect_local();
- for operand in operands {
- let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) =
- operand
- else {
- continue;
- };
- debug!(
- "annotate_argument_and_return_for_borrow: assigned_from={:?}",
- assigned_from
- );
+ assigned_to, rvalue
+ );
+ // Check if our `target` was captured by a closure.
+ if let Rvalue::Aggregate(box AggregateKind::Closure(def_id, args), operands) =
+ rvalue
+ {
+ let def_id = def_id.expect_local();
+ for operand in operands {
+ let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) =
+ operand
+ else {
+ continue;
+ };
+ debug!(
+ "annotate_argument_and_return_for_borrow: assigned_from={:?}",
+ assigned_from
+ );
- // Find the local from the operand.
- let Some(assigned_from_local) =
- assigned_from.local_or_deref_local()
- else {
- continue;
- };
+ // Find the local from the operand.
+ let Some(assigned_from_local) = assigned_from.local_or_deref_local()
+ else {
+ continue;
+ };
- if assigned_from_local != target {
- continue;
- }
-
- // If a closure captured our `target` and then assigned
- // into a place then we should annotate the closure in
- // case it ends up being assigned into the return place.
- annotated_closure =
- self.annotate_fn_sig(def_id, args.as_closure().sig());
- debug!(
- "annotate_argument_and_return_for_borrow: \
- annotated_closure={:?} assigned_from_local={:?} \
- assigned_to={:?}",
- annotated_closure, assigned_from_local, assigned_to
- );
-
- if assigned_to == mir::RETURN_PLACE {
- // If it was assigned directly into the return place, then
- // return now.
- return annotated_closure;
- } else {
- // Otherwise, update the target.
- target = assigned_to;
- }
+ if assigned_from_local != target {
+ continue;
}
- // If none of our closure's operands matched, then skip to the next
- // statement.
- continue;
+ // If a closure captured our `target` and then assigned
+ // into a place then we should annotate the closure in
+ // case it ends up being assigned into the return place.
+ annotated_closure =
+ self.annotate_fn_sig(def_id, args.as_closure().sig());
+ debug!(
+ "annotate_argument_and_return_for_borrow: \
+ annotated_closure={:?} assigned_from_local={:?} \
+ assigned_to={:?}",
+ annotated_closure, assigned_from_local, assigned_to
+ );
+
+ if assigned_to == mir::RETURN_PLACE {
+ // If it was assigned directly into the return place, then
+ // return now.
+ return annotated_closure;
+ } else {
+ // Otherwise, update the target.
+ target = assigned_to;
+ }
}
- // Otherwise, look at other types of assignment.
- let assigned_from = match rvalue {
- Rvalue::Ref(_, _, assigned_from) => assigned_from,
- Rvalue::Use(operand) => match operand {
- Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
- assigned_from
- }
- _ => continue,
- },
- _ => continue,
- };
- debug!(
- "annotate_argument_and_return_for_borrow: \
- assigned_from={:?}",
- assigned_from,
- );
-
- // Find the local from the rvalue.
- let Some(assigned_from_local) = assigned_from.local_or_deref_local() else {
- continue;
- };
- debug!(
- "annotate_argument_and_return_for_borrow: \
- assigned_from_local={:?}",
- assigned_from_local,
- );
-
- // Check if our local matches the target - if so, we've assigned our
- // borrow to a new place.
- if assigned_from_local != target {
- continue;
- }
-
- // If we assigned our `target` into a new place, then we should
- // check if it was the return place.
- debug!(
- "annotate_argument_and_return_for_borrow: \
- assigned_from_local={:?} assigned_to={:?}",
- assigned_from_local, assigned_to
- );
- if assigned_to == mir::RETURN_PLACE {
- // If it was then return the annotated closure if there was one,
- // else, annotate this function.
- return annotated_closure.or_else(fallback);
- }
-
- // If we didn't assign into the return place, then we just update
- // the target.
- target = assigned_to;
+ // If none of our closure's operands matched, then skip to the next
+ // statement.
+ continue;
}
+
+ // Otherwise, look at other types of assignment.
+ let assigned_from = match rvalue {
+ Rvalue::Ref(_, _, assigned_from) => assigned_from,
+ Rvalue::Use(operand) => match operand {
+ Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
+ assigned_from
+ }
+ _ => continue,
+ },
+ _ => continue,
+ };
+ debug!(
+ "annotate_argument_and_return_for_borrow: \
+ assigned_from={:?}",
+ assigned_from,
+ );
+
+ // Find the local from the rvalue.
+ let Some(assigned_from_local) = assigned_from.local_or_deref_local() else {
+ continue;
+ };
+ debug!(
+ "annotate_argument_and_return_for_borrow: \
+ assigned_from_local={:?}",
+ assigned_from_local,
+ );
+
+ // Check if our local matches the target - if so, we've assigned our
+ // borrow to a new place.
+ if assigned_from_local != target {
+ continue;
+ }
+
+ // If we assigned our `target` into a new place, then we should
+ // check if it was the return place.
+ debug!(
+ "annotate_argument_and_return_for_borrow: \
+ assigned_from_local={:?} assigned_to={:?}",
+ assigned_from_local, assigned_to
+ );
+ if assigned_to == mir::RETURN_PLACE {
+ // If it was then return the annotated closure if there was one,
+ // else, annotate this function.
+ return annotated_closure.or_else(fallback);
+ }
+
+ // If we didn't assign into the return place, then we just update
+ // the target.
+ target = assigned_to;
}
}
@@ -4120,32 +4168,31 @@ fn annotate_argument_and_return_for_borrow(
);
if let TerminatorKind::Call { destination, target: Some(_), args, .. } =
&terminator.kind
+ && let Some(assigned_to) = destination.as_local()
{
- if let Some(assigned_to) = destination.as_local() {
+ debug!(
+ "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
+ assigned_to, args
+ );
+ for operand in args {
+ let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) =
+ &operand.node
+ else {
+ continue;
+ };
debug!(
- "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
- assigned_to, args
+ "annotate_argument_and_return_for_borrow: assigned_from={:?}",
+ assigned_from,
);
- for operand in args {
- let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) =
- &operand.node
- else {
- continue;
- };
+
+ if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
debug!(
- "annotate_argument_and_return_for_borrow: assigned_from={:?}",
- assigned_from,
+ "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
+ assigned_from_local,
);
- if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
- debug!(
- "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
- assigned_from_local,
- );
-
- if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
- return annotated_closure.or_else(fallback);
- }
+ if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
+ return annotated_closure.or_else(fallback);
}
}
}
@@ -4244,10 +4291,10 @@ fn annotate_fn_sig(
// as the HIR doesn't have full types for closure arguments.
let return_ty = sig.output().skip_binder();
let mut return_span = fn_decl.output.span();
- if let hir::FnRetTy::Return(ty) = &fn_decl.output {
- if let hir::TyKind::Ref(lifetime, _) = ty.kind {
- return_span = lifetime.ident.span;
- }
+ if let hir::FnRetTy::Return(ty) = &fn_decl.output
+ && let hir::TyKind::Ref(lifetime, _) = ty.kind
+ {
+ return_span = lifetime.ident.span;
}
Some(AnnotatedBorrowFnSignature::NamedFunction {
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index f9e5223..fdca6b5 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -341,7 +341,7 @@ fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
}
}
} else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
- let sp = info.span.find_oldest_ancestor_in_same_ctxt();
+ let sp = info.span.find_ancestor_not_from_macro().unwrap_or(info.span);
if info.tail_result_is_ignored {
// #85581: If the first mutable borrow's scope contains
// the second borrow, this suggestion isn't helpful.
@@ -917,30 +917,29 @@ fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool {
if let TerminatorKind::Call { destination, target: Some(block), args, .. } =
&terminator.kind
+ && let Some(dest) = destination.as_local()
{
- if let Some(dest) = destination.as_local() {
- debug!(
- "was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
- target, dest, args
- );
- // Check if one of the arguments to this function is the target place.
- let found_target = args.iter().any(|arg| {
- if let Operand::Move(place) = arg.node {
- if let Some(potential) = place.as_local() {
- potential == target
- } else {
- false
- }
+ debug!(
+ "was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
+ target, dest, args
+ );
+ // Check if one of the arguments to this function is the target place.
+ let found_target = args.iter().any(|arg| {
+ if let Operand::Move(place) = arg.node {
+ if let Some(potential) = place.as_local() {
+ potential == target
} else {
false
}
- });
-
- // If it is, follow this to the next block and update the target.
- if found_target {
- target = dest;
- queue.push(block.start_location());
+ } else {
+ false
}
+ });
+
+ // If it is, follow this to the next block and update the target.
+ if found_target {
+ target = dest;
+ queue.push(block.start_location());
}
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 9ad91d6..56fdaf1 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -266,48 +266,44 @@ pub(super) fn add_moved_or_invoked_closure_note(
args,
..
} = &terminator.kind
+ && let ty::FnDef(id, _) = *const_.ty().kind()
{
- if let ty::FnDef(id, _) = *const_.ty().kind() {
- debug!("add_moved_or_invoked_closure_note: id={:?}", id);
- if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) {
- let closure = match args.first() {
- Some(Spanned {
- node: Operand::Copy(place) | Operand::Move(place), ..
- }) if target == place.local_or_deref_local() => {
- place.local_or_deref_local().unwrap()
- }
- _ => return false,
- };
+ debug!("add_moved_or_invoked_closure_note: id={:?}", id);
+ if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) {
+ let closure = match args.first() {
+ Some(Spanned { node: Operand::Copy(place) | Operand::Move(place), .. })
+ if target == place.local_or_deref_local() =>
+ {
+ place.local_or_deref_local().unwrap()
+ }
+ _ => return false,
+ };
- debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
- if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
- let did = did.expect_local();
- if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
- diag.subdiagnostic(OnClosureNote::InvokedTwice {
- place_name: &ty::place_to_string_for_capture(
- self.infcx.tcx,
- hir_place,
- ),
- span: *span,
- });
- return true;
- }
+ debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
+ if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
+ let did = did.expect_local();
+ if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
+ diag.subdiagnostic(OnClosureNote::InvokedTwice {
+ place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
+ span: *span,
+ });
+ return true;
}
}
}
}
// Check if we are just moving a closure after it has been invoked.
- if let Some(target) = target {
- if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
- let did = did.expect_local();
- if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
- diag.subdiagnostic(OnClosureNote::MovedTwice {
- place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
- span: *span,
- });
- return true;
- }
+ if let Some(target) = target
+ && let ty::Closure(did, _) = self.body.local_decls[target].ty.kind()
+ {
+ let did = did.expect_local();
+ if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
+ diag.subdiagnostic(OnClosureNote::MovedTwice {
+ place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
+ span: *span,
+ });
+ return true;
}
}
false
@@ -942,7 +938,7 @@ pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String {
fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
match *func.kind() {
ty::FnDef(def_id, args) => {
- let trait_id = tcx.trait_of_item(def_id)?;
+ let trait_id = tcx.trait_of_assoc(def_id)?;
if tcx.is_lang_item(trait_id, LangItem::Deref)
|| tcx.is_lang_item(trait_id, LangItem::DerefMut)
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 447bf7d..1067f1e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -115,10 +115,8 @@ fn group_move_errors(&mut self) -> Vec<GroupedMoveError<'tcx>> {
fn append_to_grouped_errors(
&self,
grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
- error: MoveError<'tcx>,
+ MoveError { place: original_path, location, kind }: MoveError<'tcx>,
) {
- let MoveError { place: original_path, location, kind } = error;
-
// Note: that the only time we assign a place isn't a temporary
// to a user variable is when initializing it.
// If that ever stops being the case, then the ever initialized
@@ -128,36 +126,35 @@ fn append_to_grouped_errors(
.statements
.get(location.statement_index)
.map(|stmt| &stmt.kind)
+ && let Some(local) = place.as_local()
{
- if let Some(local) = place.as_local() {
- let local_decl = &self.body.local_decls[local];
- // opt_match_place is the
- // match_span is the span of the expression being matched on
- // match *x.y { ... } match_place is Some(*x.y)
- // ^^^^ match_span is the span of *x.y
- //
- // opt_match_place is None for let [mut] x = ... statements,
- // whether or not the right-hand side is a place expression
- if let LocalInfo::User(BindingForm::Var(VarBindingForm {
- opt_match_place: Some((opt_match_place, match_span)),
- binding_mode: _,
- opt_ty_info: _,
- pat_span: _,
- })) = *local_decl.local_info()
- {
- let stmt_source_info = self.body.source_info(location);
- self.append_binding_error(
- grouped_errors,
- kind,
- original_path,
- *move_from,
- local,
- opt_match_place,
- match_span,
- stmt_source_info.span,
- );
- return;
- }
+ let local_decl = &self.body.local_decls[local];
+ // opt_match_place is the
+ // match_span is the span of the expression being matched on
+ // match *x.y { ... } match_place is Some(*x.y)
+ // ^^^^ match_span is the span of *x.y
+ //
+ // opt_match_place is None for let [mut] x = ... statements,
+ // whether or not the right-hand side is a place expression
+ if let LocalInfo::User(BindingForm::Var(VarBindingForm {
+ opt_match_place: Some((opt_match_place, match_span)),
+ binding_mode: _,
+ opt_ty_info: _,
+ pat_span: _,
+ })) = *local_decl.local_info()
+ {
+ let stmt_source_info = self.body.source_info(location);
+ self.append_binding_error(
+ grouped_errors,
+ kind,
+ original_path,
+ *move_from,
+ local,
+ opt_match_place,
+ match_span,
+ stmt_source_info.span,
+ );
+ return;
}
}
@@ -251,54 +248,47 @@ fn append_binding_error(
}
fn report(&mut self, error: GroupedMoveError<'tcx>) {
- let (mut err, err_span) = {
- let (span, use_spans, original_path, kind) = match error {
- GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. }
- | GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => {
- (span, None, original_path, kind)
- }
- GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => {
- (use_spans.args_or_use(), Some(use_spans), original_path, kind)
- }
- };
- debug!(
- "report: original_path={:?} span={:?}, kind={:?} \
- original_path.is_upvar_field_projection={:?}",
- original_path,
- span,
- kind,
- self.is_upvar_field_projection(original_path.as_ref())
- );
- if self.has_ambiguous_copy(original_path.ty(self.body, self.infcx.tcx).ty) {
- // If the type may implement Copy, skip the error.
- // It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check
- self.dcx().span_delayed_bug(
- span,
- "Type may implement copy, but there is no other error.",
- );
- return;
+ let (span, use_spans, original_path, kind) = match error {
+ GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. }
+ | GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => {
+ (span, None, original_path, kind)
}
- (
- match kind {
- &IllegalMoveOriginKind::BorrowedContent { target_place } => self
- .report_cannot_move_from_borrowed_content(
- original_path,
- target_place,
- span,
- use_spans,
- ),
- &IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
- self.cannot_move_out_of_interior_of_drop(span, ty)
- }
- &IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
- self.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index))
- }
- },
- span,
- )
+ GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => {
+ (use_spans.args_or_use(), Some(use_spans), original_path, kind)
+ }
+ };
+ debug!(
+ "report: original_path={:?} span={:?}, kind={:?} \
+ original_path.is_upvar_field_projection={:?}",
+ original_path,
+ span,
+ kind,
+ self.is_upvar_field_projection(original_path.as_ref())
+ );
+ if self.has_ambiguous_copy(original_path.ty(self.body, self.infcx.tcx).ty) {
+ // If the type may implement Copy, skip the error.
+ // It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check
+ self.dcx()
+ .span_delayed_bug(span, "Type may implement copy, but there is no other error.");
+ return;
+ }
+ let mut err = match kind {
+ &IllegalMoveOriginKind::BorrowedContent { target_place } => self
+ .report_cannot_move_from_borrowed_content(
+ original_path,
+ target_place,
+ span,
+ use_spans,
+ ),
+ &IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
+ self.cannot_move_out_of_interior_of_drop(span, ty)
+ }
+ &IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
+ self.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index))
+ }
};
- self.add_move_hints(error, &mut err, err_span);
+ self.add_move_hints(error, &mut err, span);
self.buffer_error(err);
}
@@ -483,7 +473,8 @@ fn report_cannot_move_from_borrowed_content(
self.cannot_move_out_of_interior_noncopy(span, ty, None)
}
ty::Closure(def_id, closure_args)
- if def_id.as_local() == Some(self.mir_def_id()) && upvar_field.is_some() =>
+ if def_id.as_local() == Some(self.mir_def_id())
+ && let Some(upvar_field) = upvar_field =>
{
let closure_kind_ty = closure_args.as_closure().kind_ty();
let closure_kind = match closure_kind_ty.to_opt_closure_kind() {
@@ -496,7 +487,7 @@ fn report_cannot_move_from_borrowed_content(
let capture_description =
format!("captured variable in an `{closure_kind}` closure");
- let upvar = &self.upvars[upvar_field.unwrap().index()];
+ let upvar = &self.upvars[upvar_field.index()];
let upvar_hir_id = upvar.get_root_variable();
let upvar_name = upvar.to_string(tcx);
let upvar_span = tcx.hir_span(upvar_hir_id);
@@ -606,7 +597,7 @@ fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span
}
// No binding. Nothing to suggest.
GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => {
- let use_span = use_spans.var_or_use();
+ let mut use_span = use_spans.var_or_use();
let place_ty = original_path.ty(self.body, self.infcx.tcx).ty;
let place_desc = match self.describe_place(original_path.as_ref()) {
Some(desc) => format!("`{desc}`"),
@@ -623,6 +614,36 @@ fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span
);
}
+ if let Some(upvar_field) = self
+ .prefixes(original_path.as_ref(), PrefixSet::All)
+ .find_map(|p| self.is_upvar_field_projection(p))
+ {
+ // Look for the introduction of the original binding being moved.
+ let upvar = &self.upvars[upvar_field.index()];
+ let upvar_hir_id = upvar.get_root_variable();
+ use_span = match self.infcx.tcx.parent_hir_node(upvar_hir_id) {
+ hir::Node::Param(param) => {
+ // Instead of pointing at the path where we access the value within a
+ // closure, we point at the type of the outer `fn` argument.
+ param.ty_span
+ }
+ hir::Node::LetStmt(stmt) => match (stmt.ty, stmt.init) {
+ // We point at the type of the outer let-binding.
+ (Some(ty), _) => ty.span,
+ // We point at the initializer of the outer let-binding, but only if it
+ // isn't something that spans multiple lines, like a closure, as the
+ // ASCII art gets messy.
+ (None, Some(init))
+ if !self.infcx.tcx.sess.source_map().is_multiline(init.span) =>
+ {
+ init.span
+ }
+ _ => use_span,
+ },
+ _ => use_span,
+ };
+ }
+
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move: false,
ty: place_ty,
@@ -630,12 +651,22 @@ fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span
span: use_span,
});
+ let mut pointed_at_span = false;
use_spans.args_subdiag(err, |args_span| {
+ if args_span == span || args_span == use_span {
+ pointed_at_span = true;
+ }
crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
- place: place_desc,
+ place: place_desc.clone(),
args_span,
}
});
+ if !pointed_at_span && use_span != span {
+ err.subdiagnostic(crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
+ place: place_desc,
+ args_span: span,
+ });
+ }
self.add_note_for_packed_struct_derive(err, original_path.local);
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index a06540f..5d9416b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -682,7 +682,7 @@ fn is_error_in_trait(&self, local: Local) -> (bool, bool, Option<Span>) {
}
let my_def = self.body.source.def_id();
let Some(td) =
- self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
+ self.infcx.tcx.impl_of_assoc(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
else {
return (false, false, None);
};
@@ -880,7 +880,7 @@ fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) -> Self::Result {
let opt_suggestions = tcx
.typeck(path_segment.hir_id.owner.def_id)
.type_dependent_def_id(expr.hir_id)
- .and_then(|def_id| tcx.impl_of_method(def_id))
+ .and_then(|def_id| tcx.impl_of_assoc(def_id))
.map(|def_id| tcx.associated_items(def_id))
.map(|assoc_items| {
assoc_items
@@ -1056,7 +1056,7 @@ fn suggest_using_iter_mut(&self, err: &mut Diag<'_>) {
.tcx
.typeck(path_segment.hir_id.owner.def_id)
.type_dependent_def_id(cur_expr.hir_id)
- .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
+ .and_then(|def_id| self.infcx.tcx.impl_of_assoc(def_id))
.map(|def_id| self.infcx.tcx.associated_items(def_id))
.map(|assoc_items| {
assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index edd14d1..517f9e8 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -528,15 +528,15 @@ fn highlight_if_we_can_match_hir_ty(
// match_adt_and_segment in this case.
Res::Def(DefKind::TyAlias, _) => (),
_ => {
- if let Some(last_segment) = path.segments.last() {
- if let Some(highlight) = self.match_adt_and_segment(
+ if let Some(last_segment) = path.segments.last()
+ && let Some(highlight) = self.match_adt_and_segment(
args,
needle_fr,
last_segment,
search_stack,
- ) {
- return Some(highlight);
- }
+ )
+ {
+ return Some(highlight);
}
}
}
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 5f1b655..68f1637 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -822,10 +822,10 @@ fn check_type_tests(
continue;
}
- if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
- if self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) {
- continue;
- }
+ if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements
+ && self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements)
+ {
+ continue;
}
// Type-test failed. Report the error.
@@ -1479,40 +1479,36 @@ fn try_propagate_universal_region_error(
shorter_fr: RegionVid,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
) -> RegionRelationCheckResult {
- if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
+ if let Some(propagated_outlives_requirements) = propagated_outlives_requirements
// Shrink `longer_fr` until we find a non-local region (if we do).
// We'll call it `fr-` -- it's ever so slightly smaller than
// `longer_fr`.
- if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr)
- {
- debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);
+ && let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr)
+ {
+ debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);
- let blame_span_category = self.find_outlives_blame_span(
- longer_fr,
- NllRegionVariableOrigin::FreeRegion,
- shorter_fr,
- );
+ let blame_span_category = self.find_outlives_blame_span(
+ longer_fr,
+ NllRegionVariableOrigin::FreeRegion,
+ shorter_fr,
+ );
- // Grow `shorter_fr` until we find some non-local regions. (We
- // always will.) We'll call them `shorter_fr+` -- they're ever
- // so slightly larger than `shorter_fr`.
- let shorter_fr_plus =
- self.universal_region_relations.non_local_upper_bounds(shorter_fr);
- debug!(
- "try_propagate_universal_region_error: shorter_fr_plus={:?}",
- shorter_fr_plus
- );
- for fr in shorter_fr_plus {
- // Push the constraint `fr-: shorter_fr+`
- propagated_outlives_requirements.push(ClosureOutlivesRequirement {
- subject: ClosureOutlivesSubject::Region(fr_minus),
- outlived_free_region: fr,
- blame_span: blame_span_category.1.span,
- category: blame_span_category.0,
- });
- }
- return RegionRelationCheckResult::Propagated;
+ // Grow `shorter_fr` until we find some non-local regions. (We
+ // always will.) We'll call them `shorter_fr+` -- they're ever
+ // so slightly larger than `shorter_fr`.
+ let shorter_fr_plus =
+ self.universal_region_relations.non_local_upper_bounds(shorter_fr);
+ debug!("try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus);
+ for fr in shorter_fr_plus {
+ // Push the constraint `fr-: shorter_fr+`
+ propagated_outlives_requirements.push(ClosureOutlivesRequirement {
+ subject: ClosureOutlivesSubject::Region(fr_minus),
+ outlived_free_region: fr,
+ blame_span: blame_span_category.1.span,
+ category: blame_span_category.0,
+ });
}
+ return RegionRelationCheckResult::Propagated;
}
RegionRelationCheckResult::Error
@@ -2085,11 +2081,11 @@ pub(crate) fn find_loop_terminator_location(
let locations = self.scc_values.locations_outlived_by(scc);
for location in locations {
let bb = &body[location.block];
- if let Some(terminator) = &bb.terminator {
+ if let Some(terminator) = &bb.terminator
// terminator of a loop should be TerminatorKind::FalseUnwind
- if let TerminatorKind::FalseUnwind { .. } = terminator.kind {
- return Some(location);
- }
+ && let TerminatorKind::FalseUnwind { .. } = terminator.kind
+ {
+ return Some(location);
}
}
None
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index d500088..f5fedbf 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -669,24 +669,24 @@ fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) {
);
}
- if let Some(annotation_index) = self.rvalue_user_ty(rv) {
- if let Err(terr) = self.relate_type_and_user_type(
+ if let Some(annotation_index) = self.rvalue_user_ty(rv)
+ && let Err(terr) = self.relate_type_and_user_type(
rv_ty,
ty::Invariant,
&UserTypeProjection { base: annotation_index, projs: vec![] },
location.to_locations(),
ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg),
- ) {
- let annotation = &self.user_type_annotations[annotation_index];
- span_mirbug!(
- self,
- stmt,
- "bad user type on rvalue ({:?} = {:?}): {:?}",
- annotation,
- rv_ty,
- terr
- );
- }
+ )
+ {
+ let annotation = &self.user_type_annotations[annotation_index];
+ span_mirbug!(
+ self,
+ stmt,
+ "bad user type on rvalue ({:?} = {:?}): {:?}",
+ annotation,
+ rv_ty,
+ terr
+ );
}
if !self.unsized_feature_enabled() {
@@ -1761,7 +1761,7 @@ fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, location: Locat
);
assert!(!matches!(
- tcx.impl_of_method(def_id).map(|imp| tcx.def_kind(imp)),
+ tcx.impl_of_assoc(def_id).map(|imp| tcx.def_kind(imp)),
Some(DefKind::Impl { of_trait: true })
));
self.prove_predicates(
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index f138f26..240c9a5 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -969,13 +969,28 @@ fn for_each_late_bound_region_in_item<'tcx>(
mir_def_id: LocalDefId,
mut f: impl FnMut(ty::Region<'tcx>),
) {
- if !tcx.def_kind(mir_def_id).is_fn_like() {
- return;
- }
+ let bound_vars = match tcx.def_kind(mir_def_id) {
+ DefKind::Fn | DefKind::AssocFn => {
+ tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id))
+ }
+ // We extract the bound vars from the deduced closure signature, since we may have
+ // only deduced that a param in the closure signature is late-bound from a constraint
+ // that we discover during typeck.
+ DefKind::Closure => {
+ let ty = tcx.type_of(mir_def_id).instantiate_identity();
+ match *ty.kind() {
+ ty::Closure(_, args) => args.as_closure().sig().bound_vars(),
+ ty::CoroutineClosure(_, args) => {
+ args.as_coroutine_closure().coroutine_closure_sig().bound_vars()
+ }
+ ty::Coroutine(_, _) | ty::Error(_) => return,
+ _ => unreachable!("unexpected type for closure: {ty}"),
+ }
+ }
+ _ => return,
+ };
- for (idx, bound_var) in
- tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id)).iter().enumerate()
- {
+ for (idx, bound_var) in bound_vars.iter().enumerate() {
if let ty::BoundVariableKind::Region(kind) = bound_var {
let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind);
let liberated_region = ty::Region::new_late_param(tcx, mir_def_id.to_def_id(), kind);
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index 42b7e0e..09f5e6f 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -1,11 +1,13 @@
-use std::mem;
+use std::{mem, slice};
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, Visitor};
-use rustc_ast::{self as ast, NodeId, attr};
+use rustc_ast::{self as ast, HasNodeId, NodeId, attr};
use rustc_ast_pretty::pprust;
+use rustc_attr_data_structures::AttributeKind;
+use rustc_attr_parsing::AttributeParser;
use rustc_errors::DiagCtxtHandle;
-use rustc_expand::base::{ExtCtxt, ResolverExpand, parse_macro_name_and_helper_attrs};
+use rustc_expand::base::{ExtCtxt, ResolverExpand};
use rustc_expand::expand::{AstFragment, ExpansionConfig};
use rustc_feature::Features;
use rustc_session::Session;
@@ -22,7 +24,7 @@ struct ProcMacroDerive {
trait_name: Symbol,
function_ident: Ident,
span: Span,
- attrs: Vec<Symbol>,
+ attrs: ThinVec<Symbol>,
}
struct ProcMacroDef {
@@ -41,6 +43,7 @@ struct CollectProcMacros<'a> {
macros: Vec<ProcMacro>,
in_root: bool,
dcx: DiagCtxtHandle<'a>,
+ session: &'a Session,
source_map: &'a SourceMap,
is_proc_macro_crate: bool,
is_test_crate: bool,
@@ -63,6 +66,7 @@ pub fn inject(
macros: Vec::new(),
in_root: true,
dcx,
+ session: sess,
source_map: sess.source_map(),
is_proc_macro_crate,
is_test_crate,
@@ -98,8 +102,18 @@ fn collect_custom_derive(
function_ident: Ident,
attr: &'a ast::Attribute,
) {
- let Some((trait_name, proc_attrs)) =
- parse_macro_name_and_helper_attrs(self.dcx, attr, "derive")
+ let Some(rustc_hir::Attribute::Parsed(AttributeKind::ProcMacroDerive {
+ trait_name,
+ helper_attrs,
+ ..
+ })) = AttributeParser::parse_limited(
+ self.session,
+ slice::from_ref(attr),
+ sym::proc_macro_derive,
+ item.span,
+ item.node_id(),
+ None,
+ )
else {
return;
};
@@ -110,7 +124,7 @@ fn collect_custom_derive(
span: item.span,
trait_name,
function_ident,
- attrs: proc_attrs,
+ attrs: helper_attrs,
}));
} else {
let msg = if !self.in_root {
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index 682e7c9..2068b5c 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -47,8 +47,6 @@ pub fn inject(
ast::ItemKind::ExternCrate(None, Ident::new(name, ident_span)),
);
- krate.items.insert(0, item);
-
let root = (edition == Edition2015).then_some(kw::PathRoot);
let import_path = root
@@ -75,6 +73,6 @@ pub fn inject(
}),
);
- krate.items.insert(0, use_item);
+ krate.items.splice(0..0, [item, use_item]);
krate.items.len() - orig_num_items
}
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch
index f6e6bbc..f3d1d5c 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch
@@ -19,7 +19,7 @@
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
#![cfg_attr(test, feature(cfg_select))]
#![feature(alloc_layout_extra)]
- #![feature(array_chunks)]
+ #![feature(array_ptr_get)]
diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs
index b735957..ea728b6 100644
--- a/coretests/tests/atomic.rs
diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs
index 113abe7..c123114 100644
--- a/compiler/rustc_codegen_gcc/src/back/write.rs
+++ b/compiler/rustc_codegen_gcc/src/back/write.rs
@@ -4,7 +4,6 @@
use rustc_codegen_ssa::back::link::ensure_removed;
use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig};
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
-use rustc_errors::DiagCtxtHandle;
use rustc_fs_util::link_or_copy;
use rustc_session::config::OutputType;
use rustc_span::fatal_error::FatalError;
@@ -258,14 +257,6 @@ pub(crate) fn codegen(
))
}
-pub(crate) fn link(
- _cgcx: &CodegenContext<GccCodegenBackend>,
- _dcx: DiagCtxtHandle<'_>,
- mut _modules: Vec<ModuleCodegen<GccContext>>,
-) -> Result<ModuleCodegen<GccContext>, FatalError> {
- unimplemented!();
-}
-
pub(crate) fn save_temp_bitcode(
cgcx: &CodegenContext<GccCodegenBackend>,
_module: &ModuleCodegen<GccContext>,
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 71765c5..a312068 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -426,14 +426,6 @@ fn prepare_thin(
fn serialize_module(_module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
unimplemented!();
}
-
- fn run_link(
- cgcx: &CodegenContext<Self>,
- dcx: DiagCtxtHandle<'_>,
- modules: Vec<ModuleCodegen<Self::Module>>,
- ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
- back::write::link(cgcx, dcx, modules)
- }
}
/// This is the entrypoint for a hot plugged rustc_codegen_gccjit
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index 3d5f17a..ce9a51b 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -12,7 +12,7 @@
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
-codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$llvm_err})
+codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$err})
codegen_llvm_mismatch_data_layout =
data-layout for target `{$rustc_target}`, `{$rustc_layout}`, differs from LLVM target's `{$llvm_target}` default layout, `{$llvm_layout}`
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 767835c..c269f11 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -7,6 +7,7 @@
use std::{io, iter, slice};
use object::read::archive::ArchiveFile;
+use object::{Object, ObjectSection};
use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared};
use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput};
use rustc_codegen_ssa::traits::*;
@@ -105,31 +106,15 @@ fn get_bitcode_slice_from_object_data<'a>(
// name" which in the public API for sections gets treated as part of the section name, but
// internally in MachOObjectFile.cpp gets treated separately.
let section_name = bitcode_section_name(cgcx).to_str().unwrap().trim_start_matches("__LLVM,");
- let mut len = 0;
- let data = unsafe {
- llvm::LLVMRustGetSliceFromObjectDataByName(
- obj.as_ptr(),
- obj.len(),
- section_name.as_ptr(),
- section_name.len(),
- &mut len,
- )
- };
- if !data.is_null() {
- assert!(len != 0);
- let bc = unsafe { slice::from_raw_parts(data, len) };
- // `bc` must be a sub-slice of `obj`.
- assert!(obj.as_ptr() <= bc.as_ptr());
- assert!(bc[bc.len()..bc.len()].as_ptr() <= obj[obj.len()..obj.len()].as_ptr());
+ let obj =
+ object::File::parse(obj).map_err(|err| LtoBitcodeFromRlib { err: err.to_string() })?;
- Ok(bc)
- } else {
- assert!(len == 0);
- Err(LtoBitcodeFromRlib {
- llvm_err: llvm::last_error().unwrap_or_else(|| "unknown LLVM error".to_string()),
- })
- }
+ let section = obj
+ .section_by_name(section_name)
+ .ok_or_else(|| LtoBitcodeFromRlib { err: format!("Can't find section {section_name}") })?;
+
+ section.data().map_err(|err| LtoBitcodeFromRlib { err: err.to_string() })
}
/// Performs fat LTO by merging all modules into a single one and returning it
@@ -505,10 +490,10 @@ fn thin_lto(
// Save the current ThinLTO import information for the next compilation
// session, overwriting the previous serialized data (if any).
- if let Some(path) = key_map_path {
- if let Err(err) = curr_key_map.save_to_file(&path) {
- return Err(write::llvm_err(dcx, LlvmError::WriteThinLtoKey { err }));
- }
+ if let Some(path) = key_map_path
+ && let Err(err) = curr_key_map.save_to_file(&path)
+ {
+ return Err(write::llvm_err(dcx, LlvmError::WriteThinLtoKey { err }));
}
Ok((opt_jobs, copy_jobs))
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 6f8fba2..85a06f4 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -796,29 +796,6 @@ pub(crate) fn optimize(
Ok(())
}
-pub(crate) fn link(
- cgcx: &CodegenContext<LlvmCodegenBackend>,
- dcx: DiagCtxtHandle<'_>,
- mut modules: Vec<ModuleCodegen<ModuleLlvm>>,
-) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
- use super::lto::{Linker, ModuleBuffer};
- // Sort the modules by name to ensure deterministic behavior.
- modules.sort_by(|a, b| a.name.cmp(&b.name));
- let (first, elements) =
- modules.split_first().expect("Bug! modules must contain at least one module.");
-
- let mut linker = Linker::new(first.module_llvm.llmod());
- for module in elements {
- let _timer = cgcx.prof.generic_activity_with_arg("LLVM_link_module", &*module.name);
- let buffer = ModuleBuffer::new(module.module_llvm.llmod());
- linker
- .add(buffer.data())
- .map_err(|()| llvm_err(dcx, LlvmError::SerializeModule { name: &module.name }))?;
- }
- drop(linker);
- Ok(modules.remove(0))
-}
-
pub(crate) fn codegen(
cgcx: &CodegenContext<LlvmCodegenBackend>,
module: ModuleCodegen<ModuleLlvm>,
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 0ade9ed..f712b3b 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -687,10 +687,10 @@ fn scalar_load_metadata<'a, 'll, 'tcx>(
bx.nonnull_metadata(load);
}
- if let Some(pointee) = layout.pointee_info_at(bx, offset) {
- if let Some(_) = pointee.safe {
- bx.align_metadata(load, pointee.align);
- }
+ if let Some(pointee) = layout.pointee_info_at(bx, offset)
+ && let Some(_) = pointee.safe
+ {
+ bx.align_metadata(load, pointee.align);
}
}
abi::Primitive::Float(_) => {}
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index a9be833..8c9dfcf 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -46,21 +46,17 @@ pub(crate) fn finalize(cx: &mut CodegenCx<'_, '_>) {
debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
// FIXME(#132395): Can this be none even when coverage is enabled?
- let instances_used = match cx.coverage_cx {
- Some(ref cx) => cx.instances_used.borrow(),
- None => return,
- };
+ let Some(ref coverage_cx) = cx.coverage_cx else { return };
- let mut covfun_records = instances_used
- .iter()
- .copied()
+ let mut covfun_records = coverage_cx
+ .instances_used()
+ .into_iter()
// Sort by symbol name, so that the global file table is built in an
// order that doesn't depend on the stable-hash-based order in which
// instances were visited during codegen.
.sorted_by_cached_key(|&instance| tcx.symbol_name(instance).name)
.filter_map(|instance| prepare_covfun_record(tcx, instance, true))
.collect::<Vec<_>>();
- drop(instances_used);
// In a single designated CGU, also prepare covfun records for functions
// in this crate that were instrumented for coverage, but are unused.
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
index 574463b..39a5956 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
@@ -39,10 +39,7 @@ pub(crate) fn make_coverage_span(&self, local_file_id: LocalFileId) -> ffi::Cove
/// or other expansions), and if it does happen then skipping a span or function is
/// better than an ICE or `llvm-cov` failure that the user might have no way to avoid.
pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span) -> Option<Coords> {
- if span.is_empty() {
- debug_assert!(false, "can't make coords from empty span: {span:?}");
- return None;
- }
+ let span = ensure_non_empty_span(source_map, span)?;
let lo = span.lo();
let hi = span.hi();
@@ -73,6 +70,29 @@ pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span)
})
}
+fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> {
+ if !span.is_empty() {
+ return Some(span);
+ }
+
+ // The span is empty, so try to enlarge it to cover an adjacent '{' or '}'.
+ source_map
+ .span_to_source(span, |src, start, end| try {
+ // Adjusting span endpoints by `BytePos(1)` is normally a bug,
+ // but in this case we have specifically checked that the character
+ // we're skipping over is one of two specific ASCII characters, so
+ // adjusting by exactly 1 byte is correct.
+ if src.as_bytes().get(end).copied() == Some(b'{') {
+ Some(span.with_hi(span.hi() + BytePos(1)))
+ } else if start > 0 && src.as_bytes()[start - 1] == b'}' {
+ Some(span.with_lo(span.lo() - BytePos(1)))
+ } else {
+ None
+ }
+ })
+ .ok()?
+}
+
/// If `llvm-cov` sees a source region that is improperly ordered (end < start),
/// it will immediately exit with a fatal error. To prevent that from happening,
/// discard regions that are improperly ordered, or might be interpreted in a
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index eefbd7c..119237a 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -5,7 +5,7 @@
use rustc_codegen_ssa::traits::{
BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
};
-use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::ty::Instance;
use tracing::{debug, instrument};
@@ -20,9 +20,14 @@
/// Extra per-CGU context/state needed for coverage instrumentation.
pub(crate) struct CguCoverageContext<'ll, 'tcx> {
- /// Coverage data for each instrumented function identified by DefId.
- pub(crate) instances_used: RefCell<FxIndexSet<Instance<'tcx>>>,
- pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
+ /// Associates function instances with an LLVM global that holds the
+ /// function's symbol name, as needed by LLVM coverage intrinsics.
+ ///
+ /// Instances in this map are also considered "used" for the purposes of
+ /// emitting covfun records. Every covfun record holds a hash of its
+ /// symbol name, and `llvm-cov` will exit fatally if it can't resolve that
+ /// hash back to an entry in the binary's `__llvm_prf_names` linker section.
+ pub(crate) pgo_func_name_var_map: RefCell<FxIndexMap<Instance<'tcx>, &'ll llvm::Value>>,
pub(crate) mcdc_condition_bitmap_map: RefCell<FxHashMap<Instance<'tcx>, Vec<&'ll llvm::Value>>>,
covfun_section_name: OnceCell<CString>,
@@ -31,7 +36,6 @@ pub(crate) struct CguCoverageContext<'ll, 'tcx> {
impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
pub(crate) fn new() -> Self {
Self {
- instances_used: RefCell::<FxIndexSet<_>>::default(),
pgo_func_name_var_map: Default::default(),
mcdc_condition_bitmap_map: Default::default(),
covfun_section_name: Default::default(),
@@ -53,6 +57,14 @@ fn try_get_mcdc_condition_bitmap(
.and_then(|bitmap_map| bitmap_map.get(decision_depth as usize))
.copied() // Dereference Option<&&Value> to Option<&Value>
}
+
+ /// Returns the list of instances considered "used" in this CGU, as
+ /// inferred from the keys of `pgo_func_name_var_map`.
+ pub(crate) fn instances_used(&self) -> Vec<Instance<'tcx>> {
+ // Collecting into a Vec is way easier than trying to juggle RefCell
+ // projections, and this should only run once per CGU anyway.
+ self.pgo_func_name_var_map.borrow().keys().copied().collect::<Vec<_>>()
+ }
}
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
@@ -78,7 +90,10 @@ fn covfun_section_name(&self) -> &CStr {
/// string, to hold the function name passed to LLVM intrinsic
/// `instrprof.increment()`. The `Value` is only created once per instance.
/// Multiple invocations with the same instance return the same `Value`.
- fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
+ ///
+ /// This has the side-effect of causing coverage codegen to consider this
+ /// function "used", making it eligible to emit an associated covfun record.
+ fn ensure_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
debug!("getting pgo_func_name_var for instance={:?}", instance);
let mut pgo_func_name_var_map = self.coverage_cx().pgo_func_name_var_map.borrow_mut();
pgo_func_name_var_map.entry(instance).or_insert_with(|| {
@@ -102,7 +117,7 @@ fn init_coverage(&mut self, instance: Instance<'tcx>) {
return;
}
- let fn_name = self.get_pgo_func_name_var(instance);
+ let fn_name = self.ensure_pgo_func_name_var(instance);
let hash = self.const_u64(function_coverage_info.function_source_hash);
let bitmap_bits = self.const_u32(function_coverage_info.mcdc_bitmap_bits as u32);
self.mcdc_parameters(fn_name, hash, bitmap_bits);
@@ -151,11 +166,6 @@ fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
return;
};
- // Mark the instance as used in this CGU, for coverage purposes.
- // This includes functions that were not partitioned into this CGU,
- // but were MIR-inlined into one of this CGU's functions.
- coverage_cx.instances_used.borrow_mut().insert(instance);
-
match *kind {
CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
"marker statement {kind:?} should have been removed by CleanupPostBorrowck"
@@ -163,7 +173,7 @@ fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
CoverageKind::VirtualCounter { bcb }
if let Some(&id) = ids_info.phys_counter_for_node.get(&bcb) =>
{
- let fn_name = bx.get_pgo_func_name_var(instance);
+ let fn_name = bx.ensure_pgo_func_name_var(instance);
let hash = bx.const_u64(function_coverage_info.function_source_hash);
let num_counters = bx.const_u32(ids_info.num_counters);
let index = bx.const_u32(id.as_u32());
@@ -193,7 +203,7 @@ fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
"bitmap index of the decision out of range"
);
- let fn_name = bx.get_pgo_func_name_var(instance);
+ let fn_name = bx.ensure_pgo_func_name_var(instance);
let hash = bx.const_u64(function_coverage_info.function_source_hash);
let bitmap_index = bx.const_u32(bitmap_idx);
bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap);
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 56fb12d..d1502d2 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -285,8 +285,8 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
// Item(T),
// }
// ```
- let is_expanding_recursive =
- debug_context(cx).adt_stack.borrow().iter().any(|(parent_def_id, parent_args)| {
+ let is_expanding_recursive = adt_def.is_enum()
+ && 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())
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 5ca2505..6cbf2db 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -533,7 +533,7 @@ fn get_containing_scope<'ll, 'tcx>(
// First, let's see if this is a method within an inherent impl. Because
// if yes, we want to make the result subroutine DIE a child of the
// subroutine's self-type.
- if let Some(impl_def_id) = cx.tcx.impl_of_method(instance.def_id()) {
+ if let Some(impl_def_id) = cx.tcx.impl_of_assoc(instance.def_id()) {
// If the method does *not* belong to a trait, proceed
if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index 2a88988..627b0c9 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -39,7 +39,7 @@ fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
#[derive(Diagnostic)]
#[diag(codegen_llvm_lto_bitcode_from_rlib)]
pub(crate) struct LtoBitcodeFromRlib {
- pub llvm_err: String,
+ pub err: String,
}
#[derive(Diagnostic)]
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index fcc0d37..7b27e49 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -382,26 +382,16 @@ fn codegen_intrinsic_call(
let width = size.bits();
let llty = self.type_ix(width);
match name {
- sym::ctlz | sym::cttz => {
- let y = self.const_bool(false);
- let ret = self.call_intrinsic(
- format!("llvm.{name}"),
- &[llty],
- &[args[0].immediate(), y],
- );
-
- self.intcast(ret, result.layout.llvm_type(self), false)
- }
- sym::ctlz_nonzero => {
- let y = self.const_bool(true);
+ sym::ctlz | sym::ctlz_nonzero | sym::cttz | sym::cttz_nonzero => {
+ let y =
+ self.const_bool(name == sym::ctlz_nonzero || name == sym::cttz_nonzero);
+ let llvm_name = if name == sym::ctlz || name == sym::ctlz_nonzero {
+ "llvm.ctlz"
+ } else {
+ "llvm.cttz"
+ };
let ret =
- self.call_intrinsic("llvm.ctlz", &[llty], &[args[0].immediate(), y]);
- self.intcast(ret, result.layout.llvm_type(self), false)
- }
- sym::cttz_nonzero => {
- let y = self.const_bool(true);
- let ret =
- self.call_intrinsic("llvm.cttz", &[llty], &[args[0].immediate(), y]);
+ self.call_intrinsic(llvm_name, &[llty], &[args[0].immediate(), y]);
self.intcast(ret, result.layout.llvm_type(self), false)
}
sym::ctpop => {
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 8b1913c..ca84b6d 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -168,13 +168,6 @@ fn print_statistics(&self) {
let stats = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap();
print!("{stats}");
}
- fn run_link(
- cgcx: &CodegenContext<Self>,
- dcx: DiagCtxtHandle<'_>,
- modules: Vec<ModuleCodegen<Self::Module>>,
- ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
- back::write::link(cgcx, dcx, modules)
- }
fn run_and_optimize_fat_lto(
cgcx: &CodegenContext<Self>,
exported_symbols_for_lto: &[String],
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index edfb29d..0d0cb5f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2612,13 +2612,6 @@ pub(crate) fn LLVMRustParseBitcodeForLTO(
len: usize,
Identifier: *const c_char,
) -> Option<&Module>;
- pub(crate) fn LLVMRustGetSliceFromObjectDataByName(
- data: *const u8,
- len: usize,
- name: *const u8,
- name_len: usize,
- out_len: &mut usize,
- ) -> *const u8;
pub(crate) fn LLVMRustLinkerNew(M: &Module) -> &mut Linker<'_>;
pub(crate) fn LLVMRustLinkerAdd(
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 0fb987b..53899da 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -405,6 +405,8 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
("mips64" | "mips64r6", _) => false,
// Selection bug <https://github.com/llvm/llvm-project/issues/95471>
("nvptx64", _) => false,
+ // Unsupported https://github.com/llvm/llvm-project/issues/121122
+ ("amdgpu", _) => false,
// ABI bugs <https://github.com/rust-lang/rust/issues/125109> et al. (full
// list at <https://github.com/rust-lang/rust/issues/116909>)
("powerpc" | "powerpc64", _) => false,
@@ -433,6 +435,9 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
// This rules out anything that doesn't have `long double` = `binary128`; <= 32 bits
// (ld is `f64`), anything other than Linux (Windows and MacOS use `f64`), and `x86`
// (ld is 80-bit extended precision).
+ //
+ // musl does not implement the symbols required for f128 math at all.
+ _ if target_env == "musl" => false,
("x86_64", _) => false,
(_, "linux") if target_pointer_width == 64 => true,
_ => false,
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index cfae1b3..94501da 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -8,8 +8,8 @@
ar_archive_writer = "0.4.2"
bitflags = "2.4.1"
bstr = "1.11.3"
-# Pinned so `cargo update` bumps don't cause breakage. Please also update the
-# `cc` in `rustc_llvm` if you update the `cc` here.
+# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version
+# per crate", so if you change this, you need to also change it in `rustc_llvm`.
cc = "=1.2.16"
itertools = "0.12"
pathdiff = "0.2.0"
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 5ce301c..162fbf3 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -3369,12 +3369,12 @@ fn elf_has_gold_version_note<'a>(
let section =
elf.sections(endian, data)?.section_by_name(endian, b".note.gnu.gold-version");
- if let Some((_, section)) = section {
- if let Some(mut notes) = section.notes(endian, data)? {
- return Ok(notes.any(|note| {
- note.is_ok_and(|note| note.n_type(endian) == elf::NT_GNU_GOLD_VERSION)
- }));
- }
+ if let Some((_, section)) = section
+ && let Some(mut notes) = section.notes(endian, data)?
+ {
+ return Ok(notes.any(|note| {
+ note.is_ok_and(|note| note.n_type(endian) == elf::NT_GNU_GOLD_VERSION)
+ }));
}
Ok(false)
diff --git a/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs
index 74f3902..b9e0c95 100644
--- a/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs
@@ -4,7 +4,7 @@
use rustc_abi::Endian;
use rustc_data_structures::base_n::{CASE_INSENSITIVE, ToBaseN};
-use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_hashes::Hash128;
use rustc_session::Session;
@@ -214,7 +214,7 @@ pub(super) fn create_raw_dylib_elf_stub_shared_objects<'a>(
/// It exports all the provided symbols, but is otherwise empty.
fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]) -> Vec<u8> {
use object::write::elf as write;
- use object::{Architecture, elf};
+ use object::{AddressSize, Architecture, elf};
let mut stub_buf = Vec::new();
@@ -226,47 +226,6 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
// It is important that the order of reservation matches the order of writing.
// The object crate contains many debug asserts that fire if you get this wrong.
- let endianness = match sess.target.options.endian {
- Endian::Little => object::Endianness::Little,
- Endian::Big => object::Endianness::Big,
- };
- let mut stub = write::Writer::new(endianness, true, &mut stub_buf);
-
- // These initial reservations don't reserve any bytes in the binary yet,
- // they just allocate in the internal data structures.
-
- // First, we crate the dynamic symbol table. It starts with a null symbol
- // and then all the symbols and their dynamic strings.
- stub.reserve_null_dynamic_symbol_index();
-
- let dynstrs = symbols
- .iter()
- .map(|sym| {
- stub.reserve_dynamic_symbol_index();
- (sym, stub.add_dynamic_string(sym.name.as_str().as_bytes()))
- })
- .collect::<Vec<_>>();
-
- let soname = stub.add_dynamic_string(soname.as_bytes());
-
- // Reserve the sections.
- // We have the minimal sections for a dynamic SO and .text where we point our dummy symbols to.
- stub.reserve_shstrtab_section_index();
- let text_section_name = stub.add_section_name(".text".as_bytes());
- let text_section = stub.reserve_section_index();
- stub.reserve_dynstr_section_index();
- stub.reserve_dynsym_section_index();
- stub.reserve_dynamic_section_index();
-
- // These reservations now determine the actual layout order of the object file.
- stub.reserve_file_header();
- stub.reserve_shstrtab();
- stub.reserve_section_headers();
- stub.reserve_dynstr();
- stub.reserve_dynsym();
- stub.reserve_dynamic(2); // DT_SONAME, DT_NULL
-
- // First write the ELF header with the arch information.
let Some((arch, sub_arch)) = sess.target.object_architecture(&sess.unstable_target_features)
else {
sess.dcx().fatal(format!(
@@ -274,6 +233,87 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
sess.target.arch
));
};
+
+ let endianness = match sess.target.options.endian {
+ Endian::Little => object::Endianness::Little,
+ Endian::Big => object::Endianness::Big,
+ };
+
+ let is_64 = match arch.address_size() {
+ Some(AddressSize::U8 | AddressSize::U16 | AddressSize::U32) => false,
+ Some(AddressSize::U64) => true,
+ _ => sess.dcx().fatal(format!(
+ "raw-dylib is not supported for the architecture `{}`",
+ sess.target.arch
+ )),
+ };
+
+ let mut stub = write::Writer::new(endianness, is_64, &mut stub_buf);
+
+ let mut vers = Vec::new();
+ let mut vers_map = FxHashMap::default();
+ let mut syms = Vec::new();
+
+ for symbol in symbols {
+ let symbol_name = symbol.name.as_str();
+ if let Some((name, version_name)) = symbol_name.split_once('@') {
+ assert!(!version_name.contains('@'));
+ let dynstr = stub.add_dynamic_string(name.as_bytes());
+ let ver = if let Some(&ver_id) = vers_map.get(version_name) {
+ ver_id
+ } else {
+ let id = vers.len();
+ vers_map.insert(version_name, id);
+ let dynstr = stub.add_dynamic_string(version_name.as_bytes());
+ vers.push((version_name, dynstr));
+ id
+ };
+ syms.push((name, dynstr, Some(ver)));
+ } else {
+ let dynstr = stub.add_dynamic_string(symbol_name.as_bytes());
+ syms.push((symbol_name, dynstr, None));
+ }
+ }
+
+ let soname = stub.add_dynamic_string(soname.as_bytes());
+
+ // These initial reservations don't reserve any bytes in the binary yet,
+ // they just allocate in the internal data structures.
+
+ // First, we create the dynamic symbol table. It starts with a null symbol
+ // and then all the symbols and their dynamic strings.
+ stub.reserve_null_dynamic_symbol_index();
+
+ for _ in syms.iter() {
+ stub.reserve_dynamic_symbol_index();
+ }
+
+ // Reserve the sections.
+ // We have the minimal sections for a dynamic SO and .text where we point our dummy symbols to.
+ stub.reserve_shstrtab_section_index();
+ let text_section_name = stub.add_section_name(".text".as_bytes());
+ let text_section = stub.reserve_section_index();
+ stub.reserve_dynsym_section_index();
+ stub.reserve_dynstr_section_index();
+ if !vers.is_empty() {
+ stub.reserve_gnu_versym_section_index();
+ stub.reserve_gnu_verdef_section_index();
+ }
+ stub.reserve_dynamic_section_index();
+
+ // These reservations now determine the actual layout order of the object file.
+ stub.reserve_file_header();
+ stub.reserve_shstrtab();
+ stub.reserve_section_headers();
+ stub.reserve_dynsym();
+ stub.reserve_dynstr();
+ if !vers.is_empty() {
+ stub.reserve_gnu_versym();
+ stub.reserve_gnu_verdef(1 + vers.len(), 1 + vers.len());
+ }
+ stub.reserve_dynamic(2); // DT_SONAME, DT_NULL
+
+ // First write the ELF header with the arch information.
let e_machine = match (arch, sub_arch) {
(Architecture::Aarch64, None) => elf::EM_AARCH64,
(Architecture::Aarch64_Ilp32, None) => elf::EM_AARCH64,
@@ -342,18 +382,19 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
sh_addralign: 1,
sh_entsize: 0,
});
- stub.write_dynstr_section_header(0);
stub.write_dynsym_section_header(0, 1);
+ stub.write_dynstr_section_header(0);
+ if !vers.is_empty() {
+ stub.write_gnu_versym_section_header(0);
+ stub.write_gnu_verdef_section_header(0);
+ }
stub.write_dynamic_section_header(0);
- // .dynstr
- stub.write_dynstr();
-
// .dynsym
stub.write_null_dynamic_symbol();
- for (_, name) in dynstrs {
+ for (_name, dynstr, _ver) in syms.iter().copied() {
stub.write_dynamic_symbol(&write::Sym {
- name: Some(name),
+ name: Some(dynstr),
st_info: (elf::STB_GLOBAL << 4) | elf::STT_NOTYPE,
st_other: elf::STV_DEFAULT,
section: Some(text_section),
@@ -363,10 +404,47 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
});
}
+ // .dynstr
+ stub.write_dynstr();
+
+ // ld.bfd is unhappy if these sections exist without any symbols, so we only generate them when necessary.
+ if !vers.is_empty() {
+ // .gnu_version
+ stub.write_null_gnu_versym();
+ for (_name, _dynstr, ver) in syms.iter().copied() {
+ stub.write_gnu_versym(if let Some(ver) = ver {
+ assert!((2 + ver as u16) < elf::VERSYM_HIDDEN);
+ elf::VERSYM_HIDDEN | (2 + ver as u16)
+ } else {
+ 1
+ });
+ }
+
+ // .gnu_version_d
+ stub.write_align_gnu_verdef();
+ stub.write_gnu_verdef(&write::Verdef {
+ version: elf::VER_DEF_CURRENT,
+ flags: elf::VER_FLG_BASE,
+ index: 1,
+ aux_count: 1,
+ name: soname,
+ });
+ for (ver, (_name, dynstr)) in vers.into_iter().enumerate() {
+ stub.write_gnu_verdef(&write::Verdef {
+ version: elf::VER_DEF_CURRENT,
+ flags: 0,
+ index: 2 + ver as u16,
+ aux_count: 1,
+ name: dynstr,
+ });
+ }
+ }
+
// .dynamic
// the DT_SONAME will be used by the linker to populate DT_NEEDED
// which the loader uses to find the library.
// DT_NULL terminates the .dynamic table.
+ stub.write_align_dynamic();
stub.write_dynamic_string(elf::DT_SONAME, soname);
stub.write_dynamic(elf::DT_NULL, 0);
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 2f5eca2..297bdec 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -86,7 +86,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
// Only consider nodes that actually have exported symbols.
match tcx.def_kind(def_id) {
DefKind::Fn | DefKind::Static { .. } => {}
- DefKind::AssocFn if tcx.impl_of_method(def_id.to_def_id()).is_some() => {}
+ DefKind::AssocFn if tcx.impl_of_assoc(def_id.to_def_id()).is_some() => {}
_ => return None,
};
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 7be274d..6773d3e 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -1,4 +1,3 @@
-use std::any::Any;
use std::assert_matches::assert_matches;
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
@@ -372,8 +371,6 @@ pub struct CodegenContext<B: WriteBackendMethods> {
/// The incremental compilation session directory, or None if we are not
/// compiling incrementally
pub incr_comp_session_dir: Option<PathBuf>,
- /// Channel back to the main control thread to send messages to
- pub coordinator_send: Sender<Box<dyn Any + Send>>,
/// `true` if the codegen should be run in parallel.
///
/// Depends on [`ExtraBackendMethods::supports_parallel()`] and `-Zno_parallel_backend`.
@@ -800,10 +797,6 @@ pub(crate) enum WorkItemResult<B: WriteBackendMethods> {
/// The backend has finished compiling a CGU, nothing more required.
Finished(CompiledModule),
- /// The backend has finished compiling a CGU, which now needs linking
- /// because `-Zcombine-cgu` was specified.
- NeedsLink(ModuleCodegen<B::Module>),
-
/// The backend has finished compiling a CGU, which now needs to go through
/// fat LTO.
NeedsFatLto(FatLtoInput<B>),
@@ -887,7 +880,10 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
};
match lto_type {
- ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config),
+ ComputedLtoType::No => {
+ let module = B::codegen(cgcx, module, module_config)?;
+ Ok(WorkItemResult::Finished(module))
+ }
ComputedLtoType::Thin => {
let (name, thin_buffer) = B::prepare_thin(module, false);
if let Some(path) = bitcode {
@@ -1027,20 +1023,8 @@ fn execute_thin_lto_work_item<B: ExtraBackendMethods>(
module_config: &ModuleConfig,
) -> Result<WorkItemResult<B>, FatalError> {
let module = B::optimize_thin(cgcx, module)?;
- finish_intra_module_work(cgcx, module, module_config)
-}
-
-fn finish_intra_module_work<B: ExtraBackendMethods>(
- cgcx: &CodegenContext<B>,
- module: ModuleCodegen<B::Module>,
- module_config: &ModuleConfig,
-) -> Result<WorkItemResult<B>, FatalError> {
- if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Allocator {
- let module = B::codegen(cgcx, module, module_config)?;
- Ok(WorkItemResult::Finished(module))
- } else {
- Ok(WorkItemResult::NeedsLink(module))
- }
+ let module = B::codegen(cgcx, module, module_config)?;
+ Ok(WorkItemResult::Finished(module))
}
/// Messages sent to the coordinator.
@@ -1122,10 +1106,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
autodiff_items: &[AutoDiffItem],
shared_emitter: SharedEmitter,
codegen_worker_send: Sender<CguMessage>,
- coordinator_receive: Receiver<Box<dyn Any + Send>>,
+ coordinator_receive: Receiver<Message<B>>,
regular_config: Arc<ModuleConfig>,
allocator_config: Arc<ModuleConfig>,
- tx_to_llvm_workers: Sender<Box<dyn Any + Send>>,
+ tx_to_llvm_workers: Sender<Message<B>>,
) -> thread::JoinHandle<Result<CompiledModules, ()>> {
let coordinator_send = tx_to_llvm_workers;
let sess = tcx.sess;
@@ -1153,7 +1137,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
let coordinator_send2 = coordinator_send.clone();
let helper = jobserver::client()
.into_helper_thread(move |token| {
- drop(coordinator_send2.send(Box::new(Message::Token::<B>(token))));
+ drop(coordinator_send2.send(Message::Token::<B>(token)));
})
.expect("failed to spawn helper thread");
@@ -1187,7 +1171,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
remark: sess.opts.cg.remark.clone(),
remark_dir,
incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()),
- coordinator_send,
expanded_args: tcx.sess.expanded_args.clone(),
diag_emitter: shared_emitter.clone(),
output_filenames: Arc::clone(tcx.output_filenames(())),
@@ -1347,7 +1330,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
// through codegen and LLVM.
let mut compiled_modules = vec![];
let mut compiled_allocator_module = None;
- let mut needs_link = Vec::new();
let mut needs_fat_lto = Vec::new();
let mut needs_thin_lto = Vec::new();
let mut lto_import_only_modules = Vec::new();
@@ -1423,7 +1405,7 @@ enum CodegenState {
let (item, _) =
work_items.pop().expect("queue empty - queue_full_enough() broken?");
main_thread_state = MainThreadState::Lending;
- spawn_work(&cgcx, &mut llvm_start_time, item);
+ spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item);
}
}
} else if codegen_state == Completed {
@@ -1502,7 +1484,7 @@ enum CodegenState {
MainThreadState::Idle => {
if let Some((item, _)) = work_items.pop() {
main_thread_state = MainThreadState::Lending;
- spawn_work(&cgcx, &mut llvm_start_time, item);
+ spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item);
} else {
// There is no unstarted work, so let the main thread
// take over for a running worker. Otherwise the
@@ -1538,7 +1520,7 @@ enum CodegenState {
while running_with_own_token < tokens.len()
&& let Some((item, _)) = work_items.pop()
{
- spawn_work(&cgcx, &mut llvm_start_time, item);
+ spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item);
running_with_own_token += 1;
}
}
@@ -1546,8 +1528,7 @@ enum CodegenState {
// Relinquish accidentally acquired extra tokens.
tokens.truncate(running_with_own_token);
- let msg = coordinator_receive.recv().unwrap();
- match *msg.downcast::<Message<B>>().ok().unwrap() {
+ match coordinator_receive.recv().unwrap() {
// Save the token locally and the next turn of the loop will use
// this to spawn a new unit of work, or it may get dropped
// immediately if we have no more work to spawn.
@@ -1630,7 +1611,6 @@ enum CodegenState {
Ok(WorkItemResult::Finished(compiled_module)) => {
match compiled_module.kind {
ModuleKind::Regular => {
- assert!(needs_link.is_empty());
compiled_modules.push(compiled_module);
}
ModuleKind::Allocator => {
@@ -1639,10 +1619,6 @@ enum CodegenState {
}
}
}
- Ok(WorkItemResult::NeedsLink(module)) => {
- assert!(compiled_modules.is_empty());
- needs_link.push(module);
- }
Ok(WorkItemResult::NeedsFatLto(fat_lto_input)) => {
assert!(!started_lto);
assert!(needs_thin_lto.is_empty());
@@ -1679,17 +1655,6 @@ enum CodegenState {
return Err(());
}
- let needs_link = mem::take(&mut needs_link);
- if !needs_link.is_empty() {
- assert!(compiled_modules.is_empty());
- let dcx = cgcx.create_dcx();
- let dcx = dcx.handle();
- let module = B::run_link(&cgcx, dcx, needs_link).map_err(|_| ())?;
- let module =
- B::codegen(&cgcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())?;
- compiled_modules.push(module);
- }
-
// Drop to print timings
drop(llvm_start_time);
@@ -1769,6 +1734,7 @@ fn queue_full_enough(items_in_queue: usize, workers_running: usize) -> bool {
fn spawn_work<'a, B: ExtraBackendMethods>(
cgcx: &'a CodegenContext<B>,
+ coordinator_send: Sender<Message<B>>,
llvm_start_time: &mut Option<VerboseTimingGuard<'a>>,
work: WorkItem<B>,
) {
@@ -1782,7 +1748,7 @@ fn spawn_work<'a, B: ExtraBackendMethods>(
// Set up a destructor which will fire off a message that we're done as
// we exit.
struct Bomb<B: ExtraBackendMethods> {
- coordinator_send: Sender<Box<dyn Any + Send>>,
+ coordinator_send: Sender<Message<B>>,
result: Option<Result<WorkItemResult<B>, FatalError>>,
}
impl<B: ExtraBackendMethods> Drop for Bomb<B> {
@@ -1794,11 +1760,11 @@ fn drop(&mut self) {
}
None => Message::WorkItem::<B> { result: Err(None) },
};
- drop(self.coordinator_send.send(Box::new(msg)));
+ drop(self.coordinator_send.send(msg));
}
}
- let mut bomb = Bomb::<B> { coordinator_send: cgcx.coordinator_send.clone(), result: None };
+ let mut bomb = Bomb::<B> { coordinator_send, result: None };
// Execute the work itself, and if it finishes successfully then flag
// ourselves as a success as well.
@@ -2003,7 +1969,7 @@ fn check(&self, sess: &Session, blocking: bool) {
}
pub struct Coordinator<B: ExtraBackendMethods> {
- pub sender: Sender<Box<dyn Any + Send>>,
+ sender: Sender<Message<B>>,
future: Option<thread::JoinHandle<Result<CompiledModules, ()>>>,
// Only used for the Message type.
phantom: PhantomData<B>,
@@ -2020,7 +1986,7 @@ fn drop(&mut self) {
if let Some(future) = self.future.take() {
// If we haven't joined yet, signal to the coordinator that it should spawn no more
// work, and wait for worker threads to finish.
- drop(self.sender.send(Box::new(Message::CodegenAborted::<B>)));
+ drop(self.sender.send(Message::CodegenAborted::<B>));
drop(future.join());
}
}
@@ -2079,7 +2045,7 @@ pub fn join(self, sess: &Session) -> (CodegenResults, FxIndexMap<WorkProductId,
pub(crate) fn codegen_finished(&self, tcx: TyCtxt<'_>) {
self.wait_for_signal_to_codegen_item();
self.check_for_errors(tcx.sess);
- drop(self.coordinator.sender.send(Box::new(Message::CodegenComplete::<B>)));
+ drop(self.coordinator.sender.send(Message::CodegenComplete::<B>));
}
pub(crate) fn check_for_errors(&self, sess: &Session) {
@@ -2100,28 +2066,25 @@ pub(crate) fn wait_for_signal_to_codegen_item(&self) {
}
pub(crate) fn submit_codegened_module_to_llvm<B: ExtraBackendMethods>(
- _backend: &B,
- tx_to_llvm_workers: &Sender<Box<dyn Any + Send>>,
+ coordinator: &Coordinator<B>,
module: ModuleCodegen<B::Module>,
cost: u64,
) {
let llvm_work_item = WorkItem::Optimize(module);
- drop(tx_to_llvm_workers.send(Box::new(Message::CodegenDone::<B> { llvm_work_item, cost })));
+ drop(coordinator.sender.send(Message::CodegenDone::<B> { llvm_work_item, cost }));
}
pub(crate) fn submit_post_lto_module_to_llvm<B: ExtraBackendMethods>(
- _backend: &B,
- tx_to_llvm_workers: &Sender<Box<dyn Any + Send>>,
+ coordinator: &Coordinator<B>,
module: CachedModuleCodegen,
) {
let llvm_work_item = WorkItem::CopyPostLtoArtifacts(module);
- drop(tx_to_llvm_workers.send(Box::new(Message::CodegenDone::<B> { llvm_work_item, cost: 0 })));
+ drop(coordinator.sender.send(Message::CodegenDone::<B> { llvm_work_item, cost: 0 }));
}
pub(crate) fn submit_pre_lto_module_to_llvm<B: ExtraBackendMethods>(
- _backend: &B,
tcx: TyCtxt<'_>,
- tx_to_llvm_workers: &Sender<Box<dyn Any + Send>>,
+ coordinator: &Coordinator<B>,
module: CachedModuleCodegen,
) {
let filename = pre_lto_bitcode_filename(&module.name);
@@ -2135,10 +2098,10 @@ pub(crate) fn submit_pre_lto_module_to_llvm<B: ExtraBackendMethods>(
})
};
// Schedule the module to be loaded
- drop(tx_to_llvm_workers.send(Box::new(Message::AddImportOnlyModule::<B> {
+ drop(coordinator.sender.send(Message::AddImportOnlyModule::<B> {
module_data: SerializedModule::FromUncompressedFile(mmap),
work_product: module.source,
- })));
+ }));
}
fn pre_lto_bitcode_filename(module_name: &str) -> String {
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 833456a..a5807c5 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -702,8 +702,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
// These modules are generally cheap and won't throw off scheduling.
let cost = 0;
submit_codegened_module_to_llvm(
- &backend,
- &ongoing_codegen.coordinator.sender,
+ &ongoing_codegen.coordinator,
ModuleCodegen::new_allocator(llmod_id, module_llvm),
cost,
);
@@ -800,18 +799,12 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
// compilation hang on post-monomorphization errors.
tcx.dcx().abort_if_errors();
- submit_codegened_module_to_llvm(
- &backend,
- &ongoing_codegen.coordinator.sender,
- module,
- cost,
- );
+ submit_codegened_module_to_llvm(&ongoing_codegen.coordinator, module, cost);
}
CguReuse::PreLto => {
submit_pre_lto_module_to_llvm(
- &backend,
tcx,
- &ongoing_codegen.coordinator.sender,
+ &ongoing_codegen.coordinator,
CachedModuleCodegen {
name: cgu.name().to_string(),
source: cgu.previous_work_product(tcx),
@@ -820,8 +813,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
}
CguReuse::PostLto => {
submit_post_lto_module_to_llvm(
- &backend,
- &ongoing_codegen.coordinator.sender,
+ &ongoing_codegen.coordinator,
CachedModuleCodegen {
name: cgu.name().to_string(),
source: cgu.previous_work_product(tcx),
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index dd49db2..e187331 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -496,30 +496,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
)
.with_note("Rustc requires this item to have a specific mangled name.")
.with_span_label(tcx.def_span(did), "should be the internal language item");
- if let Some(lang_item) = lang_item {
- if let Some(link_name) = lang_item.link_name() {
- err = err
- .with_note("If you are trying to prevent mangling to ease debugging, many")
- .with_note(format!(
- "debuggers support a command such as `rbreak {link_name}` to"
- ))
- .with_note(format!(
- "match `.*{link_name}.*` instead of `break {link_name}` on a specific name"
- ))
- }
+ if let Some(lang_item) = lang_item
+ && let Some(link_name) = lang_item.link_name()
+ {
+ err = err
+ .with_note("If you are trying to prevent mangling to ease debugging, many")
+ .with_note(format!("debuggers support a command such as `rbreak {link_name}` to"))
+ .with_note(format!(
+ "match `.*{link_name}.*` instead of `break {link_name}` on a specific name"
+ ))
}
err.emit();
}
- // Any linkage to LLVM intrinsics for now forcibly marks them all as never
- // unwinds since LLVM sometimes can't handle codegen which `invoke`s
- // intrinsic functions.
- if let Some(name) = &codegen_fn_attrs.link_name
- && name.as_str().starts_with("llvm.")
- {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
- }
-
if let Some(features) = check_tied_features(
tcx.sess,
&codegen_fn_attrs
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index 6d6465d..c2c023a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -1,12 +1,13 @@
//! An analysis to determine which locals require allocas and
//! which do not.
+use rustc_abi as abi;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_index::bit_set::DenseBitSet;
use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind, traversal};
-use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
+use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::{bug, span_bug};
use tracing::debug;
@@ -99,63 +100,75 @@ fn process_place(
context: PlaceContext,
location: Location,
) {
- let cx = self.fx.cx;
+ if !place_ref.projection.is_empty() {
+ const COPY_CONTEXT: PlaceContext =
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
- if let Some((place_base, elem)) = place_ref.last_projection() {
- let mut base_context = if context.is_mutating_use() {
- PlaceContext::MutatingUse(MutatingUseContext::Projection)
- } else {
- PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
- };
-
- // Allow uses of projections that are ZSTs or from scalar fields.
- let is_consume = matches!(
- context,
- PlaceContext::NonMutatingUse(
- NonMutatingUseContext::Copy | NonMutatingUseContext::Move,
- )
- );
- if is_consume {
- let base_ty = place_base.ty(self.fx.mir, cx.tcx());
- let base_ty = self.fx.monomorphize(base_ty);
-
- // ZSTs don't require any actual memory access.
- let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(elem)).ty;
- let span = self.fx.mir.local_decls[place_ref.local].source_info.span;
- if cx.spanned_layout_of(elem_ty, span).is_zst() {
- return;
+ // `PlaceElem::Index` is the only variant that can mention other `Local`s,
+ // so check for those up-front before any potential short-circuits.
+ for elem in place_ref.projection {
+ if let mir::PlaceElem::Index(index_local) = *elem {
+ self.visit_local(index_local, COPY_CONTEXT, location);
}
+ }
- if let mir::ProjectionElem::Field(..) = elem {
- let layout = cx.spanned_layout_of(base_ty.ty, span);
- if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
- // Recurse with the same context, instead of `Projection`,
- // potentially stopping at non-operand projections,
- // which would trigger `not_ssa` on locals.
- base_context = context;
+ // If our local is already memory, nothing can make it *more* memory
+ // so we don't need to bother checking the projections further.
+ if self.locals[place_ref.local] == LocalKind::Memory {
+ return;
+ }
+
+ if place_ref.is_indirect_first_projection() {
+ // If this starts with a `Deref`, we only need to record a read of the
+ // pointer being dereferenced, as all the subsequent projections are
+ // working on a place which is always supported. (And because we're
+ // looking at codegen MIR, it can only happen as the first projection.)
+ self.visit_local(place_ref.local, COPY_CONTEXT, location);
+ return;
+ }
+
+ if context.is_mutating_use() {
+ // If it's a mutating use it doesn't matter what the projections are,
+ // if there are *any* then we need a place to write. (For example,
+ // `_1 = Foo()` works in SSA but `_2.0 = Foo()` does not.)
+ let mut_projection = PlaceContext::MutatingUse(MutatingUseContext::Projection);
+ self.visit_local(place_ref.local, mut_projection, location);
+ return;
+ }
+
+ // Scan through to ensure the only projections are those which
+ // `FunctionCx::maybe_codegen_consume_direct` can handle.
+ let base_ty = self.fx.monomorphized_place_ty(mir::PlaceRef::from(place_ref.local));
+ let mut layout = self.fx.cx.layout_of(base_ty);
+ for elem in place_ref.projection {
+ layout = match *elem {
+ mir::PlaceElem::Field(fidx, ..) => layout.field(self.fx.cx, fidx.as_usize()),
+ mir::PlaceElem::Downcast(_, vidx)
+ if let abi::Variants::Single { index: single_variant } =
+ layout.variants
+ && vidx == single_variant =>
+ {
+ layout.for_variant(self.fx.cx, vidx)
+ }
+ mir::PlaceElem::Subtype(subtype_ty) => {
+ let subtype_ty = self.fx.monomorphize(subtype_ty);
+ self.fx.cx.layout_of(subtype_ty)
+ }
+ _ => {
+ self.locals[place_ref.local] = LocalKind::Memory;
+ return;
}
}
}
-
- if let mir::ProjectionElem::Deref = elem {
- // Deref projections typically only read the pointer.
- base_context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
- }
-
- self.process_place(&place_base, base_context, location);
- // HACK(eddyb) this emulates the old `visit_projection_elem`, this
- // entire `visit_place`-like `process_place` method should be rewritten,
- // now that we have moved to the "slice of projections" representation.
- if let mir::ProjectionElem::Index(local) = elem {
- self.visit_local(
- local,
- PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
- location,
- );
- }
- } else {
- self.visit_local(place_ref.local, context, location);
+ debug_assert!(
+ !self.fx.cx.is_backend_ref(layout),
+ "Post-projection {place_ref:?} layout should be non-Ref, but it's {layout:?}",
+ );
}
+
+ // Even with supported projections, we still need to have `visit_local`
+ // check for things that can't be done in SSA (like `SharedBorrow`).
+ self.visit_local(place_ref.local, context, location);
}
}
@@ -170,11 +183,6 @@ fn visit_assign(
if let Some(local) = place.as_local() {
self.define(local, DefLocation::Assignment(location));
- if self.locals[local] != LocalKind::Memory {
- if !self.fx.rvalue_creates_operand(rvalue) {
- self.locals[local] = LocalKind::Memory;
- }
- }
} else {
self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), location);
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 8e308aa..5459f95 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -335,13 +335,6 @@ pub(crate) fn extract_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
let val = if field.is_zst() {
OperandValue::ZeroSized
- } else if let BackendRepr::SimdVector { .. } = self.layout.backend_repr {
- // codegen_transmute_operand doesn't support SIMD, but since the previous
- // check handled ZSTs, the only possible field access into something SIMD
- // is to the `non_1zst_field` that's the same SIMD. (Other things, even
- // just padding, would change the wrapper's representation type.)
- assert_eq!(field.size, self.layout.size);
- self.val
} else if field.size == self.layout.size {
assert_eq!(offset.bytes(), 0);
fx.codegen_transmute_operand(bx, *self, field)
@@ -928,9 +921,10 @@ fn maybe_codegen_consume_direct(
match self.locals[place_ref.local] {
LocalRef::Operand(mut o) => {
- // Moves out of scalar and scalar pair fields are trivial.
- for elem in place_ref.projection.iter() {
- match elem {
+ // We only need to handle the projections that
+ // `LocalAnalyzer::process_place` let make it here.
+ for elem in place_ref.projection {
+ match *elem {
mir::ProjectionElem::Field(f, _) => {
assert!(
!o.layout.ty.is_any_ptr(),
@@ -939,17 +933,18 @@ fn maybe_codegen_consume_direct(
);
o = o.extract_field(self, bx, f.index());
}
- mir::ProjectionElem::Index(_)
- | mir::ProjectionElem::ConstantIndex { .. } => {
- // ZSTs don't require any actual memory access.
- // FIXME(eddyb) deduplicate this with the identical
- // checks in `codegen_consume` and `extract_field`.
- let elem = o.layout.field(bx.cx(), 0);
- if elem.is_zst() {
- o = OperandRef::zero_sized(elem);
- } else {
- return None;
- }
+ mir::PlaceElem::Downcast(_, vidx) => {
+ debug_assert_eq!(
+ o.layout.variants,
+ abi::Variants::Single { index: vidx },
+ );
+ let layout = o.layout.for_variant(bx.cx(), vidx);
+ o = OperandRef { val: o.val, layout }
+ }
+ mir::PlaceElem::Subtype(subtype_ty) => {
+ let subtype_ty = self.monomorphize(subtype_ty);
+ let layout = self.cx.layout_of(subtype_ty);
+ o = OperandRef { val: o.val, layout }
}
_ => return None,
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 610e2fd..8a67b8d 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -2,12 +2,12 @@
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
-use rustc_middle::{bug, mir};
+use rustc_middle::{bug, mir, span_bug};
use rustc_session::config::OptLevel;
use tracing::{debug, instrument};
use super::operand::{OperandRef, OperandRefBuilder, OperandValue};
-use super::place::{PlaceRef, codegen_tag_value};
+use super::place::{PlaceRef, PlaceValue, codegen_tag_value};
use super::{FunctionCx, LocalRef};
use crate::common::{IntPredicate, TypeKind};
use crate::traits::*;
@@ -180,7 +180,6 @@ pub(crate) fn codegen_rvalue(
}
_ => {
- assert!(self.rvalue_creates_operand(rvalue));
let temp = self.codegen_rvalue_operand(bx, rvalue);
temp.val.store(bx, dest);
}
@@ -218,17 +217,26 @@ fn codegen_transmute(
/// Transmutes an `OperandValue` to another `OperandValue`.
///
- /// This is supported only for cases where [`Self::rvalue_creates_operand`]
- /// returns `true`, and will ICE otherwise. (In particular, anything that
- /// would need to `alloca` in order to return a `PlaceValue` will ICE,
- /// expecting those to go via [`Self::codegen_transmute`] instead where
- /// the destination place is already allocated.)
+ /// This is supported for all cases where the `cast` type is SSA,
+ /// but for non-ZSTs with [`abi::BackendRepr::Memory`] it ICEs.
pub(crate) fn codegen_transmute_operand(
&mut self,
bx: &mut Bx,
operand: OperandRef<'tcx, Bx::Value>,
cast: TyAndLayout<'tcx>,
) -> OperandValue<Bx::Value> {
+ if let abi::BackendRepr::Memory { .. } = cast.backend_repr
+ && !cast.is_zst()
+ {
+ span_bug!(self.mir.span, "Use `codegen_transmute` to transmute to {cast:?}");
+ }
+
+ // `Layout` is interned, so we can do a cheap check for things that are
+ // exactly the same and thus don't need any handling.
+ if abi::Layout::eq(&operand.layout.layout, &cast.layout) {
+ return operand.val;
+ }
+
// Check for transmutes that are always UB.
if operand.layout.size != cast.size
|| operand.layout.is_uninhabited()
@@ -241,11 +249,22 @@ pub(crate) fn codegen_transmute_operand(
return OperandValue::poison(bx, cast);
}
+ // To or from pointers takes different methods, so we use this to restrict
+ // the SimdVector case to types which can be `bitcast` between each other.
+ #[inline]
+ fn vector_can_bitcast(x: abi::Scalar) -> bool {
+ matches!(
+ x,
+ abi::Scalar::Initialized {
+ value: abi::Primitive::Int(..) | abi::Primitive::Float(..),
+ ..
+ }
+ )
+ }
+
+ let cx = bx.cx();
match (operand.val, operand.layout.backend_repr, cast.backend_repr) {
_ if cast.is_zst() => OperandValue::ZeroSized,
- (_, _, abi::BackendRepr::Memory { .. }) => {
- bug!("Cannot `codegen_transmute_operand` to non-ZST memory-ABI output {cast:?}");
- }
(OperandValue::Ref(source_place_val), abi::BackendRepr::Memory { .. }, _) => {
assert_eq!(source_place_val.llextra, None);
// The existing alignment is part of `source_place_val`,
@@ -256,16 +275,46 @@ pub(crate) fn codegen_transmute_operand(
OperandValue::Immediate(imm),
abi::BackendRepr::Scalar(from_scalar),
abi::BackendRepr::Scalar(to_scalar),
- ) => OperandValue::Immediate(transmute_scalar(bx, imm, from_scalar, to_scalar)),
+ ) if from_scalar.size(cx) == to_scalar.size(cx) => {
+ OperandValue::Immediate(transmute_scalar(bx, imm, from_scalar, to_scalar))
+ }
+ (
+ OperandValue::Immediate(imm),
+ abi::BackendRepr::SimdVector { element: from_scalar, .. },
+ abi::BackendRepr::SimdVector { element: to_scalar, .. },
+ ) if vector_can_bitcast(from_scalar) && vector_can_bitcast(to_scalar) => {
+ let to_backend_ty = bx.cx().immediate_backend_type(cast);
+ OperandValue::Immediate(bx.bitcast(imm, to_backend_ty))
+ }
(
OperandValue::Pair(imm_a, imm_b),
abi::BackendRepr::ScalarPair(in_a, in_b),
abi::BackendRepr::ScalarPair(out_a, out_b),
- ) => OperandValue::Pair(
- transmute_scalar(bx, imm_a, in_a, out_a),
- transmute_scalar(bx, imm_b, in_b, out_b),
- ),
- _ => bug!("Cannot `codegen_transmute_operand` {operand:?} to {cast:?}"),
+ ) if in_a.size(cx) == out_a.size(cx) && in_b.size(cx) == out_b.size(cx) => {
+ OperandValue::Pair(
+ transmute_scalar(bx, imm_a, in_a, out_a),
+ transmute_scalar(bx, imm_b, in_b, out_b),
+ )
+ }
+ _ => {
+ // For any other potentially-tricky cases, make a temporary instead.
+ // If anything else wants the target local to be in memory this won't
+ // be hit, as `codegen_transmute` will get called directly. Thus this
+ // is only for places where everything else wants the operand form,
+ // and thus it's not worth making those places get it from memory.
+ //
+ // Notably, Scalar ⇌ ScalarPair cases go here to avoid padding
+ // and endianness issues, as do SimdVector ones to avoid worrying
+ // about things like f32x8 ⇌ ptrx4 that would need multiple steps.
+ let align = Ord::max(operand.layout.align.abi, cast.align.abi);
+ let size = Ord::max(operand.layout.size, cast.size);
+ let temp = PlaceValue::alloca(bx, size, align);
+ bx.lifetime_start(temp.llval, size);
+ operand.val.store(bx, temp.with_type(operand.layout));
+ let val = bx.load_operand(temp.with_type(cast)).val;
+ bx.lifetime_end(temp.llval, size);
+ val
+ }
}
}
@@ -288,7 +337,7 @@ fn cast_immediate(
// valid ranges. For example, `char`s are passed as just `i32`, with no
// way for LLVM to know that they're 0x10FFFF at most. Thus we assume
// the range of the input value too, not just the output range.
- assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
+ assume_scalar_range(bx, imm, from_scalar, from_backend_ty, None);
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
(Int(_, is_signed), Int(..)) => bx.intcast(imm, to_backend_ty, is_signed),
@@ -326,8 +375,6 @@ pub(crate) fn codegen_rvalue_operand(
bx: &mut Bx,
rvalue: &mir::Rvalue<'tcx>,
) -> OperandRef<'tcx, Bx::Value> {
- assert!(self.rvalue_creates_operand(rvalue), "cannot codegen {rvalue:?} to operand",);
-
match *rvalue {
mir::Rvalue::Cast(ref kind, ref source, mir_cast_ty) => {
let operand = self.codegen_operand(bx, source);
@@ -653,8 +700,6 @@ pub(crate) fn codegen_rvalue_operand(
let ty = self.monomorphize(ty);
let layout = self.cx.layout_of(ty);
- // `rvalue_creates_operand` has arranged that we only get here if
- // we can build the aggregate immediate from the field immediates.
let mut builder = OperandRefBuilder::new(layout);
for (field_idx, field) in fields.iter_enumerated() {
let op = self.codegen_operand(bx, field);
@@ -955,69 +1000,6 @@ fn codegen_scalar_checked_binop(
OperandValue::Pair(val, of)
}
-
- /// Returns `true` if the `rvalue` can be computed into an [`OperandRef`],
- /// rather than needing a full `PlaceRef` for the assignment destination.
- ///
- /// This is used by the [`super::analyze`] code to decide which MIR locals
- /// can stay as SSA values (as opposed to generating `alloca` slots for them).
- /// As such, some paths here return `true` even where the specific rvalue
- /// will not actually take the operand path because the result type is such
- /// that it always gets an `alloca`, but where it's not worth re-checking the
- /// layout in this code when the right thing will happen anyway.
- pub(crate) fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool {
- match *rvalue {
- mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, cast_ty) => {
- let operand_ty = operand.ty(self.mir, self.cx.tcx());
- let cast_layout = self.cx.layout_of(self.monomorphize(cast_ty));
- let operand_layout = self.cx.layout_of(self.monomorphize(operand_ty));
- match (operand_layout.backend_repr, cast_layout.backend_repr) {
- // When the output will be in memory anyway, just use its place
- // (instead of the operand path) unless it's the trivial ZST case.
- (_, abi::BackendRepr::Memory { .. }) => cast_layout.is_zst(),
-
- // Otherwise (for a non-memory output) if the input is memory
- // then we can just read the value from the place.
- (abi::BackendRepr::Memory { .. }, _) => true,
-
- // When we have scalar immediates, we can only convert things
- // where the sizes match, to avoid endianness questions.
- (abi::BackendRepr::Scalar(a), abi::BackendRepr::Scalar(b)) =>
- a.size(self.cx) == b.size(self.cx),
- (abi::BackendRepr::ScalarPair(a0, a1), abi::BackendRepr::ScalarPair(b0, b1)) =>
- a0.size(self.cx) == b0.size(self.cx) && a1.size(self.cx) == b1.size(self.cx),
-
- // Mixing Scalars and ScalarPairs can get quite complicated when
- // padding and undef get involved, so leave that to the memory path.
- (abi::BackendRepr::Scalar(_), abi::BackendRepr::ScalarPair(_, _)) |
- (abi::BackendRepr::ScalarPair(_, _), abi::BackendRepr::Scalar(_)) => false,
-
- // SIMD vectors aren't worth the trouble of dealing with complex
- // cases like from vectors of f32 to vectors of pointers or
- // from fat pointers to vectors of u16. (See #143194 #110021 ...)
- (abi::BackendRepr::SimdVector { .. }, _) | (_, abi::BackendRepr::SimdVector { .. }) => false,
- }
- }
- mir::Rvalue::Ref(..) |
- mir::Rvalue::CopyForDeref(..) |
- mir::Rvalue::RawPtr(..) |
- mir::Rvalue::Len(..) |
- mir::Rvalue::Cast(..) | // (*)
- mir::Rvalue::ShallowInitBox(..) | // (*)
- mir::Rvalue::BinaryOp(..) |
- mir::Rvalue::UnaryOp(..) |
- mir::Rvalue::Discriminant(..) |
- mir::Rvalue::NullaryOp(..) |
- mir::Rvalue::ThreadLocalRef(_) |
- mir::Rvalue::Use(..) |
- mir::Rvalue::Repeat(..) | // (*)
- mir::Rvalue::Aggregate(..) | // (*)
- mir::Rvalue::WrapUnsafeBinder(..) => // (*)
- true,
- }
-
- // (*) this is only true if the type is suitable
- }
}
/// Transmutes a single scalar value `imm` from `from_scalar` to `to_scalar`.
@@ -1064,7 +1046,7 @@ pub(super) fn transmute_scalar<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// That said, last time we tried removing this, it didn't actually help
// the rustc-perf results, so might as well keep doing it
// <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182>
- assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
+ assume_scalar_range(bx, imm, from_scalar, from_backend_ty, Some(&to_scalar));
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
@@ -1092,22 +1074,42 @@ pub(super) fn transmute_scalar<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// since it's never passed to something with parameter metadata (especially
// after MIR inlining) so the only way to tell the backend about the
// constraint that the `transmute` introduced is to `assume` it.
- assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
+ assume_scalar_range(bx, imm, to_scalar, to_backend_ty, Some(&from_scalar));
imm = bx.to_immediate_scalar(imm, to_scalar);
imm
}
+/// Emits an `assume` call that `imm`'s value is within the known range of `scalar`.
+///
+/// If `known` is `Some`, only emits the assume if it's more specific than
+/// whatever is already known from the range of *that* scalar.
fn assume_scalar_range<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
imm: Bx::Value,
scalar: abi::Scalar,
backend_ty: Bx::Type,
+ known: Option<&abi::Scalar>,
) {
- if matches!(bx.cx().sess().opts.optimize, OptLevel::No) || scalar.is_always_valid(bx.cx()) {
+ if matches!(bx.cx().sess().opts.optimize, OptLevel::No) {
return;
}
+ match (scalar, known) {
+ (abi::Scalar::Union { .. }, _) => return,
+ (_, None) => {
+ if scalar.is_always_valid(bx.cx()) {
+ return;
+ }
+ }
+ (abi::Scalar::Initialized { valid_range, .. }, Some(known)) => {
+ let known_range = known.valid_range(bx.cx());
+ if valid_range.contains_range(known_range, scalar.size(bx.cx())) {
+ return;
+ }
+ }
+ }
+
match scalar.primitive() {
abi::Primitive::Int(..) => {
let range = scalar.valid_range(bx.cx());
diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs
index 8e78cbe..f391c19 100644
--- a/compiler/rustc_codegen_ssa/src/traits/write.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/write.rs
@@ -16,12 +16,6 @@ pub trait WriteBackendMethods: Clone + 'static {
type ThinData: Send + Sync;
type ThinBuffer: ThinBufferMethods;
- /// Merge all modules into main_module and returning it
- fn run_link(
- cgcx: &CodegenContext<Self>,
- dcx: DiagCtxtHandle<'_>,
- modules: Vec<ModuleCodegen<Self::Module>>,
- ) -> Result<ModuleCodegen<Self::Module>, FatalError>;
/// Performs fat LTO by merging all modules into a single one, running autodiff
/// if necessary and running any further optimizations
fn run_and_optimize_fat_lto(
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index aa0bc42..2985eaf 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -128,15 +128,15 @@
const_eval_frame_note_last = the failure occurred here
+const_eval_incompatible_arg_types =
+ calling a function whose parameter #{$arg_idx} has type {$callee_ty} passing argument of type {$caller_ty}
+
const_eval_incompatible_calling_conventions =
calling a function with calling convention "{$callee_conv}" using calling convention "{$caller_conv}"
const_eval_incompatible_return_types =
calling a function with return type {$callee_ty} passing return place of type {$caller_ty}
-const_eval_incompatible_types =
- calling a function with argument of type {$callee_ty} passing data of type {$caller_ty}
-
const_eval_interior_mutable_borrow_escaping =
interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
.label = this borrow of an interior mutable value refers to such a temporary
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 0eb6f28..44e5d1d 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -714,10 +714,10 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
self.super_operand(op, location);
- if let Operand::Constant(c) = op {
- if let Some(def_id) = c.check_static_ptr(self.tcx) {
- self.check_static(def_id, self.span);
- }
+ if let Operand::Constant(c) = op
+ && let Some(def_id) = c.check_static_ptr(self.tcx)
+ {
+ self.check_static(def_id, self.span);
}
}
@@ -784,7 +784,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
self.revalidate_conditional_constness(callee, fn_args, *fn_span);
// Attempting to call a trait method?
- if let Some(trait_did) = tcx.trait_of_item(callee) {
+ if let Some(trait_did) = tcx.trait_of_assoc(callee) {
// We can't determine the actual callee here, so we have to do different checks
// than usual.
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index b2e0577..982e640 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -295,21 +295,18 @@ macro_rules! error {
}
let deref = "*".repeat(num_refs);
- if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) {
- if let Some(eq_idx) = call_str.find("==") {
- if let Some(rhs_idx) =
- call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
- {
- let rhs_pos =
- span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
- let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
- sugg = Some(errors::ConsiderDereferencing {
- deref,
- span: span.shrink_to_lo(),
- rhs_span,
- });
- }
- }
+ if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span)
+ && let Some(eq_idx) = call_str.find("==")
+ && let Some(rhs_idx) =
+ call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
+ {
+ let rhs_pos = span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
+ let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
+ sugg = Some(errors::ConsiderDereferencing {
+ deref,
+ span: span.shrink_to_lo(),
+ rhs_span,
+ });
}
}
_ => {}
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index 166491b..faf41f1 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -369,7 +369,7 @@ pub fn in_operand<'tcx, Q, F>(
assert!(promoted.is_none() || Q::ALLOW_PROMOTED);
// Don't peek inside trait associated constants.
- if promoted.is_none() && cx.tcx.trait_of_item(def).is_none() {
+ if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() {
let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def);
if !Q::in_qualifs(&qualifs) {
diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs
index 9f7fcc5..d98e502 100644
--- a/compiler/rustc_const_eval/src/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs
@@ -137,14 +137,14 @@ fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
// If a local with no projections is moved from (e.g. `x` in `y = x`), record that
// it no longer needs to be dropped.
- if let mir::Operand::Move(place) = operand {
- if let Some(local) = place.as_local() {
- // For backward compatibility with the MaybeMutBorrowedLocals used in an earlier
- // implementation we retain qualif if a local had been borrowed before. This might
- // not be strictly necessary since the local is no longer initialized.
- if !self.state.borrow.contains(local) {
- self.state.qualif.remove(local);
- }
+ if let mir::Operand::Move(place) = operand
+ && let Some(local) = place.as_local()
+ {
+ // For backward compatibility with the MaybeMutBorrowedLocals used in an earlier
+ // implementation we retain qualif if a local had been borrowed before. This might
+ // not be strictly necessary since the local is no longer initialized.
+ if !self.state.borrow.contains(local) {
+ self.state.qualif.remove(local);
}
}
}
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index b6a6403..a4148cb 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -500,7 +500,7 @@ fn diagnostic_message(&self) -> DiagMessage {
InvalidNichedEnumVariantWritten { .. } => {
const_eval_invalid_niched_enum_variant_written
}
- AbiMismatchArgument { .. } => const_eval_incompatible_types,
+ AbiMismatchArgument { .. } => const_eval_incompatible_arg_types,
AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
}
}
@@ -625,12 +625,16 @@ fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("data_size", info.data_size);
}
InvalidNichedEnumVariantWritten { enum_ty } => {
- diag.arg("ty", enum_ty.to_string());
+ diag.arg("ty", enum_ty);
}
- AbiMismatchArgument { caller_ty, callee_ty }
- | AbiMismatchReturn { caller_ty, callee_ty } => {
- diag.arg("caller_ty", caller_ty.to_string());
- diag.arg("callee_ty", callee_ty.to_string());
+ AbiMismatchArgument { arg_idx, caller_ty, callee_ty } => {
+ diag.arg("arg_idx", arg_idx + 1); // adjust for 1-indexed lists in output
+ diag.arg("caller_ty", caller_ty);
+ diag.arg("callee_ty", callee_ty);
+ }
+ AbiMismatchReturn { caller_ty, callee_ty } => {
+ diag.arg("caller_ty", caller_ty);
+ diag.arg("callee_ty", callee_ty);
}
}
}
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 1503f3b..5b3adba 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -270,6 +270,7 @@ fn pass_argument<'x, 'y>(
Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>),
>,
callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
+ callee_arg_idx: usize,
callee_arg: &mir::Place<'tcx>,
callee_ty: Ty<'tcx>,
already_live: bool,
@@ -298,6 +299,7 @@ fn pass_argument<'x, 'y>(
// Check compatibility
if !self.check_argument_compat(caller_abi, callee_abi)? {
throw_ub!(AbiMismatchArgument {
+ arg_idx: callee_arg_idx,
caller_ty: caller_abi.layout.ty,
callee_ty: callee_abi.layout.ty
});
@@ -424,7 +426,7 @@ pub fn init_stack_frame(
// this is a single iterator (that handles `spread_arg`), then
// `pass_argument` would be the loop body. It takes care to
// not advance `caller_iter` for ignored arguments.
- let mut callee_args_abis = callee_fn_abi.args.iter();
+ let mut callee_args_abis = callee_fn_abi.args.iter().enumerate();
for local in body.args_iter() {
// Construct the destination place for this argument. At this point all
// locals are still dead, so we cannot construct a `PlaceTy`.
@@ -445,10 +447,11 @@ pub fn init_stack_frame(
&[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)],
*self.tcx,
);
- let callee_abi = callee_args_abis.next().unwrap();
+ let (idx, callee_abi) = callee_args_abis.next().unwrap();
self.pass_argument(
&mut caller_args,
callee_abi,
+ idx,
&dest,
field_ty,
/* already_live */ true,
@@ -456,10 +459,11 @@ pub fn init_stack_frame(
}
} else {
// Normal argument. Cannot mark it as live yet, it might be unsized!
- let callee_abi = callee_args_abis.next().unwrap();
+ let (idx, callee_abi) = callee_args_abis.next().unwrap();
self.pass_argument(
&mut caller_args,
callee_abi,
+ idx,
&dest,
ty,
/* already_live */ false,
@@ -721,7 +725,7 @@ fn assert_virtual_instance_matches_concrete(
) {
let tcx = *self.tcx;
- let trait_def_id = tcx.trait_of_item(def_id).unwrap();
+ let trait_def_id = tcx.trait_of_assoc(def_id).unwrap();
let virtual_trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, virtual_instance.args);
let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 0c88869..0a8591c 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -442,10 +442,10 @@ pub(super) fn size_and_align_from_meta(
// # First compute the dynamic alignment
// Packed type alignment needs to be capped.
- if let ty::Adt(def, _) = layout.ty.kind() {
- if let Some(packed) = def.repr().pack {
- unsized_align = unsized_align.min(packed);
- }
+ if let ty::Adt(def, _) = layout.ty.kind()
+ && let Some(packed) = def.repr().pack
+ {
+ unsized_align = unsized_align.min(packed);
}
// Choose max of two known alignments (combined value must
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 693b378..ed48f53 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -320,10 +320,10 @@ fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize)
// for a coroutine).
let var_hir_id = captured_place.get_root_variable();
let node = self.ecx.tcx.hir_node(var_hir_id);
- if let hir::Node::Pat(pat) = node {
- if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
- name = Some(ident.name);
- }
+ if let hir::Node::Pat(pat) = node
+ && let hir::PatKind::Binding(_, _, ident, _) = pat.kind
+ {
+ name = Some(ident.name);
}
}
}
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 881aa67..4a9551a6 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -551,6 +551,11 @@ pub fn llvm_recording_enabled(&self) -> bool {
pub fn get_self_profiler(&self) -> Option<Arc<SelfProfiler>> {
self.profiler.clone()
}
+
+ /// Is expensive recording of query keys and/or function arguments enabled?
+ pub fn is_args_recording_enabled(&self) -> bool {
+ self.enabled() && self.event_filter_mask.intersects(EventFilter::ARGS)
+ }
}
/// A helper for recording costly arguments to self-profiling events. Used with
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 95400ac..46a4a18 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -713,8 +713,7 @@ fn draw_line(
Style::LineNumber,
);
}
- buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber);
-
+ self.draw_line_num(buffer, line_index, line_offset, width_offset - 3);
self.draw_col_separator_no_space(buffer, line_offset, width_offset - 2);
left
}
@@ -2128,11 +2127,11 @@ fn emit_suggestion_default(
// Account for a suggestion to completely remove a line(s) with whitespace (#94192).
let line_end = sm.lookup_char_pos(parts[0].span.hi()).line;
for line in line_start..=line_end {
- buffer.puts(
+ self.draw_line_num(
+ &mut buffer,
+ line,
row_num - 1 + line - line_start,
- 0,
- &self.maybe_anonymized(line),
- Style::LineNumber,
+ max_line_num_len,
);
buffer.puts(
row_num - 1 + line - line_start,
@@ -2612,12 +2611,7 @@ fn draw_code_line(
// For more info: https://github.com/rust-lang/rust/issues/92741
let lines_to_remove = file_lines.lines.iter().take(file_lines.lines.len() - 1);
for (index, line_to_remove) in lines_to_remove.enumerate() {
- buffer.puts(
- *row_num - 1,
- 0,
- &self.maybe_anonymized(line_num + index),
- Style::LineNumber,
- );
+ self.draw_line_num(buffer, line_num + index, *row_num - 1, max_line_num_len);
buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
let line = normalize_whitespace(
&file_lines.file.get_line(line_to_remove.line_index).unwrap(),
@@ -2634,11 +2628,11 @@ fn draw_code_line(
let last_line_index = file_lines.lines[file_lines.lines.len() - 1].line_index;
let last_line = &file_lines.file.get_line(last_line_index).unwrap();
if last_line != line_to_add {
- buffer.puts(
+ self.draw_line_num(
+ buffer,
+ line_num + file_lines.lines.len() - 1,
*row_num - 1,
- 0,
- &self.maybe_anonymized(line_num + file_lines.lines.len() - 1),
- Style::LineNumber,
+ max_line_num_len,
);
buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
buffer.puts(
@@ -2661,7 +2655,7 @@ fn draw_code_line(
// 2 - .await
// |
// *row_num -= 1;
- buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
+ self.draw_line_num(buffer, line_num, *row_num, max_line_num_len);
buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
} else {
@@ -2671,7 +2665,7 @@ fn draw_code_line(
*row_num -= 2;
}
} else if is_multiline {
- buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
+ self.draw_line_num(buffer, line_num, *row_num, max_line_num_len);
match &highlight_parts {
[SubstitutionHighlight { start: 0, end }] if *end == line_to_add.len() => {
buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
@@ -2702,11 +2696,11 @@ fn draw_code_line(
Style::NoStyle,
);
} else if let DisplaySuggestion::Add = show_code_change {
- buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
+ self.draw_line_num(buffer, line_num, *row_num, max_line_num_len);
buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
} else {
- buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
+ self.draw_line_num(buffer, line_num, *row_num, max_line_num_len);
self.draw_col_separator(buffer, *row_num, max_line_num_len + 1);
buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
}
@@ -3016,6 +3010,22 @@ fn margin(&self) -> &'static str {
OutputTheme::Unicode => "…",
}
}
+
+ fn draw_line_num(
+ &self,
+ buffer: &mut StyledBuffer,
+ line_num: usize,
+ line_offset: usize,
+ max_line_num_len: usize,
+ ) {
+ let line_num = self.maybe_anonymized(line_num);
+ buffer.puts(
+ line_offset,
+ max_line_num_len.saturating_sub(str_width(&line_num)),
+ &line_num,
+ Style::LineNumber,
+ );
+ }
}
#[derive(Debug, Clone, Copy)]
diff --git a/compiler/rustc_errors/src/markdown/term.rs b/compiler/rustc_errors/src/markdown/term.rs
index 579e00b..fe1d80b 100644
--- a/compiler/rustc_errors/src/markdown/term.rs
+++ b/compiler/rustc_errors/src/markdown/term.rs
@@ -18,7 +18,7 @@
pub(crate) fn entrypoint(stream: &MdStream<'_>, buf: &mut Buffer) -> io::Result<()> {
#[cfg(not(test))]
if let Some((w, _)) = termize::dimensions() {
- WIDTH.with(|c| c.set(std::cmp::min(w, DEFAULT_COLUMN_WIDTH)));
+ WIDTH.set(std::cmp::min(w, DEFAULT_COLUMN_WIDTH));
}
write_stream(stream, buf, None, 0)?;
buf.write_all(b"\n")
@@ -84,7 +84,7 @@ fn write_tt(tt: &MdTree<'_>, buf: &mut Buffer, indent: usize) -> io::Result<()>
reset_cursor();
}
MdTree::HorizontalRule => {
- (0..WIDTH.with(Cell::get)).for_each(|_| buf.write_all(b"-").unwrap());
+ (0..WIDTH.get()).for_each(|_| buf.write_all(b"-").unwrap());
reset_cursor();
}
MdTree::Heading(n, stream) => {
@@ -121,7 +121,7 @@ fn write_tt(tt: &MdTree<'_>, buf: &mut Buffer, indent: usize) -> io::Result<()>
/// End of that block, just wrap the line
fn reset_cursor() {
- CURSOR.with(|cur| cur.set(0));
+ CURSOR.set(0);
}
/// Change to be generic on Write for testing. If we have a link URL, we don't
@@ -144,7 +144,7 @@ fn write_wrapping<B: io::Write>(
buf.write_all(ind_ws)?;
cur.set(indent);
}
- let ch_count = WIDTH.with(Cell::get) - cur.get();
+ let ch_count = WIDTH.get() - cur.get();
let mut iter = to_write.char_indices();
let Some((end_idx, _ch)) = iter.nth(ch_count) else {
// Write entire line
diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs
index 790efd0..095502e 100644
--- a/compiler/rustc_errors/src/styled_buffer.rs
+++ b/compiler/rustc_errors/src/styled_buffer.rs
@@ -153,12 +153,11 @@ pub(crate) fn set_style_range(
/// 1. That line and column exist in `StyledBuffer`
/// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
- if let Some(ref mut line) = self.lines.get_mut(line) {
- if let Some(StyledChar { style: s, .. }) = line.get_mut(col) {
- if overwrite || matches!(s, Style::NoStyle | Style::Quotation) {
- *s = style;
- }
- }
+ if let Some(ref mut line) = self.lines.get_mut(line)
+ && let Some(StyledChar { style: s, .. }) = line.get_mut(col)
+ && (overwrite || matches!(s, Style::NoStyle | Style::Quotation))
+ {
+ *s = style;
}
}
}
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 89d6e62..5a53670 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -1,26 +1,8 @@
-expand_arg_not_attributes =
- second argument must be `attributes`
-
-expand_attr_no_arguments =
- attribute must have either one or two arguments
-
-expand_attribute_meta_item =
- attribute must be a meta item, not a literal
-
-expand_attribute_single_word =
- attribute must only be a single word
-
expand_attributes_on_expressions_experimental =
attributes on expressions are experimental
.help_outer_doc = `///` is used for outer documentation comments; for a plain comment, use `//`
.help_inner_doc = `//!` is used for inner documentation comments; for a plain comment, use `//` by removing the `!` or inserting a space in between them: `// !`
-expand_attributes_wrong_form =
- attribute must be of form: `attributes(foo, bar)`
-
-expand_cannot_be_name_of_macro =
- `{$trait_ident}` cannot be a name of {$macro_type} macro
-
expand_collapse_debuginfo_illegal =
illegal value for attribute #[collapse_debuginfo(no|external|yes)]
@@ -71,9 +53,6 @@
expand_glob_delegation_traitless_qpath =
qualified path without a trait in glob delegation
-expand_helper_attribute_name_invalid =
- `{$name}` cannot be a name of derive helper attribute
-
expand_incomplete_parse =
macro expansion ignores {$descr} and any tokens following
.label = caused by the macro expansion here
@@ -165,12 +144,6 @@
expand_non_inline_modules_in_proc_macro_input_are_unstable =
non-inline modules in proc macro input are unstable
-expand_not_a_meta_item =
- not a meta item
-
-expand_only_one_word =
- must only be one word
-
expand_proc_macro_back_compat = using an old version of `{$crate_name}`
.note = older versions of the `{$crate_name}` crate no longer compile; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 25ec540..c01320f 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -861,7 +861,7 @@ fn collapse_debuginfo_by_name(
/// | (unspecified) | no | if-ext | if-ext | yes |
/// | external | no | if-ext | if-ext | yes |
/// | yes | yes | yes | yes | yes |
- fn get_collapse_debuginfo(sess: &Session, attrs: &[impl AttributeExt], ext: bool) -> bool {
+ fn get_collapse_debuginfo(sess: &Session, attrs: &[hir::Attribute], ext: bool) -> bool {
let flag = sess.opts.cg.collapse_macro_debuginfo;
let attr = ast::attr::find_by_name(attrs, sym::collapse_debuginfo)
.and_then(|attr| {
@@ -872,7 +872,7 @@ fn get_collapse_debuginfo(sess: &Session, attrs: &[impl AttributeExt], ext: bool
.ok()
})
.unwrap_or_else(|| {
- if ast::attr::contains_name(attrs, sym::rustc_builtin_macro) {
+ if find_attr!(attrs, AttributeKind::RustcBuiltinMacro { .. }) {
CollapseMacroDebuginfo::Yes
} else {
CollapseMacroDebuginfo::Unspecified
@@ -915,16 +915,18 @@ pub fn new(
let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, !is_local);
tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
- let (builtin_name, helper_attrs) = ast::attr::find_by_name(attrs, sym::rustc_builtin_macro)
- .map(|attr| {
- // Override `helper_attrs` passed above if it's a built-in macro,
- // marking `proc_macro_derive` macros as built-in is not a realistic use case.
- parse_macro_name_and_helper_attrs(sess.dcx(), attr, "built-in").map_or_else(
- || (Some(name), Vec::new()),
- |(name, helper_attrs)| (Some(name), helper_attrs),
- )
- })
- .unwrap_or_else(|| (None, helper_attrs));
+ let (builtin_name, helper_attrs) = match find_attr!(attrs, AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, .. } => (builtin_name, helper_attrs))
+ {
+ // Override `helper_attrs` passed above if it's a built-in macro,
+ // marking `proc_macro_derive` macros as built-in is not a realistic use case.
+ Some((Some(name), helper_attrs)) => {
+ (Some(*name), helper_attrs.iter().copied().collect())
+ }
+ Some((None, _)) => (Some(name), Vec::new()),
+
+ // Not a built-in macro
+ None => (None, helper_attrs),
+ };
let stability = find_attr!(attrs, AttributeKind::Stability { stability, .. } => *stability);
@@ -1141,7 +1143,7 @@ fn append_stripped_cfg_item(
/// Names of specific methods to which glob delegation expands.
fn glob_delegation_suffixes(
- &mut self,
+ &self,
trait_def_id: DefId,
impl_def_id: LocalDefId,
) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate>;
@@ -1224,6 +1226,7 @@ pub struct ExtCtxt<'a> {
pub(super) expanded_inert_attrs: MarkedAttrs,
/// `-Zmacro-stats` data.
pub macro_stats: FxHashMap<(Symbol, MacroKind), MacroStat>,
+ pub nb_macro_errors: usize,
}
impl<'a> ExtCtxt<'a> {
@@ -1254,6 +1257,7 @@ pub fn new(
expanded_inert_attrs: MarkedAttrs::new(),
buffered_early_lint: vec![],
macro_stats: Default::default(),
+ nb_macro_errors: 0,
}
}
@@ -1315,6 +1319,12 @@ pub fn expansion_cause(&self) -> Option<Span> {
self.current_expansion.id.expansion_cause()
}
+ /// This method increases the internal macro errors count and then call `trace_macros_diag`.
+ pub fn macro_error_and_trace_macros_diag(&mut self) {
+ self.nb_macro_errors += 1;
+ self.trace_macros_diag();
+ }
+
pub fn trace_macros_diag(&mut self) {
for (span, notes) in self.expansions.iter() {
let mut db = self.dcx().create_note(errors::TraceMacro { span: *span });
@@ -1382,80 +1392,6 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe
}
}
-pub fn parse_macro_name_and_helper_attrs(
- dcx: DiagCtxtHandle<'_>,
- attr: &impl AttributeExt,
- macro_type: &str,
-) -> Option<(Symbol, Vec<Symbol>)> {
- // Once we've located the `#[proc_macro_derive]` attribute, verify
- // that it's of the form `#[proc_macro_derive(Foo)]` or
- // `#[proc_macro_derive(Foo, attributes(A, ..))]`
- let list = attr.meta_item_list()?;
- let ([trait_attr] | [trait_attr, _]) = list.as_slice() else {
- dcx.emit_err(errors::AttrNoArguments { span: attr.span() });
- return None;
- };
- let Some(trait_attr) = trait_attr.meta_item() else {
- dcx.emit_err(errors::NotAMetaItem { span: trait_attr.span() });
- return None;
- };
- let trait_ident = match trait_attr.ident() {
- Some(trait_ident) if trait_attr.is_word() => trait_ident,
- _ => {
- dcx.emit_err(errors::OnlyOneWord { span: trait_attr.span });
- return None;
- }
- };
-
- if !trait_ident.name.can_be_raw() {
- dcx.emit_err(errors::CannotBeNameOfMacro {
- span: trait_attr.span,
- trait_ident,
- macro_type,
- });
- }
-
- let attributes_attr = list.get(1);
- let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
- if !attr.has_name(sym::attributes) {
- dcx.emit_err(errors::ArgumentNotAttributes { span: attr.span() });
- }
- attr.meta_item_list()
- .unwrap_or_else(|| {
- dcx.emit_err(errors::AttributesWrongForm { span: attr.span() });
- &[]
- })
- .iter()
- .filter_map(|attr| {
- let Some(attr) = attr.meta_item() else {
- dcx.emit_err(errors::AttributeMetaItem { span: attr.span() });
- return None;
- };
-
- let ident = match attr.ident() {
- Some(ident) if attr.is_word() => ident,
- _ => {
- dcx.emit_err(errors::AttributeSingleWord { span: attr.span });
- return None;
- }
- };
- if !ident.name.can_be_raw() {
- dcx.emit_err(errors::HelperAttributeNameInvalid {
- span: attr.span,
- name: ident,
- });
- }
-
- Some(ident.name)
- })
- .collect()
- } else {
- Vec::new()
- };
-
- Some((trait_ident.name, proc_attrs))
-}
-
/// If this item looks like a specific enums from `rental`, emit a fatal error.
/// See #73345 and #83125 for more details.
/// FIXME(#73933): Remove this eventually.
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 3ac5d21..fd1391a 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -79,72 +79,6 @@ pub(crate) struct MacroBodyStability {
}
#[derive(Diagnostic)]
-#[diag(expand_attr_no_arguments)]
-pub(crate) struct AttrNoArguments {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_not_a_meta_item)]
-pub(crate) struct NotAMetaItem {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_only_one_word)]
-pub(crate) struct OnlyOneWord {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_cannot_be_name_of_macro)]
-pub(crate) struct CannotBeNameOfMacro<'a> {
- #[primary_span]
- pub span: Span,
- pub trait_ident: Ident,
- pub macro_type: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_arg_not_attributes)]
-pub(crate) struct ArgumentNotAttributes {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_attributes_wrong_form)]
-pub(crate) struct AttributesWrongForm {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_attribute_meta_item)]
-pub(crate) struct AttributeMetaItem {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_attribute_single_word)]
-pub(crate) struct AttributeSingleWord {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_helper_attribute_name_invalid)]
-pub(crate) struct HelperAttributeNameInvalid {
- #[primary_span]
- pub span: Span,
- pub name: Ident,
-}
-
-#[derive(Diagnostic)]
#[diag(expand_feature_removed, code = E0557)]
#[note]
pub(crate) struct FeatureRemoved<'a> {
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 79ec79a..0517fd0 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -693,7 +693,7 @@ fn error_recursion_limit_reached(&mut self) -> ErrorGuaranteed {
crate_name: self.cx.ecfg.crate_name,
});
- self.cx.trace_macros_diag();
+ self.cx.macro_error_and_trace_macros_diag();
guar
}
@@ -707,7 +707,7 @@ fn error_wrong_fragment_kind(
) -> ErrorGuaranteed {
let guar =
self.cx.dcx().emit_err(WrongFragmentKind { span, kind: kind.name(), name: &mac.path });
- self.cx.trace_macros_diag();
+ self.cx.macro_error_and_trace_macros_diag();
guar
}
@@ -1048,7 +1048,7 @@ fn parse_ast_fragment(
}
annotate_err_with_kind(&mut err, kind, span);
let guar = err.emit();
- self.cx.trace_macros_diag();
+ self.cx.macro_error_and_trace_macros_diag();
kind.dummy(span, guar)
}
}
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 3f1fc84..0324057 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -299,6 +299,7 @@ enum EofMatcherPositions {
}
/// Represents the possible results of an attempted parse.
+#[derive(Debug)]
pub(crate) enum ParseResult<T, F> {
/// Parsed successfully.
Success(T),
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 2f713a0..febe6f8 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -280,7 +280,7 @@ fn expand_macro<'cx>(
// Retry and emit a better error.
let (span, guar) =
diagnostics::failed_to_match_macro(cx.psess(), sp, def_span, name, arg, rules);
- cx.trace_macros_diag();
+ cx.macro_error_and_trace_macros_diag();
DummyResult::any(span, guar)
}
}
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index ca57c4f..3fee9af 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -295,6 +295,10 @@ pub fn def_path_data(self, name: Option<Symbol>) -> DefPathData {
}
}
+ pub fn is_assoc(self) -> bool {
+ matches!(self, DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy)
+ }
+
/// This is a "module" in name resolution sense.
#[inline]
pub fn is_module_like(self) -> bool {
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index e83f6a1..4ccc2e5 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -148,6 +148,11 @@ fn from(ident: Ident) -> Self {
/// `LifetimeSource::OutlivesBound` or `LifetimeSource::PreciseCapturing`
/// — there's no way to "elide" these lifetimes.
#[derive(Debug, Copy, Clone, HashStable_Generic)]
+// Raise the aligement to at least 4 bytes - this is relied on in other parts of the compiler(for pointer tagging):
+// https://github.com/rust-lang/rust/blob/ce5fdd7d42aba9a2925692e11af2bd39cf37798a/compiler/rustc_data_structures/src/tagged_ptr.rs#L163
+// Removing this `repr(4)` will cause the compiler to not build on platforms like `m68k` Linux, where the aligement of u32 and usize is only 2.
+// Since `repr(align)` may only raise aligement, this has no effect on platforms where the aligement is already sufficient.
+#[repr(align(4))]
pub struct Lifetime {
#[stable_hasher(ignore)]
pub hir_id: HirId,
@@ -1363,6 +1368,17 @@ fn doc_resolution_scope(&self) -> Option<AttrStyle> {
_ => None,
}
}
+
+ fn is_proc_macro_attr(&self) -> bool {
+ matches!(
+ self,
+ Attribute::Parsed(
+ AttributeKind::ProcMacro(..)
+ | AttributeKind::ProcMacroAttribute(..)
+ | AttributeKind::ProcMacroDerive { .. }
+ )
+ )
+ }
}
// FIXME(fn_delegation): use function delegation instead of manually forwarding
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 03c026c..6e63ce3 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -767,7 +767,10 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
DefKind::Static { .. } => {
check_static_inhabited(tcx, def_id);
check_static_linkage(tcx, def_id);
- res = res.and(wfcheck::check_static_item(tcx, def_id));
+ let ty = tcx.type_of(def_id).instantiate_identity();
+ res = res.and(wfcheck::check_static_item(
+ tcx, def_id, ty, /* should_check_for_sync */ true,
+ ));
}
DefKind::Const => res = res.and(wfcheck::check_const_item(tcx, def_id)),
_ => unreachable!(),
@@ -1642,20 +1645,40 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
if def.repr().int.is_none() {
let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind(), Some(CtorKind::Const));
- let has_disr = |var: &ty::VariantDef| matches!(var.discr, ty::VariantDiscr::Explicit(_));
+ let get_disr = |var: &ty::VariantDef| match var.discr {
+ ty::VariantDiscr::Explicit(disr) => Some(disr),
+ ty::VariantDiscr::Relative(_) => None,
+ };
- let has_non_units = def.variants().iter().any(|var| !is_unit(var));
- let disr_units = def.variants().iter().any(|var| is_unit(var) && has_disr(var));
- let disr_non_unit = def.variants().iter().any(|var| !is_unit(var) && has_disr(var));
+ let non_unit = def.variants().iter().find(|var| !is_unit(var));
+ let disr_unit =
+ def.variants().iter().filter(|var| is_unit(var)).find_map(|var| get_disr(var));
+ let disr_non_unit =
+ def.variants().iter().filter(|var| !is_unit(var)).find_map(|var| get_disr(var));
- if disr_non_unit || (disr_units && has_non_units) {
- struct_span_code_err!(
+ if disr_non_unit.is_some() || (disr_unit.is_some() && non_unit.is_some()) {
+ let mut err = struct_span_code_err!(
tcx.dcx(),
tcx.def_span(def_id),
E0732,
- "`#[repr(inttype)]` must be specified"
- )
- .emit();
+ "`#[repr(inttype)]` must be specified for enums with explicit discriminants and non-unit variants"
+ );
+ if let Some(disr_non_unit) = disr_non_unit {
+ err.span_label(
+ tcx.def_span(disr_non_unit),
+ "explicit discriminant on non-unit variant specified here",
+ );
+ } else {
+ err.span_label(
+ tcx.def_span(disr_unit.unwrap()),
+ "explicit discriminant specified here",
+ );
+ err.span_label(
+ tcx.def_span(non_unit.unwrap().def_id),
+ "non-unit discriminant declared here",
+ );
+ }
+ err.emit();
}
}
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 14ec82e..a62efed 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1180,12 +1180,13 @@ fn check_item_fn(
}
#[instrument(level = "debug", skip(tcx))]
-pub(super) fn check_static_item(
- tcx: TyCtxt<'_>,
+pub(crate) fn check_static_item<'tcx>(
+ tcx: TyCtxt<'tcx>,
item_id: LocalDefId,
+ ty: Ty<'tcx>,
+ should_check_for_sync: bool,
) -> Result<(), ErrorGuaranteed> {
enter_wf_checking_ctxt(tcx, item_id, |wfcx| {
- let ty = tcx.type_of(item_id).instantiate_identity();
let span = tcx.ty_span(item_id);
let item_ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
@@ -1212,9 +1213,9 @@ pub(super) fn check_static_item(
}
// Ensure that the end result is `Sync` in a non-thread local `static`.
- let should_check_for_sync = tcx.static_mutability(item_id.to_def_id())
- == Some(hir::Mutability::Not)
+ let should_check_for_sync = should_check_for_sync
&& !is_foreign_item
+ && tcx.static_mutability(item_id.to_def_id()) == Some(hir::Mutability::Not)
&& !tcx.is_thread_local_static(item_id.to_def_id());
if should_check_for_sync {
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 0728b24..afe79be 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -530,13 +530,12 @@ fn lower_fn_sig(
.iter()
.enumerate()
.map(|(i, a)| {
- if let hir::TyKind::Infer(()) = a.kind {
- if let Some(suggested_ty) =
+ if let hir::TyKind::Infer(()) = a.kind
+ && let Some(suggested_ty) =
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
- {
- infer_replacements.push((a.span, suggested_ty.to_string()));
- return Ty::new_error_with_message(tcx, a.span, suggested_ty.to_string());
- }
+ {
+ infer_replacements.push((a.span, suggested_ty.to_string()));
+ return Ty::new_error_with_message(tcx, a.span, suggested_ty.to_string());
}
self.lowerer().lower_ty(a)
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 902a2e1..22fb027 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -14,6 +14,7 @@
use rustc_span::{DUMMY_SP, Ident, Span};
use super::{HirPlaceholderCollector, ItemCtxt, bad_placeholder};
+use crate::check::wfcheck::check_static_item;
use crate::errors::TypeofReservedKeywordUsed;
use crate::hir_ty_lowering::HirTyLowerer;
@@ -217,7 +218,15 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
"static variable",
)
} else {
- icx.lower_ty(ty)
+ let ty = icx.lower_ty(ty);
+ // MIR relies on references to statics being scalars.
+ // Verify that here to avoid ill-formed MIR.
+ // We skip the `Sync` check to avoid cycles for type-alias-impl-trait,
+ // relying on the fact that non-Sync statics don't ICE the rest of the compiler.
+ match check_static_item(tcx, def_id, ty, /* should_check_for_sync */ false) {
+ Ok(()) => ty,
+ Err(guar) => Ty::new_error(tcx, guar),
+ }
}
}
ItemKind::Const(ident, _, ty, body_id) => {
@@ -275,7 +284,17 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
}
- ForeignItemKind::Static(t, _, _) => icx.lower_ty(t),
+ ForeignItemKind::Static(ty, _, _) => {
+ let ty = icx.lower_ty(ty);
+ // MIR relies on references to statics being scalars.
+ // Verify that here to avoid ill-formed MIR.
+ // We skip the `Sync` check to avoid cycles for type-alias-impl-trait,
+ // relying on the fact that non-Sync statics don't ICE the rest of the compiler.
+ match check_static_item(tcx, def_id, ty, /* should_check_for_sync */ false) {
+ Ok(()) => ty,
+ Err(guar) => Ty::new_error(tcx, guar),
+ }
+ }
ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()),
},
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 2d60c95..835f8e8 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
@@ -759,7 +759,7 @@ fn suggest_moving_args_from_assoc_fn_to_trait(
&self,
err: &mut Diag<'_, impl EmissionGuarantee>,
) {
- let trait_ = match self.tcx.trait_of_item(self.def_id) {
+ let trait_ = match self.tcx.trait_of_assoc(self.def_id) {
Some(def_id) => def_id,
None => return,
};
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 d7a827c..7760642 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -617,18 +617,14 @@ pub(super) fn lower_assoc_item_constraint(
});
// Provide the resolved type of the associated constant to `type_of(AnonConst)`.
- if let Some(const_arg) = constraint.ct() {
- if let hir::ConstArgKind::Anon(anon_const) = const_arg.kind {
- let ty = alias_term
- .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args));
- let ty = check_assoc_const_binding_type(
- self,
- constraint.ident,
- ty,
- constraint.hir_id,
- );
- tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty));
- }
+ if let Some(const_arg) = constraint.ct()
+ && let hir::ConstArgKind::Anon(anon_const) = const_arg.kind
+ {
+ let ty = alias_term
+ .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args));
+ let ty =
+ check_assoc_const_binding_type(self, constraint.ident, ty, constraint.hir_id);
+ tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty));
}
alias_term
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 287a553..f73442f 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -755,7 +755,7 @@ fn note_ambiguous_inherent_assoc_item(
let limit = if candidates.len() == 5 { 5 } else { 4 };
for (index, &item) in candidates.iter().take(limit).enumerate() {
- let impl_ = tcx.impl_of_method(item).unwrap();
+ let impl_ = tcx.impl_of_assoc(item).unwrap();
let note_span = if item.is_local() {
Some(tcx.def_span(item))
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 9abae33..646ff3c 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -447,17 +447,30 @@ fn maybe_suggest_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -
fn maybe_suggest_assoc_ty_bound(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) {
let mut parents = self.tcx().hir_parent_iter(self_ty.hir_id);
- if let Some((_, hir::Node::AssocItemConstraint(constraint))) = parents.next()
+ if let Some((c_hir_id, hir::Node::AssocItemConstraint(constraint))) = parents.next()
&& let Some(obj_ty) = constraint.ty()
+ && let Some((_, hir::Node::TraitRef(trait_ref))) = parents.next()
{
- if let Some((_, hir::Node::TraitRef(..))) = parents.next()
- && let Some((_, hir::Node::Ty(ty))) = parents.next()
+ if let Some((_, hir::Node::Ty(ty))) = parents.next()
&& let hir::TyKind::TraitObject(..) = ty.kind
{
// Assoc ty bounds aren't permitted inside trait object types.
return;
}
+ if trait_ref
+ .path
+ .segments
+ .iter()
+ .find_map(|seg| {
+ seg.args.filter(|args| args.constraints.iter().any(|c| c.hir_id == c_hir_id))
+ })
+ .is_none_or(|args| args.parenthesized != hir::GenericArgsParentheses::No)
+ {
+ // Only consider angle-bracketed args (where we have a `=` to replace with `:`).
+ return;
+ }
+
let lo = if constraint.gen_args.span_ext.is_dummy() {
constraint.ident.span
} else {
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index bf539df..3fddaee 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -103,16 +103,15 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
// over less-specific types (e.g. `Option<MyStruct<u8>>`)
if self.depth >= self.cause_depth {
self.cause = Some(error.obligation.cause);
- if let hir::TyKind::TraitObject(..) = ty.kind {
- if let DefKind::AssocTy | DefKind::AssocConst | DefKind::AssocFn =
+ if let hir::TyKind::TraitObject(..) = ty.kind
+ && let DefKind::AssocTy | DefKind::AssocConst | DefKind::AssocFn =
self.tcx.def_kind(self.def_id)
- {
- self.cause = Some(ObligationCause::new(
- ty.span,
- self.def_id,
- ObligationCauseCode::DynCompatible(ty.span),
- ));
- }
+ {
+ self.cause = Some(ObligationCause::new(
+ ty.span,
+ self.def_id,
+ ObligationCauseCode::DynCompatible(ty.span),
+ ));
}
self.cause_depth = self.depth
}
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 759b5d9..9406697 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -694,7 +694,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result {
// i.e. changing `Default::default()` to `<() as Default>::default()`.
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let Res::Def(DefKind::AssocFn, def_id) = path.res
- && self.fcx.tcx.trait_of_item(def_id).is_some()
+ && self.fcx.tcx.trait_of_assoc(def_id).is_some()
&& let Some(args) = self.fcx.typeck_results.borrow().node_args_opt(expr.hir_id)
&& let self_ty = args.type_at(0)
&& let Some(vid) = self.fcx.root_vid(self_ty)
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index eb8d671c..719989d 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -2136,10 +2136,10 @@ fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span {
)
};
- if let hir::ExprKind::If(_, _, Some(el)) = expr.kind {
- if let Some(rslt) = check_in_progress(el) {
- return rslt;
- }
+ if let hir::ExprKind::If(_, _, Some(el)) = expr.kind
+ && let Some(rslt) = check_in_progress(el)
+ {
+ return rslt;
}
if let hir::ExprKind::Match(_, arms, _) = expr.kind {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index dd6eb73..2345cda 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -615,31 +615,31 @@ pub(in super::super) fn suggest_no_capture_closure(
expected: Ty<'tcx>,
found: Ty<'tcx>,
) -> bool {
- if let (ty::FnPtr(..), ty::Closure(def_id, _)) = (expected.kind(), found.kind()) {
- if let Some(upvars) = self.tcx.upvars_mentioned(*def_id) {
- // Report upto four upvars being captured to reduce the amount error messages
- // reported back to the user.
- let spans_and_labels = upvars
- .iter()
- .take(4)
- .map(|(var_hir_id, upvar)| {
- let var_name = self.tcx.hir_name(*var_hir_id).to_string();
- let msg = format!("`{var_name}` captured here");
- (upvar.span, msg)
- })
- .collect::<Vec<_>>();
+ if let (ty::FnPtr(..), ty::Closure(def_id, _)) = (expected.kind(), found.kind())
+ && let Some(upvars) = self.tcx.upvars_mentioned(*def_id)
+ {
+ // Report upto four upvars being captured to reduce the amount error messages
+ // reported back to the user.
+ let spans_and_labels = upvars
+ .iter()
+ .take(4)
+ .map(|(var_hir_id, upvar)| {
+ let var_name = self.tcx.hir_name(*var_hir_id).to_string();
+ let msg = format!("`{var_name}` captured here");
+ (upvar.span, msg)
+ })
+ .collect::<Vec<_>>();
- let mut multi_span: MultiSpan =
- spans_and_labels.iter().map(|(sp, _)| *sp).collect::<Vec<_>>().into();
- for (sp, label) in spans_and_labels {
- multi_span.push_span_label(sp, label);
- }
- err.span_note(
- multi_span,
- "closures can only be coerced to `fn` types if they do not capture any variables"
- );
- return true;
+ let mut multi_span: MultiSpan =
+ spans_and_labels.iter().map(|(sp, _)| *sp).collect::<Vec<_>>().into();
+ for (sp, label) in spans_and_labels {
+ multi_span.push_span_label(sp, label);
}
+ err.span_note(
+ multi_span,
+ "closures can only be coerced to `fn` types if they do not capture any variables",
+ );
+ return true;
}
false
}
@@ -1302,8 +1302,10 @@ pub(crate) fn suggest_clone_for_ref(
None => ".clone()".to_string(),
};
+ let span = expr.span.find_ancestor_not_from_macro().unwrap_or(expr.span).shrink_to_hi();
+
diag.span_suggestion_verbose(
- expr.span.shrink_to_hi(),
+ span,
"consider using clone here",
suggestion,
Applicability::MachineApplicable,
@@ -1393,7 +1395,10 @@ pub(crate) fn suggest_into(
.macro_backtrace()
.any(|x| matches!(x.kind, ExpnKind::Macro(MacroKind::Attr | MacroKind::Derive, ..)))
{
- let span = expr.span.find_oldest_ancestor_in_same_ctxt();
+ let span = expr
+ .span
+ .find_ancestor_not_from_extern_macro(&self.tcx.sess.source_map())
+ .unwrap_or(expr.span);
let mut sugg = if self.precedence(expr) >= ExprPrecedence::Unambiguous {
vec![(span.shrink_to_hi(), ".into()".to_owned())]
@@ -2060,7 +2065,10 @@ pub(crate) fn suggest_missing_unwrap_expect(
None => sugg.to_string(),
};
- let span = expr.span.find_oldest_ancestor_in_same_ctxt();
+ let span = expr
+ .span
+ .find_ancestor_not_from_extern_macro(&self.tcx.sess.source_map())
+ .unwrap_or(expr.span);
err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders);
true
}
@@ -3006,13 +3014,11 @@ pub(crate) fn suggest_deref_or_ref(
/// Returns whether the given expression is an `else if`.
fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
- if let hir::ExprKind::If(..) = expr.kind {
- if let Node::Expr(hir::Expr {
- kind: hir::ExprKind::If(_, _, Some(else_expr)), ..
- }) = self.tcx.parent_hir_node(expr.hir_id)
- {
- return else_expr.hir_id == expr.hir_id;
- }
+ if let hir::ExprKind::If(..) = expr.kind
+ && let Node::Expr(hir::Expr { kind: hir::ExprKind::If(_, _, Some(else_expr)), .. }) =
+ self.tcx.parent_hir_node(expr.hir_id)
+ {
+ return else_expr.hir_id == expr.hir_id;
}
false
}
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 4c343bb..8d9f7ea 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -669,17 +669,17 @@ fn predicates_require_illegal_sized_bound(
fn check_for_illegal_method_calls(&self, pick: &probe::Pick<'_>) {
// Disallow calls to the method `drop` defined in the `Drop` trait.
- if let Some(trait_def_id) = pick.item.trait_container(self.tcx) {
- if let Err(e) = callee::check_legal_trait_for_method_call(
+ if let Some(trait_def_id) = pick.item.trait_container(self.tcx)
+ && let Err(e) = callee::check_legal_trait_for_method_call(
self.tcx,
self.span,
Some(self.self_expr.span),
self.call_expr.span,
trait_def_id,
self.body_id.to_def_id(),
- ) {
- self.set_tainted_by_errors(e);
- }
+ )
+ {
+ self.set_tainted_by_errors(e);
}
}
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index dbfa7e6..e64af8f 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -264,6 +264,7 @@ pub(crate) fn report_method_error(
err.span_label(within_macro_span, "due to this macro variable");
}
self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true);
+ self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_name);
err.emit()
}
diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
index 9f4ab8c..6a985fc 100644
--- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
+++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
@@ -165,13 +165,12 @@ fn update_infer_var_info(&self, obligation: &PredicateObligation<'tcx>) {
if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) =
obligation.predicate.kind().skip_binder()
- {
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
// we need to make it into one.
- if let Some(vid) = predicate.term.as_type().and_then(|ty| ty.ty_vid()) {
- debug!("infer_var_info: {:?}.output = true", vid);
- infer_var_info.entry(vid).or_default().output = true;
- }
+ && let Some(vid) = predicate.term.as_type().and_then(|ty| ty.ty_vid())
+ {
+ debug!("infer_var_info: {:?}.output = true", vid);
+ infer_var_info.entry(vid).or_default().output = true;
}
}
}
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index be77410..df38c3a 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -1047,7 +1047,7 @@ fn perform_2229_migration_analysis(
}
}
}
- lint.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
+ lint.note("for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
let diagnostic_msg = format!(
"add a dummy let to cause {migrated_variables_concat} to be fully captured"
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index b2497cb..093de95 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -227,21 +227,19 @@ fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) {
self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
self.typeck_results.node_args_mut().remove(e.hir_id);
- if let Some(a) = self.typeck_results.adjustments_mut().get_mut(base.hir_id) {
+ if let Some(a) = self.typeck_results.adjustments_mut().get_mut(base.hir_id)
// Discard the need for a mutable borrow
-
// Extra adjustment made when indexing causes a drop
// of size information - we need to get rid of it
// Since this is "after" the other adjustment to be
// discarded, we do an extra `pop()`
- if let Some(Adjustment {
+ && let Some(Adjustment {
kind: Adjust::Pointer(PointerCoercion::Unsize),
..
}) = a.pop()
- {
- // So the borrow discard actually happens here
- a.pop();
- }
+ {
+ // So the borrow discard actually happens here
+ a.pop();
}
}
}
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index fb6897c..057fbe2 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -208,6 +208,10 @@ fn configure_and_expand(
// Expand macros now!
let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
+ if ecx.nb_macro_errors > 0 {
+ sess.dcx().abort_if_errors();
+ }
+
// The rest is error reporting and stats
sess.psess.buffered_lints.with_lock(|buffered_lints: &mut Vec<BufferedEarlyLint>| {
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 1a1cfc9f..69fe7fe 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -593,7 +593,7 @@
lint_non_fmt_panic = panic message is not a string literal
.note = this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021
- .more_info_note = for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ .more_info_note = for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
.supports_fmt_note = the `{$name}!()` macro supports formatting, so there's no need for the `format!()` macro here
.supports_fmt_suggestion = remove the `format!(..)` macro call
.display_suggestion = add a "{"{"}{"}"}" format string to `Display` the message
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 73e6883..152971c 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1654,7 +1654,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
"`...` range patterns are deprecated",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>",
};
}
@@ -1835,7 +1835,7 @@ fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) {
"detects edition keywords being used as an identifier",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>",
};
}
@@ -2446,16 +2446,16 @@ fn is_zero(expr: &hir::Expr<'_>) -> bool {
/// Determine if this expression is a "dangerous initialization".
fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<InitKind> {
- if let hir::ExprKind::Call(path_expr, args) = expr.kind {
+ if let hir::ExprKind::Call(path_expr, args) = expr.kind
// Find calls to `mem::{uninitialized,zeroed}` methods.
- if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
- let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
- match cx.tcx.get_diagnostic_name(def_id) {
- Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
- Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
- Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
- _ => {}
- }
+ && let hir::ExprKind::Path(ref qpath) = path_expr.kind
+ {
+ let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
+ match cx.tcx.get_diagnostic_name(def_id) {
+ Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
+ Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
+ Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
+ _ => {}
}
} else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind {
// Find problematic calls to `MaybeUninit::assume_init`.
@@ -2463,14 +2463,14 @@ fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<InitK
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
// This is a call to *some* method named `assume_init`.
// See if the `self` parameter is one of the dangerous constructors.
- if let hir::ExprKind::Call(path_expr, _) = receiver.kind {
- if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
- let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
- match cx.tcx.get_diagnostic_name(def_id) {
- Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
- Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
- _ => {}
- }
+ if let hir::ExprKind::Call(path_expr, _) = receiver.kind
+ && let hir::ExprKind::Path(ref qpath) = path_expr.kind
+ {
+ let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
+ match cx.tcx.get_diagnostic_name(def_id) {
+ Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
+ Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
+ _ => {}
}
}
}
@@ -2724,13 +2724,13 @@ fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
}
// check for call to `core::ptr::null` or `core::ptr::null_mut`
hir::ExprKind::Call(path, _) => {
- if let hir::ExprKind::Path(ref qpath) = path.kind {
- if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
- return matches!(
- cx.tcx.get_diagnostic_name(def_id),
- Some(sym::ptr_null | sym::ptr_null_mut)
- );
- }
+ if let hir::ExprKind::Path(ref qpath) = path.kind
+ && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+ {
+ return matches!(
+ cx.tcx.get_diagnostic_name(def_id),
+ Some(sym::ptr_null | sym::ptr_null_mut)
+ );
}
}
_ => {}
@@ -2870,7 +2870,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
if let hir::Expr {
kind:
hir::ExprKind::InlineAsm(hir::InlineAsm {
- asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm,
+ asm_macro: asm_macro @ (AsmMacro::Asm | AsmMacro::NakedAsm),
template_strs,
options,
..
@@ -2878,6 +2878,15 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
..
} = expr
{
+ // Non-generic naked functions are allowed to define arbitrary
+ // labels.
+ if *asm_macro == AsmMacro::NakedAsm {
+ let def_id = expr.hir_id.owner.def_id;
+ if !cx.tcx.generics_of(def_id).requires_monomorphization(cx.tcx) {
+ return;
+ }
+ }
+
// asm with `options(raw)` does not do replacement with `{` and `}`.
let raw = options.contains(InlineAsmOptions::RAW);
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index 263ea6f..ff67ed1 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -87,7 +87,7 @@
rewriting in `match` is an option to preserve the semantics up to Edition 2021",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>",
};
}
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index c17281d..b9afb62 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -71,7 +71,7 @@
"`impl Trait` will capture more lifetimes than possibly intended in edition 2024",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/rpit-lifetime-capture.html>",
};
}
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index d8fc46a..7dafcc1 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -411,22 +411,21 @@ fn check_path(
impl EarlyLintPass for LintPassImpl {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
- if let ast::ItemKind::Impl(box ast::Impl { of_trait: Some(lint_pass), .. }) = &item.kind {
- if let Some(last) = lint_pass.path.segments.last() {
- if last.ident.name == sym::LintPass {
- let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
- let call_site = expn_data.call_site;
- if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
- && call_site.ctxt().outer_expn_data().kind
- != ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
- {
- cx.emit_span_lint(
- LINT_PASS_IMPL_WITHOUT_MACRO,
- lint_pass.path.span,
- LintPassByHand,
- );
- }
- }
+ if let ast::ItemKind::Impl(box ast::Impl { of_trait: Some(lint_pass), .. }) = &item.kind
+ && let Some(last) = lint_pass.path.segments.last()
+ && last.ident.name == sym::LintPass
+ {
+ let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
+ let call_site = expn_data.call_site;
+ if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
+ && call_site.ctxt().outer_expn_data().kind
+ != ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
+ {
+ cx.emit_span_lint(
+ LINT_PASS_IMPL_WITHOUT_MACRO,
+ lint_pass.path.span,
+ LintPassByHand,
+ );
}
}
}
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index c681dee..ccfba71 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -356,7 +356,16 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
let store = unerased_lint_store(tcx.sess);
if store.late_module_passes.is_empty() {
- late_lint_mod_inner(tcx, module_def_id, context, builtin_lints);
+ // If all builtin lints can be skipped, there is no point in running `late_lint_mod_inner`
+ // at all. This happens often for dependencies built with `--cap-lints=allow`.
+ let dont_need_to_run = tcx.lints_that_dont_need_to_run(());
+ let can_skip_lints = builtin_lints
+ .get_lints()
+ .iter()
+ .all(|lint| dont_need_to_run.contains(&LintId::of(lint)));
+ if !can_skip_lints {
+ late_lint_mod_inner(tcx, module_def_id, context, builtin_lints);
+ }
} else {
let builtin_lints = Box::new(builtin_lints) as Box<dyn LateLintPass<'tcx>>;
let mut binding = store
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 16eeb89..ac47897 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -933,6 +933,7 @@ fn add(
fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool {
let feature = if let Some(feature) = lint_id.lint.feature_gate
&& !self.features.enabled(feature)
+ && !span.allows_unstable(feature)
{
// Lint is behind a feature that is not enabled; eventually return false.
feature
diff --git a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs
index ce280fe..7de6fbd 100644
--- a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs
+++ b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs
@@ -65,7 +65,7 @@
/// to ensure the macros implement the desired behavior.
///
/// [editions]: https://doc.rust-lang.org/edition-guide/
- /// [macro matcher fragment specifiers]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/macro-fragment-specifiers.html
+ /// [macro matcher fragment specifiers]: https://doc.rust-lang.org/edition-guide/rust-2024/macro-fragment-specifiers.html
/// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
pub EDITION_2024_EXPR_FRAGMENT_SPECIFIER,
Allow,
@@ -73,7 +73,7 @@
To keep the existing behavior, use the `expr_2021` fragment specifier.",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
- reference: "Migration Guide <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/macro-fragment-specifiers.html>",
+ reference: "Migration Guide <https://doc.rust-lang.org/edition-guide/rust-2024/macro-fragment-specifiers.html>",
};
}
diff --git a/compiler/rustc_lint/src/map_unit_fn.rs b/compiler/rustc_lint/src/map_unit_fn.rs
index af509cb..3421013 100644
--- a/compiler/rustc_lint/src/map_unit_fn.rs
+++ b/compiler/rustc_lint/src/map_unit_fn.rs
@@ -43,56 +43,50 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'_>) {
return;
}
- if let StmtKind::Semi(expr) = stmt.kind {
- if let ExprKind::MethodCall(path, receiver, args, span) = expr.kind {
- if path.ident.name.as_str() == "map" {
- if receiver.span.from_expansion()
- || args.iter().any(|e| e.span.from_expansion())
- || !is_impl_slice(cx, receiver)
- || !is_diagnostic_name(cx, expr.hir_id, "IteratorMap")
- {
- return;
+ if let StmtKind::Semi(expr) = stmt.kind
+ && let ExprKind::MethodCall(path, receiver, args, span) = expr.kind
+ {
+ if path.ident.name.as_str() == "map" {
+ if receiver.span.from_expansion()
+ || args.iter().any(|e| e.span.from_expansion())
+ || !is_impl_slice(cx, receiver)
+ || !is_diagnostic_name(cx, expr.hir_id, "IteratorMap")
+ {
+ return;
+ }
+ let arg_ty = cx.typeck_results().expr_ty(&args[0]);
+ let default_span = args[0].span;
+ if let ty::FnDef(id, _) = arg_ty.kind() {
+ let fn_ty = cx.tcx.fn_sig(id).skip_binder();
+ let ret_ty = fn_ty.output().skip_binder();
+ if is_unit_type(ret_ty) {
+ cx.emit_span_lint(
+ MAP_UNIT_FN,
+ span,
+ MappingToUnit {
+ function_label: cx.tcx.span_of_impl(*id).unwrap_or(default_span),
+ argument_label: args[0].span,
+ map_label: span,
+ suggestion: path.ident.span,
+ replace: "for_each".to_string(),
+ },
+ )
}
- let arg_ty = cx.typeck_results().expr_ty(&args[0]);
- let default_span = args[0].span;
- if let ty::FnDef(id, _) = arg_ty.kind() {
- let fn_ty = cx.tcx.fn_sig(id).skip_binder();
- let ret_ty = fn_ty.output().skip_binder();
- if is_unit_type(ret_ty) {
- cx.emit_span_lint(
- MAP_UNIT_FN,
- span,
- MappingToUnit {
- function_label: cx
- .tcx
- .span_of_impl(*id)
- .unwrap_or(default_span),
- argument_label: args[0].span,
- map_label: span,
- suggestion: path.ident.span,
- replace: "for_each".to_string(),
- },
- )
- }
- } else if let ty::Closure(id, subs) = arg_ty.kind() {
- let cl_ty = subs.as_closure().sig();
- let ret_ty = cl_ty.output().skip_binder();
- if is_unit_type(ret_ty) {
- cx.emit_span_lint(
- MAP_UNIT_FN,
- span,
- MappingToUnit {
- function_label: cx
- .tcx
- .span_of_impl(*id)
- .unwrap_or(default_span),
- argument_label: args[0].span,
- map_label: span,
- suggestion: path.ident.span,
- replace: "for_each".to_string(),
- },
- )
- }
+ } else if let ty::Closure(id, subs) = arg_ty.kind() {
+ let cl_ty = subs.as_closure().sig();
+ let ret_ty = cl_ty.output().skip_binder();
+ if is_unit_type(ret_ty) {
+ cx.emit_span_lint(
+ MAP_UNIT_FN,
+ span,
+ MappingToUnit {
+ function_label: cx.tcx.span_of_impl(*id).unwrap_or(default_span),
+ argument_label: args[0].span,
+ map_label: span,
+ suggestion: path.ident.span,
+ replace: "for_each".to_string(),
+ },
+ )
}
}
}
@@ -101,10 +95,10 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'_>) {
}
fn is_impl_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
- if let Some(impl_id) = cx.tcx.impl_of_method(method_id) {
- return cx.tcx.type_of(impl_id).skip_binder().is_slice();
- }
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
+ {
+ return cx.tcx.type_of(impl_id).skip_binder().is_slice();
}
false
}
@@ -114,11 +108,11 @@ fn is_unit_type(ty: Ty<'_>) -> bool {
}
fn is_diagnostic_name(cx: &LateContext<'_>, id: HirId, name: &str) -> bool {
- if let Some(def_id) = cx.typeck_results().type_dependent_def_id(id) {
- if let Some(item) = cx.tcx.get_diagnostic_name(def_id) {
- if item.as_str() == name {
- return true;
- }
+ if let Some(def_id) = cx.typeck_results().type_dependent_def_id(id)
+ && let Some(item) = cx.tcx.get_diagnostic_name(def_id)
+ {
+ if item.as_str() == name {
+ return true;
}
}
false
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 16c0610..2eabeea 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -48,38 +48,38 @@
impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
- if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
- if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
- let f_diagnostic_name = cx.tcx.get_diagnostic_name(def_id);
+ if let hir::ExprKind::Call(f, [arg]) = &expr.kind
+ && let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind()
+ {
+ let f_diagnostic_name = cx.tcx.get_diagnostic_name(def_id);
- if cx.tcx.is_lang_item(def_id, LangItem::BeginPanic)
- || cx.tcx.is_lang_item(def_id, LangItem::Panic)
- || f_diagnostic_name == Some(sym::panic_str_2015)
+ if cx.tcx.is_lang_item(def_id, LangItem::BeginPanic)
+ || cx.tcx.is_lang_item(def_id, LangItem::Panic)
+ || f_diagnostic_name == Some(sym::panic_str_2015)
+ {
+ if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
+ if matches!(
+ cx.tcx.get_diagnostic_name(id),
+ Some(sym::core_panic_2015_macro | sym::std_panic_2015_macro)
+ ) {
+ check_panic(cx, f, arg);
+ }
+ }
+ } else if f_diagnostic_name == Some(sym::unreachable_display) {
+ if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id
+ && cx.tcx.is_diagnostic_item(sym::unreachable_2015_macro, id)
{
- if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
- if matches!(
- cx.tcx.get_diagnostic_name(id),
- Some(sym::core_panic_2015_macro | sym::std_panic_2015_macro)
- ) {
- check_panic(cx, f, arg);
- }
- }
- } else if f_diagnostic_name == Some(sym::unreachable_display) {
- if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
- if cx.tcx.is_diagnostic_item(sym::unreachable_2015_macro, id) {
- check_panic(
- cx,
- f,
- // This is safe because we checked above that the callee is indeed
- // unreachable_display
- match &arg.kind {
- // Get the borrowed arg not the borrow
- hir::ExprKind::AddrOf(ast::BorrowKind::Ref, _, arg) => arg,
- _ => bug!("call to unreachable_display without borrow"),
- },
- );
- }
- }
+ check_panic(
+ cx,
+ f,
+ // This is safe because we checked above that the callee is indeed
+ // unreachable_display
+ match &arg.kind {
+ // Get the borrowed arg not the borrow
+ hir::ExprKind::AddrOf(ast::BorrowKind::Ref, _, arg) => arg,
+ _ => bug!("call to unreachable_display without borrow"),
+ },
+ );
}
}
}
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index db89396..76e374d 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -623,15 +623,15 @@ fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) {
..
}) = p.kind
{
- if let Res::Def(DefKind::Const, _) = path.res {
- if let [segment] = path.segments {
- NonUpperCaseGlobals::check_upper_case(
- cx,
- "constant in pattern",
- None,
- &segment.ident,
- );
- }
+ if let Res::Def(DefKind::Const, _) = path.res
+ && let [segment] = path.segments
+ {
+ NonUpperCaseGlobals::check_upper_case(
+ cx,
+ "constant in pattern",
+ None,
+ &segment.ident,
+ );
}
}
}
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index b7835e6..24682c4 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -84,7 +84,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
return;
};
- let Some(trait_id) = cx.tcx.trait_of_item(did) else { return };
+ let Some(trait_id) = cx.tcx.trait_of_assoc(did) else { return };
let Some(trait_) = cx.tcx.get_diagnostic_name(trait_id) else { return };
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index d3b3b55..a3cf3d5 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -24,7 +24,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
match &ty.kind {
TyKind::Ref(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => {
- if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {
+ if let Some(impl_did) = cx.tcx.impl_of_assoc(ty.hir_id.owner.to_def_id()) {
if cx.tcx.impl_trait_ref(impl_did).is_some() {
return;
}
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index affea1b..191eb72 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -92,7 +92,7 @@ macro_rules! expand_combined_late_lint_pass_methods {
/// Combines multiple lints passes into a single lint pass, at compile time,
/// for maximum speed. Each `check_foo` method in `$methods` within this pass
/// simply calls `check_foo` once per `$pass`. Compare with
-/// `LateLintPassObjects`, which is similar, but combines lint passes at
+/// `RuntimeCombinedLateLintPass`, which is similar, but combines lint passes at
/// runtime.
#[macro_export]
macro_rules! declare_combined_late_lint_pass {
@@ -123,10 +123,10 @@ impl<'tcx> $crate::LateLintPass<'tcx> for $name {
#[allow(rustc::lint_pass_impl_without_macro)]
impl $crate::LintPass for $name {
fn name(&self) -> &'static str {
- panic!()
+ stringify!($name)
}
fn get_lints(&self) -> LintVec {
- panic!()
+ $name::get_lints()
}
}
)
diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs
index 00fa049..d296ae4 100644
--- a/compiler/rustc_lint/src/shadowed_into_iter.rs
+++ b/compiler/rustc_lint/src/shadowed_into_iter.rs
@@ -32,7 +32,7 @@
"detects calling `into_iter` on arrays in Rust 2015 and 2018",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
};
}
@@ -61,7 +61,7 @@
"detects calling `into_iter` on boxed slices in Rust 2015, 2018, and 2021",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/intoiterator-box-slice.html>"
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/intoiterator-box-slice.html>"
};
}
diff --git a/compiler/rustc_lint/src/static_mut_refs.rs b/compiler/rustc_lint/src/static_mut_refs.rs
index 4dda3c7..16e1fb0 100644
--- a/compiler/rustc_lint/src/static_mut_refs.rs
+++ b/compiler/rustc_lint/src/static_mut_refs.rs
@@ -54,7 +54,7 @@
"creating a shared reference to mutable static",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>",
explain_reason: false,
};
@edition Edition2024 => Deny;
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index fc9d795..b0afc33 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1904,7 +1904,7 @@ fn inherent_atomic_method_call<'hir>(
if let ExprKind::MethodCall(method_path, _, args, _) = &expr.kind
&& recognized_names.contains(&method_path.ident.name)
&& let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
- && let Some(impl_did) = cx.tcx.impl_of_method(m_def_id)
+ && let Some(impl_did) = cx.tcx.impl_of_assoc(m_def_id)
&& let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def()
// skip extension traits, only lint functions from the standard library
&& cx.tcx.trait_id_of_impl(impl_did).is_none()
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index a9eb173..00e40b5 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -185,7 +185,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
let mut op_warned = false;
if let Some(must_use_op) = must_use_op {
- let span = expr.span.find_oldest_ancestor_in_same_ctxt();
+ let span = expr.span.find_ancestor_not_from_macro().unwrap_or(expr.span);
cx.emit_span_lint(
UNUSED_MUST_USE,
expr.span,
@@ -511,7 +511,7 @@ fn emit_must_use_untranslated(
);
}
MustUsePath::Def(span, def_id, reason) => {
- let span = span.find_oldest_ancestor_in_same_ctxt();
+ let span = span.find_ancestor_not_from_macro().unwrap_or(*span);
cx.emit_span_lint(
UNUSED_MUST_USE,
span,
@@ -562,20 +562,19 @@ fn emit_must_use_untranslated(
impl<'tcx> LateLintPass<'tcx> for PathStatements {
fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
- if let hir::StmtKind::Semi(expr) = s.kind {
- if let hir::ExprKind::Path(_) = expr.kind {
- let ty = cx.typeck_results().expr_ty(expr);
- if ty.needs_drop(cx.tcx, cx.typing_env()) {
- let sub = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span)
- {
- PathStatementDropSub::Suggestion { span: s.span, snippet }
- } else {
- PathStatementDropSub::Help { span: s.span }
- };
- cx.emit_span_lint(PATH_STATEMENTS, s.span, PathStatementDrop { sub })
+ if let hir::StmtKind::Semi(expr) = s.kind
+ && let hir::ExprKind::Path(_) = expr.kind
+ {
+ let ty = cx.typeck_results().expr_ty(expr);
+ if ty.needs_drop(cx.tcx, cx.typing_env()) {
+ let sub = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
+ PathStatementDropSub::Suggestion { span: s.span, snippet }
} else {
- cx.emit_span_lint(PATH_STATEMENTS, s.span, PathStatementNoEffect);
- }
+ PathStatementDropSub::Help { span: s.span }
+ };
+ cx.emit_span_lint(PATH_STATEMENTS, s.span, PathStatementDrop { sub })
+ } else {
+ cx.emit_span_lint(PATH_STATEMENTS, s.span, PathStatementNoEffect);
}
}
}
@@ -1340,7 +1339,15 @@ fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
self.with_self_ty_parens = false;
}
ast::TyKind::Ref(_, mut_ty) | ast::TyKind::Ptr(mut_ty) => {
- self.in_no_bounds_pos.insert(mut_ty.ty.id, NoBoundsException::OneBound);
+ // If this type itself appears in no-bounds position, we propagate its
+ // potentially tighter constraint or risk a false posive (issue 143653).
+ let own_constraint = self.in_no_bounds_pos.get(&ty.id);
+ let constraint = match own_constraint {
+ Some(NoBoundsException::None) => NoBoundsException::None,
+ Some(NoBoundsException::OneBound) => NoBoundsException::OneBound,
+ None => NoBoundsException::OneBound,
+ };
+ self.in_no_bounds_pos.insert(mut_ty.ty.id, constraint);
}
ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => {
for i in 0..bounds.len() {
@@ -1509,21 +1516,19 @@ fn check_unused_delims_expr(
// let _: A<{produces_literal!()}>;
// ```
// FIXME(const_generics): handle paths when #67075 is fixed.
- if let [stmt] = inner.stmts.as_slice() {
- if let ast::StmtKind::Expr(ref expr) = stmt.kind {
- if !Self::is_expr_delims_necessary(expr, ctx, followed_by_block)
- && (ctx != UnusedDelimsCtx::AnonConst
- || (matches!(expr.kind, ast::ExprKind::Lit(_))
- && !expr.span.from_expansion()))
- && ctx != UnusedDelimsCtx::ClosureBody
- && !cx.sess().source_map().is_multiline(value.span)
- && value.attrs.is_empty()
- && !value.span.from_expansion()
- && !inner.span.from_expansion()
- {
- self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
- }
- }
+ if let [stmt] = inner.stmts.as_slice()
+ && let ast::StmtKind::Expr(ref expr) = stmt.kind
+ && !Self::is_expr_delims_necessary(expr, ctx, followed_by_block)
+ && (ctx != UnusedDelimsCtx::AnonConst
+ || (matches!(expr.kind, ast::ExprKind::Lit(_))
+ && !expr.span.from_expansion()))
+ && ctx != UnusedDelimsCtx::ClosureBody
+ && !cx.sess().source_map().is_multiline(value.span)
+ && value.attrs.is_empty()
+ && !value.span.from_expansion()
+ && !inner.span.from_expansion()
+ {
+ self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
}
}
ast::ExprKind::Let(_, ref expr, _, _) => {
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index a08d68e..b1edb5c 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1814,7 +1814,7 @@
"suggest using `dyn Trait` for trait objects",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>",
};
}
@@ -2472,7 +2472,7 @@
"unsafe operations in unsafe functions without an explicit unsafe block are deprecated",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>",
explain_reason: false
};
@edition Edition2024 => Warn;
@@ -3445,7 +3445,7 @@
"detects usage of old versions of or-patterns",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html>",
};
}
@@ -3494,7 +3494,7 @@
prelude in future editions",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>",
};
}
@@ -3534,7 +3534,7 @@
prelude in future editions",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/prelude.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/prelude.html>",
};
}
@@ -3571,7 +3571,7 @@
"identifiers that will be parsed as a prefix in Rust 2021",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/reserving-syntax.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2021/reserving-syntax.html>",
};
crate_level_only
}
@@ -4100,7 +4100,7 @@
"never type fallback affecting unsafe function calls",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>",
report_in_deps: true,
};
@edition Edition2024 => Deny;
@@ -4155,7 +4155,7 @@
"never type fallback affecting unsafe function calls",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionAndFutureReleaseError(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>",
report_in_deps: true,
};
report_in_external_macro
@@ -4740,7 +4740,7 @@
"detects unsafe functions being used as safe functions",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/newly-unsafe-functions.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/newly-unsafe-functions.html>",
};
}
@@ -4776,7 +4776,7 @@
"detects missing unsafe keyword on extern declarations",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-extern.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-extern.html>",
};
}
@@ -4817,7 +4817,7 @@
"detects unsafe attributes outside of unsafe",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-attributes.html>",
};
}
@@ -5014,7 +5014,7 @@
"Detect and warn on significant change in drop order in tail expression location",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>",
};
}
@@ -5053,7 +5053,7 @@
"will be parsed as a guarded string in Rust 2024",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
- reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>",
+ reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>",
};
crate_level_only
}
diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml
index 39de478..85a2a9c 100644
--- a/compiler/rustc_llvm/Cargo.toml
+++ b/compiler/rustc_llvm/Cargo.toml
@@ -10,8 +10,8 @@
[build-dependencies]
# tidy-alphabetical-start
-# Pinned so `cargo update` bumps don't cause breakage. Please also update the
-# pinned `cc` in `rustc_codegen_ssa` if you update `cc` here.
+# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version
+# per crate", so if you change this, you need to also change it in `rustc_codegen_ssa`.
cc = "=1.2.16"
# tidy-alphabetical-end
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index a2e4d73..8c34052 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -1650,40 +1650,6 @@
return wrap(std::move(*SrcOrError).release());
}
-// Find a section of an object file by name. Fail if the section is missing or
-// empty.
-extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data,
- size_t len,
- const char *name,
- size_t name_len,
- size_t *out_len) {
- *out_len = 0;
- auto Name = StringRef(name, name_len);
- auto Data = StringRef(data, len);
- auto Buffer = MemoryBufferRef(Data, ""); // The id is unused.
- file_magic Type = identify_magic(Buffer.getBuffer());
- Expected<std::unique_ptr<object::ObjectFile>> ObjFileOrError =
- object::ObjectFile::createObjectFile(Buffer, Type);
- if (!ObjFileOrError) {
- LLVMRustSetLastError(toString(ObjFileOrError.takeError()).c_str());
- return nullptr;
- }
- for (const object::SectionRef &Sec : (*ObjFileOrError)->sections()) {
- Expected<StringRef> SecName = Sec.getName();
- if (SecName && *SecName == Name) {
- Expected<StringRef> SectionOrError = Sec.getContents();
- if (!SectionOrError) {
- LLVMRustSetLastError(toString(SectionOrError.takeError()).c_str());
- return nullptr;
- }
- *out_len = SectionOrError->size();
- return SectionOrError->data();
- }
- }
- LLVMRustSetLastError("could not find requested section");
- return nullptr;
-}
-
// Computes the LTO cache key for the provided 'ModId' in the given 'Data',
// storing the result in 'KeyOut'.
// Currently, this cache key is a SHA-1 hash of anything that could affect
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 82568ed..c9814be 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1610,7 +1610,7 @@
extern "C" void LLVMRustPositionAfter(LLVMBuilderRef B, LLVMValueRef Instr) {
if (auto I = dyn_cast<Instruction>(unwrap<Value>(Instr))) {
- auto J = I->getNextNonDebugInstruction();
+ auto J = I->getNextNode();
unwrap(B)->SetInsertPoint(J);
}
}
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index 3bef5ca..4d3e879 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -330,3 +330,6 @@
metadata_whole_archive_needs_static =
linking modifier `whole-archive` is only compatible with `static` linking kind
+
+metadata_raw_dylib_malformed =
+ link name must be well-formed if link kind is `raw-dylib`
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index 4a3b431..0332dba 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -815,3 +815,10 @@ pub struct AsyncDropTypesInDependency {
pub extern_crate: Symbol,
pub local_crate: Symbol,
}
+
+#[derive(Diagnostic)]
+#[diag(metadata_raw_dylib_malformed)]
+pub struct RawDylibMalformed {
+ #[primary_span]
+ pub span: Span,
+}
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index c30cfd1..9fef22f 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -370,12 +370,11 @@ pub(crate) fn maybe_load_library_crate(
return self.find_commandline_library(crate_rejections);
}
let mut seen_paths = FxHashSet::default();
- if let Some(extra_filename) = self.extra_filename {
- if let library @ Some(_) =
+ if let Some(extra_filename) = self.extra_filename
+ && let library @ Some(_) =
self.find_library_crate(crate_rejections, extra_filename, &mut seen_paths)?
- {
- return Ok(library);
- }
+ {
+ return Ok(library);
}
self.find_library_crate(crate_rejections, "", &mut seen_paths)
}
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 4d276f8..ed0f084 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -700,8 +700,21 @@ fn build_dll_import(
.link_ordinal
.map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
+ let name = codegen_fn_attrs.link_name.unwrap_or_else(|| self.tcx.item_name(item));
+
+ if self.tcx.sess.target.binary_format == BinaryFormat::Elf {
+ let name = name.as_str();
+ if name.contains('\0') {
+ self.tcx.dcx().emit_err(errors::RawDylibMalformed { span });
+ } else if let Some((left, right)) = name.split_once('@')
+ && (left.is_empty() || right.is_empty() || right.contains('@'))
+ {
+ self.tcx.dcx().emit_err(errors::RawDylibMalformed { span });
+ }
+ }
+
DllImport {
- name: codegen_fn_attrs.link_name.unwrap_or_else(|| self.tcx.item_name(item)),
+ name,
import_name_type,
calling_convention,
span,
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 5cd9803..4075bee 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -5,7 +5,7 @@
use std::path::{Path, PathBuf};
use std::sync::Arc;
-use rustc_attr_data_structures::EncodeCrossCrate;
+use rustc_attr_data_structures::{AttributeKind, EncodeCrossCrate, find_attr};
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::memmap::{Mmap, MmapMut};
use rustc_data_structures::sync::{join, par_for_each_in};
@@ -1965,18 +1965,13 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
// Proc-macros may have attributes like `#[allow_internal_unstable]`,
// so downstream crates need access to them.
let attrs = tcx.hir_attrs(proc_macro);
- let macro_kind = if ast::attr::contains_name(attrs, sym::proc_macro) {
+ let macro_kind = if find_attr!(attrs, AttributeKind::ProcMacro(..)) {
MacroKind::Bang
- } else if ast::attr::contains_name(attrs, sym::proc_macro_attribute) {
+ } else if find_attr!(attrs, AttributeKind::ProcMacroAttribute(..)) {
MacroKind::Attr
- } else if let Some(attr) = ast::attr::find_by_name(attrs, sym::proc_macro_derive) {
- // This unwrap chain should have been checked by the proc-macro harness.
- name = attr.meta_item_list().unwrap()[0]
- .meta_item()
- .unwrap()
- .ident()
- .unwrap()
- .name;
+ } else if let Some(trait_name) = find_attr!(attrs, AttributeKind::ProcMacroDerive { trait_name, ..} => trait_name)
+ {
+ name = *trait_name;
MacroKind::Derive
} else {
bug!("Unknown proc-macro type for item {:?}", id);
@@ -2124,11 +2119,11 @@ fn encode_impls(&mut self) -> LazyArray<TraitImpls> {
};
let def_id = id.owner_id.to_def_id();
- self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id));
-
if of_trait && let Some(header) = tcx.impl_trait_header(def_id) {
record!(self.tables.impl_trait_header[def_id] <- header);
+ self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id));
+
let trait_ref = header.trait_ref.instantiate_identity();
let simplified_self_ty = fast_reject::simplify_type(
self.tcx,
@@ -2141,10 +2136,10 @@ fn encode_impls(&mut self) -> LazyArray<TraitImpls> {
.push((id.owner_id.def_id.local_def_index, simplified_self_ty));
let trait_def = tcx.trait_def(trait_ref.def_id);
- if let Ok(mut an) = trait_def.ancestors(tcx, def_id) {
- if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) {
- self.tables.impl_parent.set_some(def_id.index, parent.into());
- }
+ if let Ok(mut an) = trait_def.ancestors(tcx, def_id)
+ && let Some(specialization_graph::Node::Impl(parent)) = an.nth(1)
+ {
+ self.tables.impl_parent.set_some(def_id.index, parent.into());
}
// if this is an impl of `CoerceUnsized`, create its
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index 0354909..785ddd1 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -182,7 +182,7 @@ pub fn check_invariants(&self, tcx: TyCtxt<'_>) {
// don't check this condition for them.
let is_impl = matches!(tcx.def_kind(def_id), DefKind::Impl { .. });
let is_associated_item_in_trait_impl = tcx
- .impl_of_method(def_id.to_def_id())
+ .impl_of_assoc(def_id.to_def_id())
.and_then(|impl_id| tcx.trait_id_of_impl(impl_id))
.is_some();
if !is_impl && !is_associated_item_in_trait_impl {
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 0f5b63f..800c1af 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -175,23 +175,22 @@ pub fn span(&self, tcx: TyCtxt<'_>, scope_tree: &ScopeTree) -> Span {
return DUMMY_SP;
};
let span = tcx.hir_span(hir_id);
- if let ScopeData::Remainder(first_statement_index) = self.data {
- if let Node::Block(blk) = tcx.hir_node(hir_id) {
- // Want span for scope starting after the
- // indexed statement and ending at end of
- // `blk`; reuse span of `blk` and shift `lo`
- // forward to end of indexed statement.
- //
- // (This is the special case alluded to in the
- // doc-comment for this method)
+ if let ScopeData::Remainder(first_statement_index) = self.data
+ // Want span for scope starting after the
+ // indexed statement and ending at end of
+ // `blk`; reuse span of `blk` and shift `lo`
+ // forward to end of indexed statement.
+ //
+ // (This is the special case alluded to in the
+ // doc-comment for this method)
+ && let Node::Block(blk) = tcx.hir_node(hir_id)
+ {
+ let stmt_span = blk.stmts[first_statement_index.index()].span;
- let stmt_span = blk.stmts[first_statement_index.index()].span;
-
- // To avoid issues with macro-generated spans, the span
- // of the statement must be nested in that of the block.
- if span.lo() <= stmt_span.lo() && stmt_span.lo() <= span.hi() {
- return span.with_lo(stmt_span.lo());
- }
+ // To avoid issues with macro-generated spans, the span
+ // of the statement must be nested in that of the block.
+ if span.lo() <= stmt_span.lo() && stmt_span.lo() <= span.hi() {
+ return span.with_lo(stmt_span.lo());
}
}
span
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 2b0cfb8..3e895c6 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -426,7 +426,12 @@ pub enum UndefinedBehaviorInfo<'tcx> {
/// Trying to set discriminant to the niched variant, but the value does not match.
InvalidNichedEnumVariantWritten { enum_ty: Ty<'tcx> },
/// ABI-incompatible argument types.
- AbiMismatchArgument { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
+ AbiMismatchArgument {
+ /// The index of the argument whose type is wrong.
+ arg_idx: usize,
+ caller_ty: Ty<'tcx>,
+ callee_ty: Ty<'tcx>,
+ },
/// ABI-incompatible return types.
AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
}
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 2d7ddd1..105736b 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -143,10 +143,8 @@ pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
};
// Similarly, the executable entrypoint must be instantiated exactly once.
- if let Some((entry_def_id, _)) = tcx.entry_fn(()) {
- if instance.def_id() == entry_def_id {
- return InstantiationMode::GloballyShared { may_conflict: false };
- }
+ if tcx.is_entrypoint(instance.def_id()) {
+ return InstantiationMode::GloballyShared { may_conflict: false };
}
// If the function is #[naked] or contains any other attribute that requires exactly-once
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 638dc2c..b0d579a 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -2152,9 +2152,6 @@
desc { |tcx| "collecting child items of module `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
}
- query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
- desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id) }
- }
/// Gets the number of definitions in a foreign crate.
///
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 730c114..3dd6d2c 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -838,6 +838,8 @@ pub enum PatKind<'tcx> {
/// * integer, bool, char or float (represented as a valtree), which will be handled by
/// exhaustiveness to cover exactly its own value, similar to `&str`, but these values are
/// much simpler.
+ /// * raw pointers derived from integers, other raw pointers will have already resulted in an
+ // error.
/// * `String`, if `string_deref_patterns` is enabled.
Constant {
value: mir::Const<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 275458f..3bf80d3 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -566,10 +566,10 @@ pub fn discriminants(
let mut prev_discr = None::<Discr<'tcx>>;
self.variants().iter_enumerated().map(move |(i, v)| {
let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
- if let VariantDiscr::Explicit(expr_did) = v.discr {
- if let Ok(new_discr) = self.eval_explicit_discr(tcx, expr_did) {
- discr = new_discr;
- }
+ if let VariantDiscr::Explicit(expr_did) = v.discr
+ && let Ok(new_discr) = self.eval_explicit_discr(tcx, expr_did)
+ {
+ discr = new_discr;
}
prev_discr = Some(discr);
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index aa2494a..6f21160 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1041,11 +1041,13 @@ fn intern_clauses(&self, clauses: &[Clause<'tcx>]) -> Clauses<'tcx> {
const NUM_PREINTERNED_FRESH_TYS: u32 = 20;
const NUM_PREINTERNED_FRESH_INT_TYS: u32 = 3;
const NUM_PREINTERNED_FRESH_FLOAT_TYS: u32 = 3;
+const NUM_PREINTERNED_ANON_BOUND_TYS_I: u32 = 3;
+const NUM_PREINTERNED_ANON_BOUND_TYS_V: u32 = 20;
// This number may seem high, but it is reached in all but the smallest crates.
const NUM_PREINTERNED_RE_VARS: u32 = 500;
-const NUM_PREINTERNED_RE_LATE_BOUNDS_I: u32 = 2;
-const NUM_PREINTERNED_RE_LATE_BOUNDS_V: u32 = 20;
+const NUM_PREINTERNED_ANON_RE_BOUNDS_I: u32 = 3;
+const NUM_PREINTERNED_ANON_RE_BOUNDS_V: u32 = 20;
pub struct CommonTypes<'tcx> {
pub unit: Ty<'tcx>,
@@ -1088,6 +1090,11 @@ pub struct CommonTypes<'tcx> {
/// Pre-interned `Infer(ty::FreshFloatTy(n))` for small values of `n`.
pub fresh_float_tys: Vec<Ty<'tcx>>,
+
+ /// Pre-interned values of the form:
+ /// `Bound(DebruijnIndex(i), BoundTy { var: v, kind: BoundTyKind::Anon})`
+ /// for small values of `i` and `v`.
+ pub anon_bound_tys: Vec<Vec<Ty<'tcx>>>,
}
pub struct CommonLifetimes<'tcx> {
@@ -1101,9 +1108,9 @@ pub struct CommonLifetimes<'tcx> {
pub re_vars: Vec<Region<'tcx>>,
/// Pre-interned values of the form:
- /// `ReBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon })`
+ /// `ReBound(DebruijnIndex(i), BoundRegion { var: v, kind: BoundRegionKind::Anon })`
/// for small values of `i` and `v`.
- pub re_late_bounds: Vec<Vec<Region<'tcx>>>,
+ pub anon_re_bounds: Vec<Vec<Region<'tcx>>>,
}
pub struct CommonConsts<'tcx> {
@@ -1131,6 +1138,19 @@ fn new(
let fresh_float_tys: Vec<_> =
(0..NUM_PREINTERNED_FRESH_FLOAT_TYS).map(|n| mk(Infer(ty::FreshFloatTy(n)))).collect();
+ let anon_bound_tys = (0..NUM_PREINTERNED_ANON_BOUND_TYS_I)
+ .map(|i| {
+ (0..NUM_PREINTERNED_ANON_BOUND_TYS_V)
+ .map(|v| {
+ mk(ty::Bound(
+ ty::DebruijnIndex::from(i),
+ ty::BoundTy { var: ty::BoundVar::from(v), kind: ty::BoundTyKind::Anon },
+ ))
+ })
+ .collect()
+ })
+ .collect();
+
CommonTypes {
unit: mk(Tuple(List::empty())),
bool: mk(Bool),
@@ -1161,6 +1181,7 @@ fn new(
fresh_tys,
fresh_int_tys,
fresh_float_tys,
+ anon_bound_tys,
}
}
}
@@ -1176,9 +1197,9 @@ fn new(interners: &CtxtInterners<'tcx>) -> CommonLifetimes<'tcx> {
let re_vars =
(0..NUM_PREINTERNED_RE_VARS).map(|n| mk(ty::ReVar(ty::RegionVid::from(n)))).collect();
- let re_late_bounds = (0..NUM_PREINTERNED_RE_LATE_BOUNDS_I)
+ let anon_re_bounds = (0..NUM_PREINTERNED_ANON_RE_BOUNDS_I)
.map(|i| {
- (0..NUM_PREINTERNED_RE_LATE_BOUNDS_V)
+ (0..NUM_PREINTERNED_ANON_RE_BOUNDS_V)
.map(|v| {
mk(ty::ReBound(
ty::DebruijnIndex::from(i),
@@ -1196,7 +1217,7 @@ fn new(interners: &CtxtInterners<'tcx>) -> CommonLifetimes<'tcx> {
re_static: mk(ty::ReStatic),
re_erased: mk(ty::ReErased),
re_vars,
- re_late_bounds,
+ anon_re_bounds,
}
}
}
@@ -3377,6 +3398,11 @@ pub fn module_children_local(self, def_id: LocalDefId) -> &'tcx [ModChild] {
self.resolutions(()).module_children.get(&def_id).map_or(&[], |v| &v[..])
}
+ /// Return the crate imported by given use item.
+ pub fn extern_mod_stmt_cnum(self, def_id: LocalDefId) -> Option<CrateNum> {
+ self.resolutions(()).extern_crate_map.get(&def_id).copied()
+ }
+
pub fn resolver_for_lowering(self) -> &'tcx Steal<(ty::ResolverAstLowering, Arc<ast::Crate>)> {
self.resolver_for_lowering_raw(()).0
}
@@ -3414,6 +3440,20 @@ pub fn needs_coroutine_by_move_body_def_id(self, def_id: DefId) -> bool {
pub fn do_not_recommend_impl(self, def_id: DefId) -> bool {
self.get_diagnostic_attr(def_id, sym::do_not_recommend).is_some()
}
+
+ /// Whether this def is one of the special bin crate entrypoint functions that must have a
+ /// monomorphization and also not be internalized in the bin crate.
+ pub fn is_entrypoint(self, def_id: DefId) -> bool {
+ if self.is_lang_item(def_id, LangItem::Start) {
+ return true;
+ }
+ if let Some((entry_def_id, _)) = self.entry_fn(())
+ && entry_def_id == def_id
+ {
+ return true;
+ }
+ false
+ }
}
/// Parameter attributes that can only be determined by examining the body of a function instead
@@ -3432,8 +3472,6 @@ pub struct DeducedParamAttrs {
}
pub fn provide(providers: &mut Providers) {
- providers.extern_mod_stmt_cnum =
- |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
providers.is_panic_runtime =
|tcx, LocalCrate| contains_name(tcx.hir_krate_attrs(), sym::panic_runtime);
providers.is_compiler_builtins =
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 8097175..aed94f9 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -107,8 +107,8 @@ fn repr_discr<'tcx>(
abi::Integer::I8
};
- // If there are no negative values, we can use the unsigned fit.
- if min >= 0 {
+ // Pick the smallest fit.
+ if unsigned_fit <= signed_fit {
(cmp::max(unsigned_fit, at_least), false)
} else {
(cmp::max(signed_fit, at_least), true)
@@ -1055,11 +1055,11 @@ fn ty_and_layout_pointee_info_at(
_ => Some(this),
};
- if let Some(variant) = data_variant {
+ if let Some(variant) = data_variant
// We're not interested in any unions.
- if let FieldsShape::Union(_) = variant.fields {
- data_variant = None;
- }
+ && let FieldsShape::Union(_) = variant.fields
+ {
+ data_variant = None;
}
let mut result = None;
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index a7cde2a..bb70c61 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1988,29 +1988,21 @@ pub fn trait_id_of_impl(self, def_id: DefId) -> Option<DefId> {
self.impl_trait_ref(def_id).map(|tr| tr.skip_binder().def_id)
}
- /// If the given `DefId` describes an item belonging to a trait,
- /// returns the `DefId` of the trait that the trait item belongs to;
- /// otherwise, returns `None`.
- pub fn trait_of_item(self, def_id: DefId) -> Option<DefId> {
- if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
- let parent = self.parent(def_id);
- if let DefKind::Trait | DefKind::TraitAlias = self.def_kind(parent) {
- return Some(parent);
- }
- }
- None
+ /// If the given `DefId` is an associated item, returns the `DefId` of the parent trait or impl.
+ pub fn assoc_parent(self, def_id: DefId) -> Option<DefId> {
+ self.def_kind(def_id).is_assoc().then(|| self.parent(def_id))
}
- /// If the given `DefId` describes a method belonging to an impl, returns the
- /// `DefId` of the impl that the method belongs to; otherwise, returns `None`.
- pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
- if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
- let parent = self.parent(def_id);
- if let DefKind::Impl { .. } = self.def_kind(parent) {
- return Some(parent);
- }
- }
- None
+ /// If the given `DefId` is an associated item of a trait,
+ /// returns the `DefId` of the trait; otherwise, returns `None`.
+ pub fn trait_of_assoc(self, def_id: DefId) -> Option<DefId> {
+ self.assoc_parent(def_id).filter(|id| self.def_kind(id) == DefKind::Trait)
+ }
+
+ /// If the given `DefId` is an associated item of an impl,
+ /// returns the `DefId` of the impl; otherwise returns `None`.
+ pub fn impl_of_assoc(self, def_id: DefId) -> Option<DefId> {
+ self.assoc_parent(def_id).filter(|id| matches!(self.def_kind(id), DefKind::Impl { .. }))
}
pub fn is_exportable(self, def_id: DefId) -> bool {
@@ -2024,7 +2016,10 @@ pub fn is_builtin_derived(self, def_id: DefId) -> bool {
&& let Some(def_id) = def_id.as_local()
&& let outer = self.def_span(def_id).ctxt().outer_expn_data()
&& matches!(outer.kind, ExpnKind::Macro(MacroKind::Derive, _))
- && self.has_attr(outer.macro_def_id.unwrap(), sym::rustc_builtin_macro)
+ && find_attr!(
+ self.get_all_attrs(outer.macro_def_id.unwrap()),
+ AttributeKind::RustcBuiltinMacro { .. }
+ )
{
true
} else {
@@ -2178,7 +2173,7 @@ pub fn is_const_trait(self, def_id: DefId) -> bool {
#[inline]
pub fn is_const_default_method(self, def_id: DefId) -> bool {
- matches!(self.trait_of_item(def_id), Some(trait_id) if self.is_const_trait(trait_id))
+ matches!(self.trait_of_assoc(def_id), Some(trait_id) if self.is_const_trait(trait_id))
}
pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 9ee64df..5c44b10 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -86,7 +86,7 @@ macro_rules! define_helper {
impl $helper {
pub fn new() -> $helper {
- $helper($tl.with(|c| c.replace(true)))
+ $helper($tl.replace(true))
}
}
@@ -100,12 +100,12 @@ pub fn new() -> $helper {
impl Drop for $helper {
fn drop(&mut self) {
- $tl.with(|c| c.set(self.0))
+ $tl.set(self.0)
}
}
pub fn $name() -> bool {
- $tl.with(|c| c.get())
+ $tl.get()
}
)+
}
@@ -225,10 +225,10 @@ pub fn maybe_highlighting_region(
region: Option<ty::Region<'tcx>>,
number: Option<usize>,
) {
- if let Some(k) = region {
- if let Some(n) = number {
- self.highlighting_region(k, n);
- }
+ if let Some(k) = region
+ && let Some(n) = number
+ {
+ self.highlighting_region(k, n);
}
}
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index 51be93d..5cf9607 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -54,7 +54,7 @@ pub fn new_bound(
) -> Region<'tcx> {
// Use a pre-interned one when possible.
if let ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon } = bound_region
- && let Some(inner) = tcx.lifetimes.re_late_bounds.get(debruijn.as_usize())
+ && let Some(inner) = tcx.lifetimes.anon_re_bounds.get(debruijn.as_usize())
&& let Some(re) = inner.get(var.as_usize()).copied()
{
re
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 8bb3b3f..4569596 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -485,7 +485,15 @@ pub fn new_bound(
index: ty::DebruijnIndex,
bound_ty: ty::BoundTy,
) -> Ty<'tcx> {
- Ty::new(tcx, Bound(index, bound_ty))
+ // Use a pre-interned one when possible.
+ if let ty::BoundTy { var, kind: ty::BoundTyKind::Anon } = bound_ty
+ && let Some(inner) = tcx.types.anon_bound_tys.get(index.as_usize())
+ && let Some(ty) = inner.get(var.as_usize()).copied()
+ {
+ ty
+ } else {
+ Ty::new(tcx, Bound(index, bound_ty))
+ }
}
#[inline]
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 174892c..a7d07ad 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -32,7 +32,7 @@
#[derive(Copy, Clone, Debug)]
pub struct Discr<'tcx> {
- /// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`).
+ /// Bit representation of the discriminant (e.g., `-1i8` is `0xFF_u128`).
pub val: u128,
pub ty: Ty<'tcx>,
}
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index e339520..abfe8eb 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -86,10 +86,16 @@
mir_build_const_continue_bad_const = could not determine the target branch for this `#[const_continue]`
.label = this value is too generic
- .note = the value must be a literal or a monomorphic const
mir_build_const_continue_missing_value = a `#[const_continue]` must break to a label with a value
+mir_build_const_continue_not_const = could not determine the target branch for this `#[const_continue]`
+ .help = try extracting the expression into a `const` item
+
+mir_build_const_continue_not_const_const_block = `const` blocks may use generics, and are not evaluated early enough
+mir_build_const_continue_not_const_const_other = this value must be a literal or a monomorphic const
+mir_build_const_continue_not_const_constant_parameter = constant parameters may use generics, and are not evaluated early enough
+
mir_build_const_continue_unknown_jump_target = the target of this `#[const_continue]` is not statically known
.label = this value must be a literal or a monomorphic const
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
index daf8fa5..a4ef6e9 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
@@ -1,6 +1,6 @@
//! See docs in `build/expr/mod.rs`.
-use rustc_abi::{BackendRepr, FieldIdx, Primitive};
+use rustc_abi::FieldIdx;
use rustc_hir::lang_items::LangItem;
use rustc_index::{Idx, IndexVec};
use rustc_middle::bug;
@@ -9,7 +9,6 @@
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::cast::{CastTy, mir_cast_kind};
-use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, Ty, UpvarArgs};
use rustc_span::source_map::Spanned;
@@ -200,8 +199,6 @@ pub(crate) fn as_rvalue(
{
let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx);
let temp = unpack!(block = this.as_temp(block, scope, source, Mutability::Not));
- let layout =
- this.tcx.layout_of(this.typing_env().as_query_input(source_expr.ty));
let discr = this.temp(discr_ty, source_expr.span);
this.cfg.push_assign(
block,
@@ -209,80 +206,7 @@ pub(crate) fn as_rvalue(
discr,
Rvalue::Discriminant(temp.into()),
);
- let (op, ty) = (Operand::Move(discr), discr_ty);
-
- if let BackendRepr::Scalar(scalar) = layout.unwrap().backend_repr
- && !scalar.is_always_valid(&this.tcx)
- && let Primitive::Int(int_width, _signed) = scalar.primitive()
- {
- let unsigned_ty = int_width.to_ty(this.tcx, false);
- let unsigned_place = this.temp(unsigned_ty, expr_span);
- this.cfg.push_assign(
- block,
- source_info,
- unsigned_place,
- Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr), unsigned_ty),
- );
-
- let bool_ty = this.tcx.types.bool;
- let range = scalar.valid_range(&this.tcx);
- let merge_op =
- if range.start <= range.end { BinOp::BitAnd } else { BinOp::BitOr };
-
- let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> {
- // We can use `ty::TypingEnv::fully_monomorphized()` here
- // as we only need it to compute the layout of a primitive.
- let range_val = Const::from_bits(
- this.tcx,
- range,
- ty::TypingEnv::fully_monomorphized(),
- unsigned_ty,
- );
- let lit_op = this.literal_operand(expr.span, range_val);
- let is_bin_op = this.temp(bool_ty, expr_span);
- this.cfg.push_assign(
- block,
- source_info,
- is_bin_op,
- Rvalue::BinaryOp(
- bin_op,
- Box::new((Operand::Copy(unsigned_place), lit_op)),
- ),
- );
- is_bin_op
- };
- let assert_place = if range.start == 0 {
- comparer(range.end, BinOp::Le)
- } else {
- let start_place = comparer(range.start, BinOp::Ge);
- let end_place = comparer(range.end, BinOp::Le);
- let merge_place = this.temp(bool_ty, expr_span);
- this.cfg.push_assign(
- block,
- source_info,
- merge_place,
- Rvalue::BinaryOp(
- merge_op,
- Box::new((
- Operand::Move(start_place),
- Operand::Move(end_place),
- )),
- ),
- );
- merge_place
- };
- this.cfg.push(
- block,
- Statement::new(
- source_info,
- StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
- Operand::Move(assert_place),
- ))),
- ),
- );
- }
-
- (op, ty)
+ (Operand::Move(discr), discr_ty)
} else {
let ty = source_expr.ty;
let source = unpack!(
diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs
index 12a56d7..1240b34 100644
--- a/compiler/rustc_mir_build/src/builder/scope.rs
+++ b/compiler/rustc_mir_build/src/builder/scope.rs
@@ -100,7 +100,9 @@
use super::matches::BuiltMatchTree;
use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
-use crate::errors::{ConstContinueBadConst, ConstContinueUnknownJumpTarget};
+use crate::errors::{
+ ConstContinueBadConst, ConstContinueNotMonomorphicConst, ConstContinueUnknownJumpTarget,
+};
#[derive(Debug)]
pub(crate) struct Scopes<'tcx> {
@@ -867,7 +869,8 @@ pub(crate) fn break_const_continuable_scope(
span_bug!(span, "break value must be a scope")
};
- let constant = match &self.thir[value].kind {
+ let expr = &self.thir[value];
+ let constant = match &expr.kind {
ExprKind::Adt(box AdtExpr { variant_index, fields, base, .. }) => {
assert!(matches!(base, AdtExprBase::None));
assert!(fields.is_empty());
@@ -887,7 +890,27 @@ pub(crate) fn break_const_continuable_scope(
),
}
}
- _ => self.as_constant(&self.thir[value]),
+
+ ExprKind::Literal { .. }
+ | ExprKind::NonHirLiteral { .. }
+ | ExprKind::ZstLiteral { .. }
+ | ExprKind::NamedConst { .. } => self.as_constant(&self.thir[value]),
+
+ other => {
+ use crate::errors::ConstContinueNotMonomorphicConstReason as Reason;
+
+ let span = expr.span;
+ let reason = match other {
+ ExprKind::ConstParam { .. } => Reason::ConstantParameter { span },
+ ExprKind::ConstBlock { .. } => Reason::ConstBlock { span },
+ _ => Reason::Other { span },
+ };
+
+ self.tcx
+ .dcx()
+ .emit_err(ConstContinueNotMonomorphicConst { span: expr.span, reason });
+ return block.unit();
+ }
};
let break_index = self
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 16b49bf..f1fbd5c 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1214,6 +1214,38 @@ pub(crate) struct LoopMatchArmWithGuard {
}
#[derive(Diagnostic)]
+#[diag(mir_build_const_continue_not_const)]
+#[help]
+pub(crate) struct ConstContinueNotMonomorphicConst {
+ #[primary_span]
+ pub span: Span,
+
+ #[subdiagnostic]
+ pub reason: ConstContinueNotMonomorphicConstReason,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum ConstContinueNotMonomorphicConstReason {
+ #[label(mir_build_const_continue_not_const_constant_parameter)]
+ ConstantParameter {
+ #[primary_span]
+ span: Span,
+ },
+
+ #[label(mir_build_const_continue_not_const_const_block)]
+ ConstBlock {
+ #[primary_span]
+ span: Span,
+ },
+
+ #[label(mir_build_const_continue_not_const_const_other)]
+ Other {
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(Diagnostic)]
#[diag(mir_build_const_continue_bad_const)]
pub(crate) struct ConstContinueBadConst {
#[primary_span]
diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs
index e858b62..57ddb8e 100644
--- a/compiler/rustc_mir_build/src/thir/cx/block.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/block.rs
@@ -76,28 +76,24 @@ fn mirror_stmts(
let mut pattern = self.pattern_from_hir(local.pat);
debug!(?pattern);
- if let Some(ty) = &local.ty {
- if let Some(&user_ty) =
+ if let Some(ty) = &local.ty
+ && let Some(&user_ty) =
self.typeck_results.user_provided_types().get(ty.hir_id)
- {
- debug!("mirror_stmts: user_ty={:?}", user_ty);
- let annotation = CanonicalUserTypeAnnotation {
- user_ty: Box::new(user_ty),
- span: ty.span,
- inferred_ty: self.typeck_results.node_type(ty.hir_id),
- };
- pattern = Box::new(Pat {
- ty: pattern.ty,
- span: pattern.span,
- kind: PatKind::AscribeUserType {
- ascription: Ascription {
- annotation,
- variance: ty::Covariant,
- },
- subpattern: pattern,
- },
- });
- }
+ {
+ debug!("mirror_stmts: user_ty={:?}", user_ty);
+ let annotation = CanonicalUserTypeAnnotation {
+ user_ty: Box::new(user_ty),
+ span: ty.span,
+ inferred_ty: self.typeck_results.node_type(ty.hir_id),
+ };
+ pattern = Box::new(Pat {
+ ty: pattern.ty,
+ span: pattern.span,
+ kind: PatKind::AscribeUserType {
+ ascription: Ascription { annotation, variance: ty::Covariant },
+ subpattern: pattern,
+ },
+ });
}
let span = match local.init {
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index b694409..16df58c 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -105,11 +105,11 @@ fn apply_adjustment(
// // ^ error message points at this expression.
// }
let mut adjust_span = |expr: &mut Expr<'tcx>| {
- if let ExprKind::Block { block } = expr.kind {
- if let Some(last_expr) = self.thir[block].expr {
- span = self.thir[last_expr].span;
- expr.span = span;
- }
+ if let ExprKind::Block { block } = expr.kind
+ && let Some(last_expr) = self.thir[block].expr
+ {
+ span = self.thir[last_expr].span;
+ expr.span = span;
}
};
@@ -955,21 +955,25 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
dcx.emit_fatal(LoopMatchBadRhs { span: block_body_expr.span })
};
- fn local(expr: &rustc_hir::Expr<'_>) -> Option<hir::HirId> {
- if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind {
- if let Res::Local(hir_id) = path.res {
- return Some(hir_id);
- }
+ fn local(
+ cx: &mut ThirBuildCx<'_>,
+ expr: &rustc_hir::Expr<'_>,
+ ) -> Option<hir::HirId> {
+ if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind
+ && let Res::Local(hir_id) = path.res
+ && !cx.is_upvar(hir_id)
+ {
+ return Some(hir_id);
}
None
}
- let Some(scrutinee_hir_id) = local(scrutinee) else {
+ let Some(scrutinee_hir_id) = local(self, scrutinee) else {
dcx.emit_fatal(LoopMatchInvalidMatch { span: scrutinee.span })
};
- if local(state) != Some(scrutinee_hir_id) {
+ if local(self, state) != Some(scrutinee_hir_id) {
dcx.emit_fatal(LoopMatchInvalidUpdate {
scrutinee: scrutinee.span,
lhs: state.span,
@@ -1260,10 +1264,7 @@ fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKi
fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'tcx> {
// We want upvars here not captures.
// Captures will be handled in MIR.
- let is_upvar = self
- .tcx
- .upvars_mentioned(self.body_owner)
- .is_some_and(|upvars| upvars.contains_key(&var_hir_id));
+ let is_upvar = self.is_upvar(var_hir_id);
debug!(
"convert_var({:?}): is_upvar={}, body_owner={:?}",
@@ -1443,6 +1444,12 @@ fn capture_upvar(
}
}
+ fn is_upvar(&mut self, var_hir_id: hir::HirId) -> bool {
+ self.tcx
+ .upvars_mentioned(self.body_owner)
+ .is_some_and(|upvars| upvars.contains_key(&var_hir_id))
+ }
+
/// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExpr.
fn field_refs(&mut self, fields: &'tcx [hir::ExprField<'tcx>]) -> Box<[FieldExpr]> {
fields
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 7f47754..ae67bb5 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1155,14 +1155,12 @@ fn find_fallback_pattern_typo<'tcx>(
}
hir::Node::Block(hir::Block { stmts, .. }) => {
for stmt in *stmts {
- if let hir::StmtKind::Let(let_stmt) = stmt.kind {
- if let hir::PatKind::Binding(_, _, binding_name, _) =
+ if let hir::StmtKind::Let(let_stmt) = stmt.kind
+ && let hir::PatKind::Binding(_, _, binding_name, _) =
let_stmt.pat.kind
- {
- if name == binding_name.name {
- lint.pattern_let_binding = Some(binding_name.span);
- }
- }
+ && name == binding_name.name
+ {
+ lint.pattern_let_binding = Some(binding_name.span);
}
}
}
diff --git a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
index c9c7fdd..1402a1a 100644
--- a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
+++ b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
@@ -124,10 +124,9 @@ pub fn drop_flag_effects_for_location<'tcx, F>(
// Drop does not count as a move but we should still consider the variable uninitialized.
if let Some(Terminator { kind: TerminatorKind::Drop { place, .. }, .. }) =
body.stmt_at(loc).right()
+ && let LookupResult::Exact(mpi) = move_data.rev_lookup.find(place.as_ref())
{
- if let LookupResult::Exact(mpi) = move_data.rev_lookup.find(place.as_ref()) {
- on_all_children_bits(move_data, mpi, |mpi| callback(mpi, DropFlagState::Absent))
- }
+ on_all_children_bits(move_data, mpi, |mpi| callback(mpi, DropFlagState::Absent))
}
debug!("drop_flag_effects: assignment for location({:?})", loc);
diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
index 085757f..117525e 100644
--- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
@@ -637,16 +637,13 @@ fn apply_primary_statement_effect(
debug!("initializes move_indexes {:?}", init_loc_map[location]);
state.gen_all(init_loc_map[location].iter().copied());
- if let mir::StatementKind::StorageDead(local) = stmt.kind {
+ if let mir::StatementKind::StorageDead(local) = stmt.kind
// End inits for StorageDead, so that an immutable variable can
// be reinitialized on the next iteration of the loop.
- if let Some(move_path_index) = rev_lookup.find_local(local) {
- debug!(
- "clears the ever initialized status of {:?}",
- init_path_map[move_path_index]
- );
- state.kill_all(init_path_map[move_path_index].iter().copied());
- }
+ && let Some(move_path_index) = rev_lookup.find_local(local)
+ {
+ debug!("clears the ever initialized status of {:?}", init_path_map[move_path_index]);
+ state.kill_all(init_path_map[move_path_index].iter().copied());
}
}
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 303fc76..1682f33 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -135,12 +135,11 @@ fn value_assigned_to_local<'a, 'tcx>(
stmt: &'a mir::Statement<'tcx>,
local: Local,
) -> Option<&'a mir::Rvalue<'tcx>> {
- if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
- if let Some(l) = place.as_local() {
- if local == l {
- return Some(&*rvalue);
- }
- }
+ if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind
+ && let Some(l) = place.as_local()
+ && local == l
+ {
+ return Some(&*rvalue);
}
None
@@ -178,31 +177,30 @@ fn from_terminator<'tcx>(
let span = terminator.source_info.span;
if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
&terminator.kind
+ && let ty::FnDef(def_id, fn_args) = *func.const_.ty().kind()
{
- if let ty::FnDef(def_id, fn_args) = *func.const_.ty().kind() {
- if tcx.intrinsic(def_id)?.name != sym::rustc_peek {
- return None;
- }
+ if tcx.intrinsic(def_id)?.name != sym::rustc_peek {
+ return None;
+ }
- assert_eq!(fn_args.len(), 1);
- let kind = PeekCallKind::from_arg_ty(fn_args.type_at(0));
- let arg = match &args[0].node {
- Operand::Copy(place) | Operand::Move(place) => {
- if let Some(local) = place.as_local() {
- local
- } else {
- tcx.dcx().emit_err(PeekMustBeNotTemporary { span });
- return None;
- }
- }
- _ => {
+ assert_eq!(fn_args.len(), 1);
+ let kind = PeekCallKind::from_arg_ty(fn_args.type_at(0));
+ let arg = match &args[0].node {
+ Operand::Copy(place) | Operand::Move(place) => {
+ if let Some(local) = place.as_local() {
+ local
+ } else {
tcx.dcx().emit_err(PeekMustBeNotTemporary { span });
return None;
}
- };
+ }
+ _ => {
+ tcx.dcx().emit_err(PeekMustBeNotTemporary { span });
+ return None;
+ }
+ };
- return Some(PeekCall { arg, kind, span });
- }
+ return Some(PeekCall { arg, kind, span });
}
None
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 83fd8cc..005e797 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -215,10 +215,10 @@ pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map:
// If both places are tracked, we copy the value to the target.
// If the target is tracked, but the source is not, we do nothing, as invalidation has
// already been performed.
- if let Some(target_value) = map.places[target].value_index {
- if let Some(source_value) = map.places[source].value_index {
- values.insert(target_value, values.get(source_value).clone());
- }
+ if let Some(target_value) = map.places[target].value_index
+ && let Some(source_value) = map.places[source].value_index
+ {
+ values.insert(target_value, values.get(source_value).clone());
}
for target_child in map.children(target) {
// Try to find corresponding child and recurse. Reasoning is similar as above.
diff --git a/compiler/rustc_mir_transform/src/check_call_recursion.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs
index cace4cd..6d61ac2 100644
--- a/compiler/rustc_mir_transform/src/check_call_recursion.rs
+++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs
@@ -21,7 +21,7 @@ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) {
// If this is trait/impl method, extract the trait's args.
- let trait_args = match tcx.trait_of_item(def_id.to_def_id()) {
+ let trait_args = match tcx.trait_of_assoc(def_id.to_def_id()) {
Some(trait_def_id) => {
let trait_args_count = tcx.generics_of(trait_def_id).count();
&GenericArgs::identity_for_item(tcx, def_id)[..trait_args_count]
@@ -44,7 +44,7 @@ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
// First check if `body` is an `fn drop()` of `Drop`
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))
+ tcx.impl_of_assoc(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(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()
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index e9b85ba..dcb812c 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -40,7 +40,7 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
if context.is_borrow() && util::is_disaligned(self.tcx, self.body, self.typing_env, *place)
{
let def_id = self.body.source.instance.def_id();
- if let Some(impl_def_id) = self.tcx.impl_of_method(def_id)
+ if let Some(impl_def_id) = self.tcx.impl_of_assoc(def_id)
&& self.tcx.is_builtin_derived(impl_def_id)
{
// If we ever reach here it means that the generated derive
diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs
index 406575c..1a314e0 100644
--- a/compiler/rustc_mir_transform/src/coroutine/drop.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs
@@ -23,10 +23,10 @@ fn visit_assign(
}
// Converting `_0 = Poll::<Rv>::Pending` to `_0 = Poll::<()>::Pending`
- if let Rvalue::Aggregate(kind, _) = rvalue {
- if let AggregateKind::Adt(_, _, ref mut args, _, _) = **kind {
- *args = self.tcx.mk_args(&[self.tcx.types.unit.into()]);
- }
+ if let Rvalue::Aggregate(kind, _) = rvalue
+ && let AggregateKind::Adt(_, _, ref mut args, _, _) = **kind
+ {
+ *args = self.tcx.mk_args(&[self.tcx.types.unit.into()]);
}
}
}
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index 986c001..73795e4 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -1,4 +1,4 @@
-use rustc_attr_data_structures::{AttributeKind, CoverageStatus, find_attr};
+use rustc_attr_data_structures::{AttributeKind, CoverageAttrKind, find_attr};
use rustc_index::bit_set::DenseBitSet;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::coverage::{BasicCoverageBlock, CoverageIdsInfo, CoverageKind, MappingKind};
@@ -32,16 +32,6 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
return false;
}
- // Don't instrument functions with `#[automatically_derived]` on their
- // enclosing impl block, on the assumption that most users won't care about
- // coverage for derived impls.
- if let Some(impl_of) = tcx.impl_of_method(def_id.to_def_id())
- && tcx.is_automatically_derived(impl_of)
- {
- trace!("InstrumentCoverage skipped for {def_id:?} (automatically derived)");
- return false;
- }
-
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NAKED) {
trace!("InstrumentCoverage skipped for {def_id:?} (`#[naked]`)");
return false;
@@ -57,20 +47,32 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
/// Query implementation for `coverage_attr_on`.
fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
- // Check for annotations directly on this def.
- if let Some(coverage_status) =
- find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Coverage(_, status) => status)
+ // Check for a `#[coverage(..)]` attribute on this def.
+ if let Some(kind) =
+ find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Coverage(_sp, kind) => kind)
{
- *coverage_status == CoverageStatus::On
- } else {
- match tcx.opt_local_parent(def_id) {
- // Check the parent def (and so on recursively) until we find an
- // enclosing attribute or reach the crate root.
- Some(parent) => tcx.coverage_attr_on(parent),
- // We reached the crate root without seeing a coverage attribute, so
- // allow coverage instrumentation by default.
- None => true,
+ match kind {
+ CoverageAttrKind::On => return true,
+ CoverageAttrKind::Off => return false,
}
+ };
+
+ // Treat `#[automatically_derived]` as an implied `#[coverage(off)]`, on
+ // the assumption that most users won't want coverage for derived impls.
+ //
+ // This affects not just the associated items of an impl block, but also
+ // any closures and other nested functions within those associated items.
+ if tcx.is_automatically_derived(def_id.to_def_id()) {
+ return false;
+ }
+
+ // Check the parent def (and so on recursively) until we find an
+ // enclosing attribute or reach the crate root.
+ match tcx.opt_local_parent(def_id) {
+ Some(parent) => tcx.coverage_attr_on(parent),
+ // We reached the crate root without seeing a coverage attribute, so
+ // allow coverage instrumentation by default.
+ None => true,
}
}
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index ddeae09..ec76076 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -1,8 +1,7 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::mir;
use rustc_middle::ty::TyCtxt;
-use rustc_span::source_map::SourceMap;
-use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span};
+use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span};
use tracing::instrument;
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
@@ -84,18 +83,8 @@ pub(super) fn extract_refined_covspans<'tcx>(
// Discard any span that overlaps with a hole.
discard_spans_overlapping_holes(&mut covspans, &holes);
- // Discard spans that overlap in unwanted ways.
+ // Perform more refinement steps after holes have been dealt with.
let mut covspans = remove_unwanted_overlapping_spans(covspans);
-
- // For all empty spans, either enlarge them to be non-empty, or discard them.
- let source_map = tcx.sess.source_map();
- covspans.retain_mut(|covspan| {
- let Some(span) = ensure_non_empty_span(source_map, covspan.span) else { return false };
- covspan.span = span;
- true
- });
-
- // Merge covspans that can be merged.
covspans.dedup_by(|b, a| a.merge_if_eligible(b));
code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| {
@@ -241,26 +230,3 @@ fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering {
// - Both have the same start and span A extends further right
.then_with(|| Ord::cmp(&a.hi(), &b.hi()).reverse())
}
-
-fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> {
- if !span.is_empty() {
- return Some(span);
- }
-
- // The span is empty, so try to enlarge it to cover an adjacent '{' or '}'.
- source_map
- .span_to_source(span, |src, start, end| try {
- // Adjusting span endpoints by `BytePos(1)` is normally a bug,
- // but in this case we have specifically checked that the character
- // we're skipping over is one of two specific ASCII characters, so
- // adjusting by exactly 1 byte is correct.
- if src.as_bytes().get(end).copied() == Some(b'{') {
- Some(span.with_hi(span.hi() + BytePos(1)))
- } else if start > 0 && src.as_bytes()[start - 1] == b'}' {
- Some(span.with_lo(span.lo() - BytePos(1)))
- } else {
- None
- }
- })
- .ok()?
-}
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index dbcaed2..c83bd25 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -55,6 +55,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let terminator = block.terminator.as_mut().unwrap();
ctx.simplify_primitive_clone(terminator, &mut block.statements);
+ ctx.simplify_align_of_slice_val(terminator, &mut block.statements);
ctx.simplify_intrinsic_assert(terminator);
ctx.simplify_nounwind_call(terminator);
simplify_duplicate_switch_targets(terminator);
@@ -252,6 +253,36 @@ fn simplify_primitive_clone(
terminator.kind = TerminatorKind::Goto { target: *destination_block };
}
+ // Convert `align_of_val::<[T]>(ptr)` to `align_of::<T>()`, since the
+ // alignment of a slice doesn't actually depend on metadata at all
+ // and the element type is always `Sized`.
+ //
+ // This is here so it can run after inlining, where it's more useful.
+ // (LowerIntrinsics is done in cleanup, before the optimization passes.)
+ fn simplify_align_of_slice_val(
+ &self,
+ terminator: &mut Terminator<'tcx>,
+ statements: &mut Vec<Statement<'tcx>>,
+ ) {
+ if let TerminatorKind::Call {
+ func, args, destination, target: Some(destination_block), ..
+ } = &terminator.kind
+ && args.len() == 1
+ && let Some((fn_def_id, generics)) = func.const_fn_def()
+ && self.tcx.is_intrinsic(fn_def_id, sym::align_of_val)
+ && let ty::Slice(elem_ty) = *generics.type_at(0).kind()
+ {
+ statements.push(Statement::new(
+ terminator.source_info,
+ StatementKind::Assign(Box::new((
+ *destination,
+ Rvalue::NullaryOp(NullOp::AlignOf, elem_ty),
+ ))),
+ ));
+ terminator.kind = TerminatorKind::Goto { target: *destination_block };
+ }
+ }
+
fn simplify_nounwind_call(&self, terminator: &mut Terminator<'tcx>) {
let TerminatorKind::Call { ref func, ref mut unwind, .. } = terminator.kind else {
return;
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 4e8f30e..462ddfa 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -997,12 +997,11 @@ fn promote_candidates<'tcx>(
for candidate in candidates.into_iter().rev() {
let Location { block, statement_index } = candidate.location;
if let StatementKind::Assign(box (place, _)) = &body[block].statements[statement_index].kind
+ && let Some(local) = place.as_local()
{
- if let Some(local) = place.as_local() {
- if temps[local] == TempState::PromotedOut {
- // Already promoted.
- continue;
- }
+ if temps[local] == TempState::PromotedOut {
+ // Already promoted.
+ continue;
}
}
@@ -1066,11 +1065,11 @@ fn promote_candidates<'tcx>(
_ => true,
});
let terminator = block.terminator_mut();
- if let TerminatorKind::Drop { place, target, .. } = &terminator.kind {
- if let Some(index) = place.as_local() {
- if promoted(index) {
- terminator.kind = TerminatorKind::Goto { target: *target };
- }
+ if let TerminatorKind::Drop { place, target, .. } = &terminator.kind
+ && let Some(index) = place.as_local()
+ {
+ if promoted(index) {
+ terminator.kind = TerminatorKind::Goto { target: *target };
}
}
}
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 797056a..5b6d7ff 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -48,14 +48,13 @@ fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect();
for bb in postorder {
debug!(" processing {:?}", bb);
- if let Some(unwind) = body[bb].terminator_mut().unwind_mut() {
- if let UnwindAction::Cleanup(unwind_bb) = *unwind {
- if nop_landing_pads.contains(unwind_bb) {
- debug!(" removing noop landing pad");
- landing_pads_removed += 1;
- *unwind = UnwindAction::Continue;
- }
- }
+ if let Some(unwind) = body[bb].terminator_mut().unwind_mut()
+ && let UnwindAction::Cleanup(unwind_bb) = *unwind
+ && nop_landing_pads.contains(unwind_bb)
+ {
+ debug!(" removing noop landing pad");
+ landing_pads_removed += 1;
+ *unwind = UnwindAction::Continue;
}
body[bb].terminator_mut().successors_mut(|target| {
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 6c65b07..c687036 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -75,7 +75,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
build_call_shim(tcx, instance, Some(adjustment), CallKind::Direct(def_id))
}
ty::InstanceKind::FnPtrShim(def_id, ty) => {
- let trait_ = tcx.trait_of_item(def_id).unwrap();
+ let trait_ = tcx.trait_of_assoc(def_id).unwrap();
// Supports `Fn` or `async Fn` traits.
let adjustment = match tcx
.fn_trait_kind_from_def_id(trait_)
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 7c6ccc8..80c4b58 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -1,4 +1,4 @@
-use rustc_abi::{FIRST_VARIANT, FieldIdx};
+use rustc_abi::FieldIdx;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_hir::LangItem;
use rustc_index::IndexVec;
@@ -32,7 +32,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let typing_env = body.typing_env(tcx);
loop {
debug!(?excluded);
- let escaping = escaping_locals(tcx, typing_env, &excluded, body);
+ let escaping = escaping_locals(tcx, &excluded, body);
debug!(?escaping);
let replacements = compute_flattening(tcx, typing_env, body, escaping);
debug!(?replacements);
@@ -64,7 +64,6 @@ fn is_required(&self) -> bool {
/// client code.
fn escaping_locals<'tcx>(
tcx: TyCtxt<'tcx>,
- typing_env: ty::TypingEnv<'tcx>,
excluded: &DenseBitSet<Local>,
body: &Body<'tcx>,
) -> DenseBitSet<Local> {
@@ -72,31 +71,12 @@ fn escaping_locals<'tcx>(
if ty.is_union() || ty.is_enum() {
return true;
}
- if let ty::Adt(def, _args) = ty.kind() {
- if def.repr().simd() {
- // Exclude #[repr(simd)] types so that they are not de-optimized into an array
- return true;
- }
- if tcx.is_lang_item(def.did(), LangItem::DynMetadata) {
- // codegen wants to see the `DynMetadata<T>`,
- // not the inner reference-to-opaque-type.
- return true;
- }
- // We already excluded unions and enums, so this ADT must have one variant
- let variant = def.variant(FIRST_VARIANT);
- if variant.fields.len() > 1 {
- // If this has more than one field, it cannot be a wrapper that only provides a
- // niche, so we do not want to automatically exclude it.
- return false;
- }
- let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) else {
- // We can't get the layout
- return true;
- };
- if layout.layout.largest_niche().is_some() {
- // This type has a niche
- return true;
- }
+ if let ty::Adt(def, _args) = ty.kind()
+ && tcx.is_lang_item(def.did(), LangItem::DynMetadata)
+ {
+ // codegen wants to see the `DynMetadata<T>`,
+ // not the inner reference-to-opaque-type.
+ return true;
}
// Default for non-ADTs
false
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 5860072..98d12bf 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -80,15 +80,14 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
cfg_checker.fail(location, msg);
}
- if let MirPhase::Runtime(_) = body.phase {
- if let ty::InstanceKind::Item(_) = body.source.instance {
- if body.has_free_regions() {
- cfg_checker.fail(
- Location::START,
- format!("Free regions in optimized {} MIR", body.phase.name()),
- );
- }
- }
+ if let MirPhase::Runtime(_) = body.phase
+ && let ty::InstanceKind::Item(_) = body.source.instance
+ && body.has_free_regions()
+ {
+ cfg_checker.fail(
+ Location::START,
+ format!("Free regions in optimized {} MIR", body.phase.name()),
+ );
}
}
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index d435e4e..1bfd83d 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1575,6 +1575,15 @@ fn push_extra_entry_roots(&mut self) {
return;
};
+ let main_instance = Instance::mono(self.tcx, main_def_id);
+ if self.tcx.should_codegen_locally(main_instance) {
+ self.output.push(create_fn_mono_item(
+ self.tcx,
+ main_instance,
+ self.tcx.def_span(main_def_id),
+ ));
+ }
+
let Some(start_def_id) = self.tcx.lang_items().start_fn() else {
self.tcx.dcx().emit_fatal(errors::StartNotFound);
};
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 6985151..cee15e0 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -223,11 +223,7 @@ fn place_mono_items<'tcx, I>(cx: &PartitioningCx<'_, 'tcx>, mono_items: I) -> Pl
// So even if its mode is LocalCopy, we need to treat it like a root.
match mono_item.instantiation_mode(cx.tcx) {
InstantiationMode::GloballyShared { .. } => {}
- InstantiationMode::LocalCopy => {
- if !cx.tcx.is_lang_item(mono_item.def_id(), LangItem::Start) {
- continue;
- }
- }
+ InstantiationMode::LocalCopy => continue,
}
let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item);
@@ -654,13 +650,13 @@ fn characteristic_def_id_of_mono_item<'tcx>(
// its self-type. If the self-type does not provide a characteristic
// DefId, we use the location of the impl after all.
- if tcx.trait_of_item(def_id).is_some() {
+ if tcx.trait_of_assoc(def_id).is_some() {
let self_ty = instance.args.type_at(0);
// This is a default implementation of a trait method.
return characteristic_def_id_of_type(self_ty).or(Some(def_id));
}
- if let Some(impl_def_id) = tcx.impl_of_method(def_id) {
+ if let Some(impl_def_id) = tcx.impl_of_assoc(def_id) {
if tcx.sess.opts.incremental.is_some()
&& tcx
.trait_id_of_impl(impl_def_id)
@@ -821,10 +817,9 @@ fn mono_item_visibility<'tcx>(
| InstanceKind::FnPtrAddrShim(..) => return Visibility::Hidden,
};
- // The `start_fn` lang item is actually a monomorphized instance of a
- // function in the standard library, used for the `main` function. We don't
- // want to export it so we tag it with `Hidden` visibility but this symbol
- // is only referenced from the actual `main` symbol which we unfortunately
+ // Both the `start_fn` lang item and `main` itself should not be exported,
+ // so we give them with `Hidden` visibility but these symbols are
+ // only referenced from the actual `main` symbol which we unfortunately
// don't know anything about during partitioning/collection. As a result we
// forcibly keep this symbol out of the `internalization_candidates` set.
//
@@ -834,7 +829,7 @@ fn mono_item_visibility<'tcx>(
// from the `main` symbol we'll generate later.
//
// This may be fixable with a new `InstanceKind` perhaps? Unsure!
- if tcx.is_lang_item(def_id, LangItem::Start) {
+ if tcx.is_entrypoint(def_id) {
*can_be_internalized = false;
return Visibility::Hidden;
}
@@ -1183,12 +1178,11 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitio
let autodiff_items = tcx.arena.alloc_from_iter(autodiff_items);
// Output monomorphization stats per def_id
- if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats {
- if let Err(err) =
+ if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats
+ && let Err(err) =
dump_mono_items_stats(tcx, codegen_units, path, tcx.crate_name(LOCAL_CRATE))
- {
- tcx.dcx().emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
- }
+ {
+ tcx.dcx().emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
}
if tcx.sess.opts.unstable_opts.print_mono_items {
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 c281ef2..b2d4014 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -10,8 +10,8 @@
use rustc_type_ir::lang_items::TraitSolverLangItem;
use rustc_type_ir::solve::SizedTraitKind;
use rustc_type_ir::{
- self as ty, Interner, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _,
- TypeVisitor, TypingMode, Upcast as _, elaborate,
+ self as ty, Interner, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable,
+ TypeVisitableExt as _, TypeVisitor, TypingMode, Upcast as _, elaborate,
};
use tracing::{debug, instrument};
@@ -132,6 +132,7 @@ fn probe_and_consider_param_env_candidate(
})
.enter(|ecx| {
Self::match_assumption(ecx, goal, assumption, |ecx| {
+ ecx.try_evaluate_added_goals()?;
source.set(ecx.characterize_param_env_assumption(goal.param_env, assumption)?);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
@@ -1069,8 +1070,10 @@ fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
} else {
ControlFlow::Continue(())
}
- } else {
+ } else if ty.has_type_flags(TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_RE_INFER) {
ty.super_visit_with(self)
+ } else {
+ ControlFlow::Continue(())
}
}
@@ -1086,8 +1089,10 @@ fn visit_const(&mut self, ct: I::Const) -> Self::Result {
} else {
ControlFlow::Continue(())
}
- } else {
+ } else if ct.has_type_flags(TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_RE_INFER) {
ct.super_visit_with(self)
+ } else {
+ ControlFlow::Continue(())
}
}
diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml
index a92012f..88f9378 100644
--- a/compiler/rustc_parse/Cargo.toml
+++ b/compiler/rustc_parse/Cargo.toml
@@ -9,6 +9,7 @@
rustc-literal-escaper = "0.0.5"
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
+rustc_attr_parsing = { path = "../rustc_attr_parsing" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 3d89530..54d8a79 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -785,9 +785,13 @@ fn parse_assoc_op_cast(
ExprKind::Call(_, _) => "a function call",
ExprKind::Await(_, _) => "`.await`",
ExprKind::Use(_, _) => "`.use`",
+ ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`",
ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
ExprKind::Err(_) => return Ok(with_postfix),
- _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
+ _ => unreachable!(
+ "did not expect {:?} as an illegal postfix operator following cast",
+ with_postfix.kind
+ ),
}
);
let mut err = self.dcx().struct_span_err(span, msg);
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index b767b0f..65d84b3 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1973,21 +1973,21 @@ fn parse_single_struct_field(
format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token));
// Try to recover extra trailing angle brackets
- if let TyKind::Path(_, Path { segments, .. }) = &a_var.ty.kind {
- if let Some(last_segment) = segments.last() {
- let guar = self.check_trailing_angle_brackets(
- last_segment,
- &[exp!(Comma), exp!(CloseBrace)],
- );
- if let Some(_guar) = guar {
- // Handle a case like `Vec<u8>>,` where we can continue parsing fields
- // after the comma
- let _ = self.eat(exp!(Comma));
+ if let TyKind::Path(_, Path { segments, .. }) = &a_var.ty.kind
+ && let Some(last_segment) = segments.last()
+ {
+ let guar = self.check_trailing_angle_brackets(
+ last_segment,
+ &[exp!(Comma), exp!(CloseBrace)],
+ );
+ if let Some(_guar) = guar {
+ // Handle a case like `Vec<u8>>,` where we can continue parsing fields
+ // after the comma
+ let _ = self.eat(exp!(Comma));
- // `check_trailing_angle_brackets` already emitted a nicer error, as
- // proven by the presence of `_guar`. We can continue parsing.
- return Ok(a_var);
- }
+ // `check_trailing_angle_brackets` already emitted a nicer error, as
+ // proven by the presence of `_guar`. We can continue parsing.
+ return Ok(a_var);
}
}
@@ -3034,18 +3034,16 @@ pub(super) fn parse_param_general(
if let Ok(t) = &ty {
// Check for trailing angle brackets
- if let TyKind::Path(_, Path { segments, .. }) = &t.kind {
- if let Some(segment) = segments.last() {
- if let Some(guar) =
- this.check_trailing_angle_brackets(segment, &[exp!(CloseParen)])
- {
- return Ok((
- dummy_arg(segment.ident, guar),
- Trailing::No,
- UsePreAttrPos::No,
- ));
- }
- }
+ if let TyKind::Path(_, Path { segments, .. }) = &t.kind
+ && let Some(segment) = segments.last()
+ && let Some(guar) =
+ this.check_trailing_angle_brackets(segment, &[exp!(CloseParen)])
+ {
+ return Ok((
+ dummy_arg(segment.ident, guar),
+ Trailing::No,
+ UsePreAttrPos::No,
+ ));
}
if this.token != token::Comma && this.token != token::CloseParen {
diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs
index 15679d2..43a1d77 100644
--- a/compiler/rustc_parse/src/parser/tests.rs
+++ b/compiler/rustc_parse/src/parser/tests.rs
@@ -2114,15 +2114,15 @@ fn foo() {
error: foo
--> test.rs:3:6
|
-3 | X0 Y0 Z0
+ 3 | X0 Y0 Z0
| _______^
-4 | | X1 Y1 Z1
+ 4 | | X1 Y1 Z1
| | ____^____-
| ||____|
| | `X` is a good letter
-5 | | 1
-6 | | 2
-7 | | 3
+ 5 | | 1
+ 6 | | 2
+ 7 | | 3
... |
15 | | X2 Y2 Z2
16 | | X3 Y3 Z3
@@ -2133,15 +2133,15 @@ fn foo() {
error: foo
╭▸ test.rs:3:6
│
-3 │ X0 Y0 Z0
+ 3 │ X0 Y0 Z0
│ ┏━━━━━━━┛
-4 │ ┃ X1 Y1 Z1
+ 4 │ ┃ X1 Y1 Z1
│ ┃┌────╿────┘
│ ┗│━━━━┥
│ │ `X` is a good letter
-5 │ │ 1
-6 │ │ 2
-7 │ │ 3
+ 5 │ │ 1
+ 6 │ │ 2
+ 7 │ │ 3
‡ │
15 │ │ X2 Y2 Z2
16 │ │ X3 Y3 Z3
@@ -2189,15 +2189,15 @@ fn foo() {
error: foo
--> test.rs:3:6
|
-3 | X0 Y0 Z0
+ 3 | X0 Y0 Z0
| _______^
-4 | | 1
-5 | | 2
-6 | | 3
-7 | | X1 Y1 Z1
+ 4 | | 1
+ 5 | | 2
+ 6 | | 3
+ 7 | | X1 Y1 Z1
| | _________-
-8 | || 4
-9 | || 5
+ 8 | || 4
+ 9 | || 5
10 | || 6
11 | || X2 Y2 Z2
| ||__________- `Z` is a good letter too
@@ -2211,15 +2211,15 @@ fn foo() {
error: foo
╭▸ test.rs:3:6
│
-3 │ X0 Y0 Z0
+ 3 │ X0 Y0 Z0
│ ┏━━━━━━━┛
-4 │ ┃ 1
-5 │ ┃ 2
-6 │ ┃ 3
-7 │ ┃ X1 Y1 Z1
+ 4 │ ┃ 1
+ 5 │ ┃ 2
+ 6 │ ┃ 3
+ 7 │ ┃ X1 Y1 Z1
│ ┃┌─────────┘
-8 │ ┃│ 4
-9 │ ┃│ 5
+ 8 │ ┃│ 4
+ 9 │ ┃│ 5
10 │ ┃│ 6
11 │ ┃│ X2 Y2 Z2
│ ┃└──────────┘ `Z` is a good letter too
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index ed7fb77..bc4c605 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -1,11 +1,14 @@
//! Meta-syntax validation logic of attributes for post-expansion.
+use std::slice;
+
use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::{
self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, NodeId,
Path, Safety,
};
+use rustc_attr_parsing::{AttributeParser, Late};
use rustc_errors::{Applicability, DiagCtxtHandle, FatalError, PResult};
use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
use rustc_session::errors::report_lit_error;
@@ -266,64 +269,7 @@ pub fn check_builtin_meta_item(
) {
if !is_attr_template_compatible(&template, &meta.kind) {
// attrs with new parsers are locally validated so excluded here
- if matches!(
- name,
- sym::inline
- | sym::export_stable
- | sym::ffi_const
- | sym::ffi_pure
- | sym::rustc_std_internal_symbol
- | sym::may_dangle
- | sym::rustc_as_ptr
- | sym::rustc_pub_transparent
- | sym::rustc_const_stable_indirect
- | sym::rustc_force_inline
- | sym::rustc_confusables
- | sym::rustc_skip_during_method_dispatch
- | sym::rustc_pass_by_value
- | sym::rustc_deny_explicit_impl
- | sym::rustc_do_not_implement_via_object
- | sym::rustc_coinductive
- | sym::const_trait
- | sym::rustc_specialization_trait
- | sym::rustc_unsafe_specialization_marker
- | sym::rustc_allow_incoherent_impl
- | sym::rustc_coherence_is_core
- | sym::marker
- | sym::fundamental
- | sym::rustc_paren_sugar
- | sym::type_const
- | sym::repr
- // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres
- // ambiguity
- | sym::rustc_align
- | sym::deprecated
- | sym::optimize
- | sym::pointee
- | sym::cold
- | sym::target_feature
- | sym::rustc_allow_const_fn_unstable
- | sym::macro_use
- | sym::macro_escape
- | sym::naked
- | sym::no_mangle
- | sym::non_exhaustive
- | sym::omit_gdb_pretty_printer_section
- | sym::path
- | sym::ignore
- | sym::must_use
- | sym::track_caller
- | sym::link_name
- | sym::link_ordinal
- | sym::export_name
- | sym::rustc_macro_transparency
- | sym::link_section
- | sym::rustc_layout_scalar_valid_range_start
- | sym::rustc_layout_scalar_valid_range_end
- | sym::no_implicit_prelude
- | sym::automatically_derived
- | sym::coverage
- ) {
+ if AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(&name)) {
return;
}
emit_malformed_attribute(psess, style, meta.span, name, template);
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 04c1933..0b329cc 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -130,6 +130,22 @@ fn check_attributes(
for attr in attrs {
let mut style = None;
match attr {
+ Attribute::Parsed(AttributeKind::ProcMacro(_)) => {
+ self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
+ }
+ Attribute::Parsed(AttributeKind::ProcMacroAttribute(_)) => {
+ self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
+ }
+ Attribute::Parsed(AttributeKind::ProcMacroDerive { span: attr_span, .. }) => {
+ self.check_generic_attr(
+ hir_id,
+ sym::proc_macro_derive,
+ *attr_span,
+ target,
+ Target::Fn,
+ );
+ self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
+ }
Attribute::Parsed(
AttributeKind::SkipDuringMethodDispatch { span: attr_span, .. }
| AttributeKind::Coinductive(attr_span)
@@ -275,6 +291,7 @@ fn check_attributes(
| AttributeKind::MacroTransparency(_)
| AttributeKind::Pointee(..)
| AttributeKind::Dummy
+ | AttributeKind::RustcBuiltinMacro { .. }
| AttributeKind::OmitGdbPrettyPrinterSection,
) => { /* do nothing */ }
Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => {
@@ -373,16 +390,6 @@ fn check_attributes(
[sym::should_panic, ..] => {
self.check_generic_attr_unparsed(hir_id, attr, target, Target::Fn)
}
- [sym::proc_macro, ..] => {
- self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
- }
- [sym::proc_macro_attribute, ..] => {
- self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
- }
- [sym::proc_macro_derive, ..] => {
- self.check_generic_attr_unparsed(hir_id, attr, target, Target::Fn);
- self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
- }
[sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => {
self.check_autodiff(hir_id, attr, span, target)
}
@@ -1258,7 +1265,7 @@ fn check_doc_masked(
return;
}
- if self.tcx.extern_mod_stmt_cnum(hir_id.owner).is_none() {
+ if self.tcx.extern_mod_stmt_cnum(hir_id.owner.def_id).is_none() {
self.tcx.emit_node_span_lint(
INVALID_DOC_ATTRIBUTES,
hir_id,
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index d987041..a90d1af 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -368,7 +368,7 @@ fn mark_live_symbols(&mut self) {
/// will be ignored for the purposes of dead code analysis (see PR #85200
/// for discussion).
fn should_ignore_item(&mut self, def_id: DefId) -> bool {
- if let Some(impl_of) = self.tcx.impl_of_method(def_id) {
+ if let Some(impl_of) = self.tcx.impl_of_assoc(def_id) {
if !self.tcx.is_automatically_derived(impl_of) {
return false;
}
@@ -429,7 +429,7 @@ fn visit_node(&mut self, node: Node<'tcx>) {
Node::TraitItem(trait_item) => {
// mark the trait live
let trait_item_id = trait_item.owner_id.to_def_id();
- if let Some(trait_id) = self.tcx.trait_of_item(trait_item_id) {
+ if let Some(trait_id) = self.tcx.trait_of_assoc(trait_item_id) {
self.check_def_id(trait_id);
}
intravisit::walk_trait_item(self, trait_item);
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index b49e811..2f78c22 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -104,10 +104,10 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
fn visit_inline_asm(&mut self, asm: &'tcx hir::InlineAsm<'tcx>, id: hir::HirId) {
for (op, _) in asm.operands {
- if let hir::InlineAsmOperand::SymStatic { def_id, .. } = op {
- if let Some(def_id) = def_id.as_local() {
- self.reachable_symbols.insert(def_id);
- }
+ if let hir::InlineAsmOperand::SymStatic { def_id, .. } = op
+ && let Some(def_id) = def_id.as_local()
+ {
+ self.reachable_symbols.insert(def_id);
}
}
intravisit::walk_inline_asm(self, asm, id);
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 40999d6..9ed7293 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -929,10 +929,10 @@ struct CheckTraitImplStable<'tcx> {
impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: hir::HirId) {
- if let Some(def_id) = path.res.opt_def_id() {
- if let Some(stab) = self.tcx.lookup_stability(def_id) {
- self.fully_stable &= stab.level.is_stable();
- }
+ if let Some(def_id) = path.res.opt_def_id()
+ && let Some(stab) = self.tcx.lookup_stability(def_id)
+ {
+ self.fully_stable &= stab.level.is_stable();
}
intravisit::walk_path(self, path)
}
@@ -1055,10 +1055,10 @@ fn check_features<'tcx>(
// implications from this crate.
remaining_implications.remove(&feature);
- if let FeatureStability::Unstable { old_name: Some(alias) } = stability {
- if let Some(span) = remaining_lib_features.swap_remove(&alias) {
- tcx.dcx().emit_err(errors::RenamedFeature { span, feature, alias });
- }
+ if let FeatureStability::Unstable { old_name: Some(alias) } = stability
+ && let Some(span) = remaining_lib_features.swap_remove(&alias)
+ {
+ tcx.dcx().emit_err(errors::RenamedFeature { span, feature, alias });
}
if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
diff --git a/compiler/rustc_passes/src/upvars.rs b/compiler/rustc_passes/src/upvars.rs
index fae88fb..88f2029 100644
--- a/compiler/rustc_passes/src/upvars.rs
+++ b/compiler/rustc_passes/src/upvars.rs
@@ -75,19 +75,19 @@ fn visit_path(&mut self, path: &hir::Path<'tcx>, _: HirId) {
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
- if let hir::ExprKind::Closure(closure) = expr.kind {
- if let Some(upvars) = self.tcx.upvars_mentioned(closure.def_id) {
- // Every capture of a closure expression is a local in scope,
- // that is moved/copied/borrowed into the closure value, and
- // for this analysis they are like any other access to a local.
- //
- // E.g. in `|b| |c| (a, b, c)`, the upvars of the inner closure
- // are `a` and `b`, and while `a` is not directly used in the
- // outer closure, it needs to be an upvar there too, so that
- // the inner closure can take it (from the outer closure's env).
- for (&var_id, upvar) in upvars {
- self.visit_local_use(var_id, upvar.span);
- }
+ if let hir::ExprKind::Closure(closure) = expr.kind
+ && let Some(upvars) = self.tcx.upvars_mentioned(closure.def_id)
+ {
+ // Every capture of a closure expression is a local in scope,
+ // that is moved/copied/borrowed into the closure value, and
+ // for this analysis they are like any other access to a local.
+ //
+ // E.g. in `|b| |c| (a, b, c)`, the upvars of the inner closure
+ // are `a` and `b`, and while `a` is not directly used in the
+ // outer closure, it needs to be an upvar there too, so that
+ // the inner closure can take it (from the outer closure's env).
+ for (&var_id, upvar) in upvars {
+ self.visit_local_use(var_id, upvar.span);
}
}
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index 0968564..9a9e0db 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -950,9 +950,7 @@ pub(crate) fn fmt_fields(
}
}
Never => write!(f, "!")?,
- Wildcard | Missing | NonExhaustive | Hidden | PrivateUninhabited => {
- write!(f, "_ : {:?}", ty)?
- }
+ Wildcard | Missing | NonExhaustive | Hidden | PrivateUninhabited => write!(f, "_")?,
}
Ok(())
}
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 66df35f..d9bb93a 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -57,6 +57,13 @@ pub trait PatCx: Sized + fmt::Debug {
fn is_exhaustive_patterns_feature_on(&self) -> bool;
+ /// Whether to ensure the non-exhaustiveness witnesses we report for a complete set. This is
+ /// `false` by default to avoid some exponential blowup cases such as
+ /// <https://github.com/rust-lang/rust/issues/118437>.
+ fn exhaustive_witnesses(&self) -> bool {
+ false
+ }
+
/// The number of fields for this constructor.
fn ctor_arity(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> usize;
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index b1c646e..19446a1 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -994,7 +994,8 @@ fn split_column_ctors<'a>(
if !missing_ctors.is_empty() && !report_individual_missing_ctors {
// Report `_` as missing.
missing_ctors = vec![Constructor::Wildcard];
- } else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) {
+ } else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) && !cx.exhaustive_witnesses()
+ {
// We need to report a `_` anyway, so listing other constructors would be redundant.
// `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked
// up by diagnostics to add a note about why `_` is required here.
@@ -1747,7 +1748,9 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>(
// `ctor` is *irrelevant* if there's another constructor in `split_ctors` that matches
// strictly fewer rows. In that case we can sometimes skip it. See the top of the file for
// details.
- let ctor_is_relevant = matches!(ctor, Constructor::Missing) || missing_ctors.is_empty();
+ let ctor_is_relevant = matches!(ctor, Constructor::Missing)
+ || missing_ctors.is_empty()
+ || mcx.tycx.exhaustive_witnesses();
let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant)?;
let mut witnesses = ensure_sufficient_stack(|| {
compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix)
diff --git a/compiler/rustc_pattern_analysis/tests/common/mod.rs b/compiler/rustc_pattern_analysis/tests/common/mod.rs
index 0b939ef..94f2a12 100644
--- a/compiler/rustc_pattern_analysis/tests/common/mod.rs
+++ b/compiler/rustc_pattern_analysis/tests/common/mod.rs
@@ -1,3 +1,4 @@
+#![allow(dead_code, unreachable_pub)]
use rustc_pattern_analysis::constructor::{
Constructor, ConstructorSet, IntRange, MaybeInfiniteInt, RangeEnd, VariantVisibility,
};
@@ -22,8 +23,10 @@ fn init_tracing() {
.try_init();
}
+pub(super) const UNIT: Ty = Ty::Tuple(&[]);
+pub(super) const NEVER: Ty = Ty::Enum(&[]);
+
/// A simple set of types.
-#[allow(dead_code)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(super) enum Ty {
/// Booleans
@@ -38,6 +41,8 @@ pub(super) enum Ty {
BigStruct { arity: usize, ty: &'static Ty },
/// A enum with `arity` variants of type `ty`.
BigEnum { arity: usize, ty: &'static Ty },
+ /// Like `Enum` but non-exhaustive.
+ NonExhaustiveEnum(&'static [Ty]),
}
/// The important logic.
@@ -47,7 +52,7 @@ pub(super) fn sub_tys(&self, ctor: &Constructor<Cx>) -> Vec<Self> {
match (ctor, *self) {
(Struct, Ty::Tuple(tys)) => tys.iter().copied().collect(),
(Struct, Ty::BigStruct { arity, ty }) => (0..arity).map(|_| *ty).collect(),
- (Variant(i), Ty::Enum(tys)) => vec![tys[*i]],
+ (Variant(i), Ty::Enum(tys) | Ty::NonExhaustiveEnum(tys)) => vec![tys[*i]],
(Variant(_), Ty::BigEnum { ty, .. }) => vec![*ty],
(Bool(..) | IntRange(..) | NonExhaustive | Missing | Wildcard, _) => vec![],
_ => panic!("Unexpected ctor {ctor:?} for type {self:?}"),
@@ -61,6 +66,7 @@ fn is_empty(&self) -> bool {
Ty::Enum(tys) => tys.iter().all(|ty| ty.is_empty()),
Ty::BigStruct { arity, ty } => arity != 0 && ty.is_empty(),
Ty::BigEnum { arity, ty } => arity == 0 || ty.is_empty(),
+ Ty::NonExhaustiveEnum(..) => false,
}
}
@@ -90,6 +96,19 @@ fn ctor_set(&self) -> ConstructorSet<Cx> {
.collect(),
non_exhaustive: false,
},
+ Ty::NonExhaustiveEnum(tys) => ConstructorSet::Variants {
+ variants: tys
+ .iter()
+ .map(|ty| {
+ if ty.is_empty() {
+ VariantVisibility::Empty
+ } else {
+ VariantVisibility::Visible
+ }
+ })
+ .collect(),
+ non_exhaustive: true,
+ },
Ty::BigEnum { arity: 0, .. } => ConstructorSet::NoConstructors,
Ty::BigEnum { arity, ty } => {
let vis = if ty.is_empty() {
@@ -113,7 +132,9 @@ fn write_variant_name(
match (*self, ctor) {
(Ty::Tuple(..), _) => Ok(()),
(Ty::BigStruct { .. }, _) => write!(f, "BigStruct"),
- (Ty::Enum(..), Constructor::Variant(i)) => write!(f, "Enum::Variant{i}"),
+ (Ty::Enum(..) | Ty::NonExhaustiveEnum(..), Constructor::Variant(i)) => {
+ write!(f, "Enum::Variant{i}")
+ }
(Ty::BigEnum { .. }, Constructor::Variant(i)) => write!(f, "BigEnum::Variant{i}"),
_ => write!(f, "{:?}::{:?}", self, ctor),
}
@@ -126,10 +147,11 @@ pub(super) fn compute_match_usefulness<'p>(
ty: Ty,
scrut_validity: PlaceValidity,
complexity_limit: usize,
+ exhaustive_witnesses: bool,
) -> Result<UsefulnessReport<'p, Cx>, ()> {
init_tracing();
rustc_pattern_analysis::usefulness::compute_match_usefulness(
- &Cx,
+ &Cx { exhaustive_witnesses },
arms,
ty,
scrut_validity,
@@ -138,7 +160,9 @@ pub(super) fn compute_match_usefulness<'p>(
}
#[derive(Debug)]
-pub(super) struct Cx;
+pub(super) struct Cx {
+ exhaustive_witnesses: bool,
+}
/// The context for pattern analysis. Forwards anything interesting to `Ty` methods.
impl PatCx for Cx {
@@ -153,6 +177,10 @@ fn is_exhaustive_patterns_feature_on(&self) -> bool {
false
}
+ fn exhaustive_witnesses(&self) -> bool {
+ self.exhaustive_witnesses
+ }
+
fn ctor_arity(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> usize {
ty.sub_tys(ctor).len()
}
@@ -219,16 +247,18 @@ macro_rules! pats {
// Entrypoint
// Parse `type; ..`
($ty:expr; $($rest:tt)*) => {{
- #[allow(unused_imports)]
+ #[allow(unused)]
use rustc_pattern_analysis::{
constructor::{Constructor, IntRange, MaybeInfiniteInt, RangeEnd},
- pat::DeconstructedPat,
+ pat::{DeconstructedPat, IndexedPat},
};
let ty = $ty;
// The heart of the macro is designed to push `IndexedPat`s into a `Vec`, so we work around
// that.
+ #[allow(unused)]
let sub_tys = ::std::iter::repeat(&ty);
- let mut vec = Vec::new();
+ #[allow(unused)]
+ let mut vec: Vec<IndexedPat<_>> = Vec::new();
pats!(@ctor(vec:vec, sub_tys:sub_tys, idx:0) $($rest)*);
vec.into_iter().map(|ipat| ipat.pat).collect::<Vec<_>>()
}};
@@ -263,6 +293,8 @@ macro_rules! pats {
let ctor = Constructor::Wildcard;
pats!(@pat($($args)*, ctor:ctor) $($rest)*)
}};
+ // Nothing
+ (@ctor($($args:tt)*)) => {};
// Integers and int ranges
(@ctor($($args:tt)*) $($start:literal)?..$end:literal $($rest:tt)*) => {{
diff --git a/compiler/rustc_pattern_analysis/tests/complexity.rs b/compiler/rustc_pattern_analysis/tests/complexity.rs
index 93aecaf..4754476 100644
--- a/compiler/rustc_pattern_analysis/tests/complexity.rs
+++ b/compiler/rustc_pattern_analysis/tests/complexity.rs
@@ -16,7 +16,7 @@ fn check(patterns: &[DeconstructedPat<Cx>], complexity_limit: usize) -> Result<(
let ty = *patterns[0].ty();
let arms: Vec<_> =
patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
- compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, complexity_limit)
+ compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, complexity_limit, false)
.map(|_report| ())
}
diff --git a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
index 3b8f346..14ca0d0 100644
--- a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
+++ b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
@@ -11,16 +11,30 @@
mod common;
/// Analyze a match made of these patterns.
-fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<WitnessPat<Cx>> {
- let ty = *patterns[0].ty();
+fn run(
+ ty: Ty,
+ patterns: Vec<DeconstructedPat<Cx>>,
+ exhaustive_witnesses: bool,
+) -> Vec<WitnessPat<Cx>> {
let arms: Vec<_> =
patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
- let report =
- compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, usize::MAX)
- .unwrap();
+ let report = compute_match_usefulness(
+ arms.as_slice(),
+ ty,
+ PlaceValidity::ValidOnly,
+ usize::MAX,
+ exhaustive_witnesses,
+ )
+ .unwrap();
report.non_exhaustiveness_witnesses
}
+/// Analyze a match made of these patterns. Panics if there are no patterns
+fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<WitnessPat<Cx>> {
+ let ty = *patterns[0].ty();
+ run(ty, patterns, true)
+}
+
#[track_caller]
fn assert_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) {
let witnesses = check(patterns);
@@ -35,6 +49,26 @@ fn assert_non_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) {
assert!(!witnesses.is_empty())
}
+use WhichWitnesses::*;
+enum WhichWitnesses {
+ AllOfThem,
+ OnlySome,
+}
+
+#[track_caller]
+/// We take the type as input to support empty matches.
+fn assert_witnesses(
+ which: WhichWitnesses,
+ ty: Ty,
+ patterns: Vec<DeconstructedPat<Cx>>,
+ expected: Vec<&str>,
+) {
+ let exhaustive_wit = matches!(which, AllOfThem);
+ let witnesses = run(ty, patterns, exhaustive_wit);
+ let witnesses: Vec<_> = witnesses.iter().map(|w| format!("{w:?}")).collect();
+ assert_eq!(witnesses, expected)
+}
+
#[test]
fn test_int_ranges() {
let ty = Ty::U8;
@@ -59,6 +93,8 @@ fn test_int_ranges() {
#[test]
fn test_nested() {
+ // enum E { A(bool), B(bool) }
+ // ty = (E, E)
let ty = Ty::BigStruct { arity: 2, ty: &Ty::BigEnum { arity: 2, ty: &Ty::Bool } };
assert_non_exhaustive(pats!(ty;
Struct(Variant.0, _),
@@ -79,9 +115,73 @@ fn test_nested() {
}
#[test]
+fn test_witnesses() {
+ // TY = Option<bool>
+ const TY: Ty = Ty::Enum(&[Ty::Bool, UNIT]);
+ // ty = (Option<bool>, Option<bool>)
+ let ty = Ty::Tuple(&[TY, TY]);
+ assert_witnesses(AllOfThem, ty, vec![], vec!["(_, _)"]);
+ assert_witnesses(
+ OnlySome,
+ ty,
+ pats!(ty;
+ (Variant.0(false), Variant.0(false)),
+ ),
+ vec!["(Enum::Variant1(_), _)"],
+ );
+ assert_witnesses(
+ AllOfThem,
+ ty,
+ pats!(ty;
+ (Variant.0(false), Variant.0(false)),
+ ),
+ vec![
+ "(Enum::Variant0(false), Enum::Variant0(true))",
+ "(Enum::Variant0(false), Enum::Variant1(_))",
+ "(Enum::Variant0(true), _)",
+ "(Enum::Variant1(_), _)",
+ ],
+ );
+ assert_witnesses(
+ OnlySome,
+ ty,
+ pats!(ty;
+ (_, Variant.0(false)),
+ ),
+ vec!["(_, Enum::Variant1(_))"],
+ );
+ assert_witnesses(
+ AllOfThem,
+ ty,
+ pats!(ty;
+ (_, Variant.0(false)),
+ ),
+ vec!["(_, Enum::Variant0(true))", "(_, Enum::Variant1(_))"],
+ );
+
+ let ty = Ty::NonExhaustiveEnum(&[UNIT, UNIT, UNIT]);
+ assert_witnesses(
+ OnlySome,
+ ty,
+ pats!(ty;
+ Variant.0,
+ ),
+ vec!["_"],
+ );
+ assert_witnesses(
+ AllOfThem,
+ ty,
+ pats!(ty;
+ Variant.0,
+ ),
+ vec!["Enum::Variant1(_)", "Enum::Variant2(_)", "_"],
+ );
+}
+
+#[test]
fn test_empty() {
// `TY = Result<bool, !>`
- const TY: Ty = Ty::Enum(&[Ty::Bool, Ty::Enum(&[])]);
+ const TY: Ty = Ty::Enum(&[Ty::Bool, NEVER]);
assert_exhaustive(pats!(TY;
Variant.0,
));
diff --git a/compiler/rustc_pattern_analysis/tests/intersection.rs b/compiler/rustc_pattern_analysis/tests/intersection.rs
index 8e6f84d..d4d3905 100644
--- a/compiler/rustc_pattern_analysis/tests/intersection.rs
+++ b/compiler/rustc_pattern_analysis/tests/intersection.rs
@@ -16,7 +16,7 @@ fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<Vec<usize>> {
let arms: Vec<_> =
patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
let report =
- compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, usize::MAX)
+ compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, usize::MAX, false)
.unwrap();
report.arm_intersections.into_iter().map(|bitset| bitset.iter().collect()).collect()
}
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 9dd80bc..b4fa11a 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -26,7 +26,7 @@
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, InferKind, Visitor};
-use rustc_hir::{AmbigArg, ForeignItemKind, ItemId, ItemKind, PatKind};
+use rustc_hir::{AmbigArg, ForeignItemId, ItemId, PatKind};
use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
use rustc_middle::query::Providers;
use rustc_middle::ty::print::PrintTraitRefExt as _;
@@ -204,12 +204,10 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
// Something like `fn() {my_method}` type of the method
// `impl Pub<Priv> { pub fn my_method() {} }` is considered a private type,
// so we need to visit the self type additionally.
- if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
- if let Some(impl_def_id) = assoc_item.impl_container(tcx) {
- try_visit!(
- tcx.type_of(impl_def_id).instantiate_identity().visit_with(self)
- );
- }
+ if let Some(assoc_item) = tcx.opt_associated_item(def_id)
+ && let Some(impl_def_id) = assoc_item.impl_container(tcx)
+ {
+ try_visit!(tcx.type_of(impl_def_id).instantiate_identity().visit_with(self));
}
}
ty::Alias(kind @ (ty::Inherent | ty::Free | ty::Projection), data) => {
@@ -599,18 +597,13 @@ fn update_macro_reachable_def(
DefKind::Struct | DefKind::Union => {
// While structs and unions have type privacy, their fields do not.
- let item = self.tcx.hir_expect_item(def_id);
- if let hir::ItemKind::Struct(_, _, ref struct_def)
- | hir::ItemKind::Union(_, _, ref struct_def) = item.kind
- {
- for field in struct_def.fields() {
- let field_vis = self.tcx.local_visibility(field.def_id);
- if field_vis.is_accessible_from(module, self.tcx) {
- self.reach(field.def_id, macro_ev).ty();
- }
+ let struct_def = self.tcx.adt_def(def_id);
+ for field in struct_def.non_enum_variant().fields.iter() {
+ let def_id = field.did.expect_local();
+ let field_vis = self.tcx.local_visibility(def_id);
+ if field_vis.is_accessible_from(module, self.tcx) {
+ self.reach(def_id, macro_ev).ty();
}
- } else {
- bug!("item {:?} with DefKind {:?}", item, def_kind);
}
}
@@ -739,6 +732,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
if let Some(ctor_def_id) = variant.data.ctor_def_id() {
self.update(ctor_def_id, variant_ev, Level::Reachable);
}
+
for field in variant.data.fields() {
self.update(field.def_id, variant_ev, Level::Reachable);
self.reach(field.def_id, variant_ev).ty();
@@ -1644,66 +1638,29 @@ fn check_item(&mut self, id: ItemId) {
self.check(def_id, item_visibility, effective_vis).generics().predicates();
}
DefKind::Enum => {
- let item = tcx.hir_item(id);
- if let hir::ItemKind::Enum(_, _, ref def) = item.kind {
- self.check_unnameable(item.owner_id.def_id, effective_vis);
+ self.check_unnameable(def_id, effective_vis);
+ self.check(def_id, item_visibility, effective_vis).generics().predicates();
- self.check(item.owner_id.def_id, item_visibility, effective_vis)
- .generics()
- .predicates();
-
- for variant in def.variants {
- for field in variant.data.fields() {
- self.check(field.def_id, item_visibility, effective_vis).ty();
- }
- }
- }
- }
- // Subitems of foreign modules have their own publicity.
- DefKind::ForeignMod => {
- let item = tcx.hir_item(id);
- if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
- for &foreign_item in items {
- let foreign_item = tcx.hir_foreign_item(foreign_item);
-
- let ev = self.get(foreign_item.owner_id.def_id);
- let vis = tcx.local_visibility(foreign_item.owner_id.def_id);
-
- if let ForeignItemKind::Type = foreign_item.kind {
- self.check_unnameable(foreign_item.owner_id.def_id, ev);
- }
-
- self.check(foreign_item.owner_id.def_id, vis, ev)
- .generics()
- .predicates()
- .ty();
- }
+ let adt = tcx.adt_def(id.owner_id);
+ for field in adt.all_fields() {
+ self.check(field.did.expect_local(), item_visibility, effective_vis).ty();
}
}
// Subitems of structs and unions have their own publicity.
DefKind::Struct | DefKind::Union => {
- let item = tcx.hir_item(id);
- if let hir::ItemKind::Struct(_, _, ref struct_def)
- | hir::ItemKind::Union(_, _, ref struct_def) = item.kind
- {
- self.check_unnameable(item.owner_id.def_id, effective_vis);
- self.check(item.owner_id.def_id, item_visibility, effective_vis)
- .generics()
- .predicates();
+ self.check_unnameable(def_id, effective_vis);
+ self.check(def_id, item_visibility, effective_vis).generics().predicates();
- for field in struct_def.fields() {
- let field_visibility = tcx.local_visibility(field.def_id);
- let field_ev = self.get(field.def_id);
+ let adt = tcx.adt_def(id.owner_id);
+ for field in adt.all_fields() {
+ let visibility = min(item_visibility, field.vis.expect_local(), tcx);
+ let field_ev = self.get(field.did.expect_local());
- self.check(
- field.def_id,
- min(item_visibility, field_visibility, tcx),
- field_ev,
- )
- .ty();
- }
+ self.check(field.did.expect_local(), visibility, field_ev).ty();
}
}
+ // Subitems of foreign modules have their own publicity.
+ DefKind::ForeignMod => {}
// An inherent impl is public when its type is public
// Subitems of inherent impls have their own publicity.
// A trait impl is public when both its type and its trait are public
@@ -1763,6 +1720,19 @@ fn check_item(&mut self, id: ItemId) {
_ => {}
}
}
+
+ fn check_foreign_item(&mut self, id: ForeignItemId) {
+ let tcx = self.tcx;
+ let def_id = id.owner_id.def_id;
+ let item_visibility = tcx.local_visibility(def_id);
+ let effective_vis = self.get(def_id);
+
+ if let DefKind::ForeignTy = self.tcx.def_kind(def_id) {
+ self.check_unnameable(def_id, effective_vis);
+ }
+
+ self.check(def_id, item_visibility, effective_vis).generics().predicates().ty();
+ }
}
pub fn provide(providers: &mut Providers) {
@@ -1791,20 +1761,13 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
if let Some(body_id) = tcx.hir_maybe_body_owned_by(def_id) {
visitor.visit_nested_body(body_id.id());
}
- }
- for id in module.free_items() {
- if let ItemKind::Impl(i) = tcx.hir_item(id).kind {
- if let Some(item) = i.of_trait {
- let trait_ref = tcx.impl_trait_ref(id.owner_id.def_id).unwrap();
- let trait_ref = trait_ref.instantiate_identity();
- visitor.span = item.path.span;
- let _ = visitor.visit_def_id(
- trait_ref.def_id,
- "trait",
- &trait_ref.print_only_trait_path(),
- );
- }
+ if let DefKind::Impl { of_trait: true } = tcx.def_kind(def_id) {
+ let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
+ let trait_ref = trait_ref.instantiate_identity();
+ visitor.span = tcx.hir_expect_item(def_id).expect_impl().of_trait.unwrap().path.span;
+ let _ =
+ visitor.visit_def_id(trait_ref.def_id, "trait", &trait_ref.print_only_trait_path());
}
}
}
@@ -1895,7 +1858,11 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
// Check for private types in public interfaces.
let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, effective_visibilities };
- for id in tcx.hir_free_items() {
+ let crate_items = tcx.hir_crate_items(());
+ for id in crate_items.free_items() {
checker.check_item(id);
}
+ for id in crate_items.foreign_items() {
+ checker.check_foreign_item(id);
+ }
}
diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs
index 3320b98..3d59528 100644
--- a/compiler/rustc_public/src/mir/body.rs
+++ b/compiler/rustc_public/src/mir/body.rs
@@ -654,9 +654,7 @@ pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
)),
AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)),
AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())),
- AggregateKind::Coroutine(def, ref args, mov) => {
- Ok(Ty::new_coroutine(def, args.clone(), mov))
- }
+ AggregateKind::Coroutine(def, ref args) => Ok(Ty::new_coroutine(def, args.clone())),
AggregateKind::CoroutineClosure(def, ref args) => {
Ok(Ty::new_coroutine_closure(def, args.clone()))
}
@@ -674,8 +672,7 @@ pub enum AggregateKind {
Tuple,
Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
Closure(ClosureDef, GenericArgs),
- // FIXME(rustc_public): Movability here is redundant
- Coroutine(CoroutineDef, GenericArgs, Movability),
+ Coroutine(CoroutineDef, GenericArgs),
CoroutineClosure(CoroutineClosureDef, GenericArgs),
RawPtr(Ty, Mutability),
}
diff --git a/compiler/rustc_public/src/mir/pretty.rs b/compiler/rustc_public/src/mir/pretty.rs
index a433df2..3183c02 100644
--- a/compiler/rustc_public/src/mir/pretty.rs
+++ b/compiler/rustc_public/src/mir/pretty.rs
@@ -428,7 +428,7 @@ fn pretty_aggregate<W: Write>(
write!(writer, "{{closure@{}}}(", def.span().diagnostic())?;
")"
}
- AggregateKind::Coroutine(def, _, _) => {
+ AggregateKind::Coroutine(def, _) => {
write!(writer, "{{coroutine@{}}}(", def.span().diagnostic())?;
")"
}
diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs
index bc67a2f..de4b21b 100644
--- a/compiler/rustc_public/src/ty.rs
+++ b/compiler/rustc_public/src/ty.rs
@@ -60,8 +60,8 @@ pub fn new_closure(def: ClosureDef, args: GenericArgs) -> Ty {
}
/// Create a new coroutine type.
- pub fn new_coroutine(def: CoroutineDef, args: GenericArgs, mov: Movability) -> Ty {
- Ty::from_rigid_kind(RigidTy::Coroutine(def, args, mov))
+ pub fn new_coroutine(def: CoroutineDef, args: GenericArgs) -> Ty {
+ Ty::from_rigid_kind(RigidTy::Coroutine(def, args))
}
/// Create a new closure type.
@@ -560,8 +560,7 @@ pub enum RigidTy {
FnDef(FnDef, GenericArgs),
FnPtr(PolyFnSig),
Closure(ClosureDef, GenericArgs),
- // FIXME(rustc_public): Movability here is redundant
- Coroutine(CoroutineDef, GenericArgs, Movability),
+ Coroutine(CoroutineDef, GenericArgs),
CoroutineClosure(CoroutineClosureDef, GenericArgs),
Dynamic(Vec<Binder<ExistentialPredicate>>, Region, DynKind),
Never,
diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs
index b2d38e49..66f767a 100644
--- a/compiler/rustc_public/src/unstable/convert/internal.rs
+++ b/compiler/rustc_public/src/unstable/convert/internal.rs
@@ -177,7 +177,7 @@ fn internal<'tcx>(
RigidTy::Closure(def, args) => {
rustc_ty::TyKind::Closure(def.0.internal(tables, tcx), args.internal(tables, tcx))
}
- RigidTy::Coroutine(def, args, _mov) => {
+ RigidTy::Coroutine(def, args) => {
rustc_ty::TyKind::Coroutine(def.0.internal(tables, tcx), args.internal(tables, tcx))
}
RigidTy::CoroutineClosure(def, args) => rustc_ty::TyKind::CoroutineClosure(
diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs
index 8dee579..be8ee80 100644
--- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs
+++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs
@@ -653,7 +653,6 @@ fn stable<'cx>(
crate::mir::AggregateKind::Coroutine(
tables.coroutine_def(*def_id),
generic_arg.stable(tables, cx),
- cx.coroutine_movability(*def_id).stable(tables, cx),
)
}
mir::AggregateKind::CoroutineClosure(def_id, generic_args) => {
diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
index d679615..5a66107 100644
--- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs
+++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
@@ -457,7 +457,6 @@ fn stable<'cx>(
ty::Coroutine(def_id, generic_args) => TyKind::RigidTy(RigidTy::Coroutine(
tables.coroutine_def(*def_id),
generic_args.stable(tables, cx),
- cx.coroutine_movability(*def_id).stable(tables, cx),
)),
ty::Never => TyKind::RigidTy(RigidTy::Never),
ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple(
diff --git a/compiler/rustc_public/src/visitor.rs b/compiler/rustc_public/src/visitor.rs
index 45e2a81..87f1cc6 100644
--- a/compiler/rustc_public/src/visitor.rs
+++ b/compiler/rustc_public/src/visitor.rs
@@ -166,7 +166,7 @@ fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
}
RigidTy::Adt(_, args)
| RigidTy::Closure(_, args)
- | RigidTy::Coroutine(_, args, _)
+ | RigidTy::Coroutine(_, args)
| RigidTy::CoroutineWitness(_, args)
| RigidTy::CoroutineClosure(_, args)
| RigidTy::FnDef(_, args) => args.visit(visitor),
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 04fc32a..7e258aa 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -498,12 +498,12 @@ pub fn read_index(&self, dep_node_index: DepNodeIndex) {
#[cfg(debug_assertions)]
{
- if let Some(target) = task_deps.node {
- if let Some(ref forbidden_edge) = data.current.forbidden_edge {
- let src = forbidden_edge.index_to_node.lock()[&dep_node_index];
- if forbidden_edge.test(&src, &target) {
- panic!("forbidden edge {:?} -> {:?} created", src, target)
- }
+ if let Some(target) = task_deps.node
+ && let Some(ref forbidden_edge) = data.current.forbidden_edge
+ {
+ let src = forbidden_edge.index_to_node.lock()[&dep_node_index];
+ if forbidden_edge.test(&src, &target) {
+ panic!("forbidden edge {:?} -> {:?} created", src, target)
}
}
}
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 7e61f50..fd1ea99 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -289,10 +289,10 @@ fn visit_waiters<I, F>(
F: FnMut(Span, QueryJobId) -> Option<Option<Waiter>>,
{
// Visit the parent query which is a non-resumable waiter since it's on the same stack
- if let Some(parent) = query.parent(query_map) {
- if let Some(cycle) = visit(query.span(query_map), parent) {
- return Some(cycle);
- }
+ if let Some(parent) = query.parent(query_map)
+ && let Some(cycle) = visit(query.span(query_map), parent)
+ {
+ return Some(cycle);
}
// Visit the explicit waiters which use condvars and are resumable
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 06e59eb..e74de5e 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -720,7 +720,7 @@ fn incremental_verify_ich_failed<Tcx>(
static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) };
};
- let old_in_panic = INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.replace(true));
+ let old_in_panic = INSIDE_VERIFY_PANIC.replace(true);
if old_in_panic {
tcx.sess().dcx().emit_err(crate::error::Reentrant);
@@ -739,7 +739,7 @@ fn incremental_verify_ich_failed<Tcx>(
panic!("Found unstable fingerprints for {dep_node:?}: {}", result());
}
- INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic));
+ INSIDE_VERIFY_PANIC.set(old_in_panic);
}
/// Ensure that either this query has all green inputs or been executed.
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 83ec037..7912345 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -23,9 +23,9 @@
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
use rustc_index::bit_set::DenseBitSet;
use rustc_metadata::creader::LoadedMacro;
-use rustc_middle::bug;
use rustc_middle::metadata::ModChild;
use rustc_middle::ty::{Feed, Visibility};
+use rustc_middle::{bug, span_bug};
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
use rustc_span::{Ident, Span, Symbol, kw, sym};
use thin_vec::ThinVec;
@@ -46,30 +46,59 @@
impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
/// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
/// otherwise, reports an error.
- pub(crate) fn define_binding(
+ pub(crate) fn define_binding_local(
&mut self,
parent: Module<'ra>,
ident: Ident,
ns: Namespace,
binding: NameBinding<'ra>,
) {
- if let Err(old_binding) = self.try_define(parent, ident, ns, binding, false) {
+ if let Err(old_binding) = self.try_define_local(parent, ident, ns, binding, false) {
self.report_conflict(parent, ident, ns, old_binding, binding);
}
}
- fn define(
+ fn define_local(
&mut self,
parent: Module<'ra>,
ident: Ident,
ns: Namespace,
res: Res,
- vis: Visibility<impl Into<DefId>>,
+ vis: Visibility,
span: Span,
expn_id: LocalExpnId,
) {
let binding = self.arenas.new_res_binding(res, vis.to_def_id(), span, expn_id);
- self.define_binding(parent, ident, ns, binding)
+ self.define_binding_local(parent, ident, ns, binding);
+ }
+
+ fn define_extern(
+ &self,
+ parent: Module<'ra>,
+ ident: Ident,
+ ns: Namespace,
+ res: Res,
+ vis: Visibility<DefId>,
+ span: Span,
+ expn_id: LocalExpnId,
+ ) {
+ let binding = self.arenas.new_res_binding(res, vis, span, expn_id);
+ // Even if underscore names cannot be looked up, we still need to add them to modules,
+ // because they can be fetched by glob imports from those modules, and bring traits
+ // into scope both directly and through glob imports.
+ let key = BindingKey::new_disambiguated(ident, ns, || {
+ parent.underscore_disambiguator.update(|d| d + 1);
+ parent.underscore_disambiguator.get()
+ });
+ if self
+ .resolution_or_default(parent, key)
+ .borrow_mut()
+ .non_glob_binding
+ .replace(binding)
+ .is_some()
+ {
+ span_bug!(span, "an external binding was already defined");
+ }
}
/// Walks up the tree of definitions starting at `def_id`,
@@ -192,7 +221,7 @@ pub(crate) fn build_reduced_graph(
visitor.parent_scope.macro_rules
}
- pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'ra>) {
+ pub(crate) fn build_reduced_graph_external(&self, module: Module<'ra>) {
for child in self.tcx.module_children(module.def_id()) {
let parent_scope = ParentScope::module(module, self);
self.build_reduced_graph_for_external_crate_res(child, parent_scope)
@@ -201,7 +230,7 @@ pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'ra>) {
/// Builds the reduced graph for a single item in an external crate.
fn build_reduced_graph_for_external_crate_res(
- &mut self,
+ &self,
child: &ModChild,
parent_scope: ParentScope<'ra>,
) {
@@ -232,7 +261,7 @@ fn build_reduced_graph_for_external_crate_res(
_,
)
| Res::PrimTy(..)
- | Res::ToolMod => self.define(parent, ident, TypeNS, res, vis, span, expansion),
+ | Res::ToolMod => self.define_extern(parent, ident, TypeNS, res, vis, span, expansion),
Res::Def(
DefKind::Fn
| DefKind::AssocFn
@@ -241,9 +270,9 @@ fn build_reduced_graph_for_external_crate_res(
| DefKind::AssocConst
| DefKind::Ctor(..),
_,
- ) => self.define(parent, ident, ValueNS, res, vis, span, expansion),
+ ) => self.define_extern(parent, ident, ValueNS, res, vis, span, expansion),
Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => {
- self.define(parent, ident, MacroNS, res, vis, span, expansion)
+ self.define_extern(parent, ident, MacroNS, res, vis, span, expansion)
}
Res::Def(
DefKind::TyParam
@@ -452,8 +481,10 @@ fn add_import(
self.r.per_ns(|this, ns| {
if !type_ns_only || ns == TypeNS {
let key = BindingKey::new(target, ns);
- let mut resolution = this.resolution(current_module, key).borrow_mut();
- resolution.single_imports.insert(import);
+ this.resolution_or_default(current_module, key)
+ .borrow_mut()
+ .single_imports
+ .insert(import);
}
});
}
@@ -709,7 +740,7 @@ fn build_reduced_graph_for_struct_variant(
let expansion = parent_scope.expansion;
// Define a name in the type namespace if it is not anonymous.
- self.r.define(parent, ident, TypeNS, adt_res, adt_vis, adt_span, expansion);
+ self.r.define_local(parent, ident, TypeNS, adt_res, adt_vis, adt_span, expansion);
self.r.feed_visibility(feed, adt_vis);
let def_id = feed.key();
@@ -761,7 +792,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'a Item) {
}
ItemKind::Mod(_, ident, ref mod_kind) => {
- self.r.define(parent, ident, TypeNS, res, vis, sp, expansion);
+ self.r.define_local(parent, ident, TypeNS, res, vis, sp, expansion);
if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind {
self.r.mods_with_parse_errors.insert(def_id);
@@ -780,10 +811,10 @@ fn build_reduced_graph_for_item(&mut self, item: &'a Item) {
ItemKind::Const(box ConstItem { ident, .. })
| ItemKind::Delegation(box Delegation { ident, .. })
| ItemKind::Static(box StaticItem { ident, .. }) => {
- self.r.define(parent, ident, ValueNS, res, vis, sp, expansion);
+ self.r.define_local(parent, ident, ValueNS, res, vis, sp, expansion);
}
ItemKind::Fn(box Fn { ident, .. }) => {
- self.r.define(parent, ident, ValueNS, res, vis, sp, expansion);
+ self.r.define_local(parent, ident, ValueNS, res, vis, sp, expansion);
// Functions introducing procedural macros reserve a slot
// in the macro namespace as well (see #52225).
@@ -792,11 +823,11 @@ fn build_reduced_graph_for_item(&mut self, item: &'a Item) {
// These items live in the type namespace.
ItemKind::TyAlias(box TyAlias { ident, .. }) | ItemKind::TraitAlias(ident, ..) => {
- self.r.define(parent, ident, TypeNS, res, vis, sp, expansion);
+ self.r.define_local(parent, ident, TypeNS, res, vis, sp, expansion);
}
ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => {
- self.r.define(parent, ident, TypeNS, res, vis, sp, expansion);
+ self.r.define_local(parent, ident, TypeNS, res, vis, sp, expansion);
self.parent_scope.module = self.r.new_local_module(
Some(parent),
@@ -848,7 +879,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'a Item) {
let feed = self.r.feed(ctor_node_id);
let ctor_def_id = feed.key();
let ctor_res = self.res(ctor_def_id);
- self.r.define(parent, ident, ValueNS, ctor_res, ctor_vis, sp, expansion);
+ self.r.define_local(parent, ident, ValueNS, ctor_res, ctor_vis, sp, expansion);
self.r.feed_visibility(feed, ctor_vis);
// We need the field visibility spans also for the constructor for E0603.
self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata.fields());
@@ -953,18 +984,17 @@ fn build_reduced_graph_for_extern_crate(
// more details: https://github.com/rust-lang/rust/pull/111761
return;
}
- let entry = self
- .r
- .extern_prelude
- .entry(ident)
- .or_insert(ExternPreludeEntry { binding: None, introduced_by_item: true });
+ let entry = self.r.extern_prelude.entry(ident).or_insert(ExternPreludeEntry {
+ binding: Cell::new(None),
+ introduced_by_item: true,
+ });
if orig_name.is_some() {
entry.introduced_by_item = true;
}
// Binding from `extern crate` item in source code can replace
// a binding from `--extern` on command line here.
if !entry.is_import() {
- entry.binding = Some(imported_binding)
+ entry.binding.set(Some(imported_binding));
} else if ident.name != kw::Underscore {
self.r.dcx().span_delayed_bug(
item.span,
@@ -972,7 +1002,7 @@ fn build_reduced_graph_for_extern_crate(
);
}
}
- self.r.define_binding(parent, ident, TypeNS, imported_binding);
+ self.r.define_binding_local(parent, ident, TypeNS, imported_binding);
}
/// Constructs the reduced graph for one foreign item.
@@ -989,7 +1019,7 @@ fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, ident: Id
let parent = self.parent_scope.module;
let expansion = self.parent_scope.expansion;
let vis = self.resolve_visibility(&item.vis);
- self.r.define(parent, ident, ns, self.res(def_id), vis, item.span, expansion);
+ self.r.define_local(parent, ident, ns, self.res(def_id), vis, item.span, expansion);
self.r.feed_visibility(feed, vis);
}
@@ -1072,7 +1102,7 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'ra>) -> boo
if let Some(span) = import_all {
let import = macro_use_import(self, span, false);
self.r.potentially_unused_imports.push(import);
- module.for_each_child(self, |this, ident, ns, binding| {
+ module.for_each_child_mut(self, |this, ident, ns, binding| {
if ns == MacroNS {
let import = if this.r.is_accessible_from(binding.vis, this.parent_scope.module)
{
@@ -1237,7 +1267,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'ra> {
});
self.r.import_use_map.insert(import, Used::Other);
let import_binding = self.r.import(binding, import);
- self.r.define_binding(self.r.graph_root, ident, MacroNS, import_binding);
+ self.r.define_binding_local(self.r.graph_root, ident, MacroNS, import_binding);
} else {
self.r.check_reserved_macro_name(ident, res);
self.insert_unused_macro(ident, def_id, item.id);
@@ -1265,7 +1295,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'ra> {
if !vis.is_public() {
self.insert_unused_macro(ident, def_id, item.id);
}
- self.r.define(module, ident, MacroNS, res, vis, span, expansion);
+ self.r.define_local(module, ident, MacroNS, res, vis, span, expansion);
self.r.feed_visibility(feed, vis);
self.parent_scope.macro_rules
}
@@ -1401,7 +1431,7 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
if ctxt == AssocCtxt::Trait {
let parent = self.parent_scope.module;
let expansion = self.parent_scope.expansion;
- self.r.define(parent, ident, ns, self.res(def_id), vis, item.span, expansion);
+ self.r.define_local(parent, ident, ns, self.res(def_id), vis, item.span, expansion);
} else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob)
&& ident.name != kw::Underscore
{
@@ -1489,7 +1519,7 @@ fn visit_variant(&mut self, variant: &'a ast::Variant) {
let feed = self.r.feed(variant.id);
let def_id = feed.key();
let vis = self.resolve_visibility(&variant.vis);
- self.r.define(parent, ident, TypeNS, self.res(def_id), vis, variant.span, expn_id);
+ self.r.define_local(parent, ident, TypeNS, self.res(def_id), vis, variant.span, expn_id);
self.r.feed_visibility(feed, vis);
// If the variant is marked as non_exhaustive then lower the visibility to within the crate.
@@ -1505,7 +1535,7 @@ fn visit_variant(&mut self, variant: &'a ast::Variant) {
let feed = self.r.feed(ctor_node_id);
let ctor_def_id = feed.key();
let ctor_res = self.res(ctor_def_id);
- self.r.define(parent, ident, ValueNS, ctor_res, ctor_vis, variant.span, expn_id);
+ self.r.define_local(parent, ident, ValueNS, ctor_res, ctor_vis, variant.span, expn_id);
self.r.feed_visibility(feed, ctor_vis);
}
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 81ee02a..b85a814 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -509,9 +509,7 @@ pub(crate) fn check_unused(&mut self, krate: &ast::Crate) {
let mut check_redundant_imports = FxIndexSet::default();
for module in self.arenas.local_modules().iter() {
for (_key, resolution) in self.resolutions(*module).borrow().iter() {
- let resolution = resolution.borrow();
-
- if let Some(binding) = resolution.best_binding()
+ if let Some(binding) = resolution.borrow().best_binding()
&& let NameBindingKind::Import { import, .. } = binding.kind
&& let ImportKind::Single { id, .. } = import.kind
{
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index d72fbc1..3af69b2 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -523,7 +523,7 @@ pub(crate) fn lint_if_path_starts_with_module(
}
pub(crate) fn add_module_candidates(
- &mut self,
+ &self,
module: Module<'ra>,
names: &mut Vec<TypoSuggestion>,
filter_fn: &impl Fn(Res) -> bool,
@@ -1076,11 +1076,6 @@ fn early_lookup_typo_candidate(
}
}
}
- Scope::CrateRoot => {
- let root_ident = Ident::new(kw::PathRoot, ident.span);
- let root_module = this.resolve_crate_root(root_ident);
- this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
- }
Scope::Module(module, _) => {
this.add_module_candidates(module, &mut suggestions, filter_fn, None);
}
@@ -1155,7 +1150,7 @@ fn early_lookup_typo_candidate(
}
fn lookup_import_candidates_from_module<FilterFn>(
- &mut self,
+ &self,
lookup_ident: Ident,
namespace: Namespace,
parent_scope: &ParentScope<'ra>,
@@ -2664,10 +2659,8 @@ pub(crate) fn check_for_module_export_macro(
return None;
}
- let resolutions = self.resolutions(crate_module).borrow();
let binding_key = BindingKey::new(ident, MacroNS);
- let resolution = resolutions.get(&binding_key)?;
- let binding = resolution.borrow().binding()?;
+ let binding = self.resolution(crate_module, binding_key)?.binding()?;
let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else {
return None;
};
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 34d1e95..fe6e5b8 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -114,9 +114,7 @@ pub(crate) fn compute_effective_visibilities<'c>(
/// including their whole reexport chains.
fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) {
let module = self.r.expect_module(module_id.to_def_id());
- let resolutions = self.r.resolutions(module);
-
- for (_, name_resolution) in resolutions.borrow().iter() {
+ for (_, name_resolution) in self.r.resolutions(module).borrow().iter() {
let Some(mut binding) = name_resolution.borrow().binding() else {
continue;
};
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 3494139..f5bc46b 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -93,20 +93,21 @@ pub(crate) fn visit_scopes<T>(
// 6. Language prelude: builtin attributes (closed, controlled).
let rust_2015 = ctxt.edition().is_rust_2015();
- let (ns, macro_kind, is_absolute_path) = match scope_set {
- ScopeSet::All(ns) => (ns, None, false),
- ScopeSet::AbsolutePath(ns) => (ns, None, true),
- ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
- ScopeSet::Late(ns, ..) => (ns, None, false),
+ let (ns, macro_kind) = match scope_set {
+ ScopeSet::All(ns)
+ | ScopeSet::ModuleAndExternPrelude(ns, _)
+ | ScopeSet::Late(ns, ..) => (ns, None),
+ ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)),
};
let module = match scope_set {
// Start with the specified module.
- ScopeSet::Late(_, module, _) => module,
+ ScopeSet::Late(_, module, _) | ScopeSet::ModuleAndExternPrelude(_, module) => module,
// Jump out of trait or enum modules, they do not act as scopes.
_ => parent_scope.module.nearest_item_scope(),
};
+ let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..));
let mut scope = match ns {
- _ if is_absolute_path => Scope::CrateRoot,
+ _ if module_and_extern_prelude => Scope::Module(module, None),
TypeNS | ValueNS => Scope::Module(module, None),
MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
};
@@ -134,11 +135,10 @@ pub(crate) fn visit_scopes<T>(
}
true
}
- Scope::CrateRoot => true,
Scope::Module(..) => true,
Scope::MacroUsePrelude => use_prelude || rust_2015,
Scope::BuiltinAttrs => true,
- Scope::ExternPrelude => use_prelude || is_absolute_path,
+ Scope::ExternPrelude => use_prelude || module_and_extern_prelude,
Scope::ToolPrelude => use_prelude,
Scope::StdLibPrelude => use_prelude || ns == MacroNS,
Scope::BuiltinTypes => true,
@@ -174,7 +174,7 @@ pub(crate) fn visit_scopes<T>(
}
MacroRulesScope::Empty => Scope::Module(module, None),
},
- Scope::CrateRoot => match ns {
+ Scope::Module(..) if module_and_extern_prelude => match ns {
TypeNS => {
ctxt.adjust(ExpnId::root());
Scope::ExternPrelude
@@ -203,7 +203,7 @@ pub(crate) fn visit_scopes<T>(
}
Scope::MacroUsePrelude => Scope::StdLibPrelude,
Scope::BuiltinAttrs => break, // nowhere else to search
- Scope::ExternPrelude if is_absolute_path => break,
+ Scope::ExternPrelude if module_and_extern_prelude => break,
Scope::ExternPrelude => Scope::ToolPrelude,
Scope::ToolPrelude => Scope::StdLibPrelude,
Scope::StdLibPrelude => match ns {
@@ -404,10 +404,10 @@ struct Flags: u8 {
}
let (ns, macro_kind) = match scope_set {
- ScopeSet::All(ns) => (ns, None),
- ScopeSet::AbsolutePath(ns) => (ns, None),
+ ScopeSet::All(ns)
+ | ScopeSet::ModuleAndExternPrelude(ns, _)
+ | ScopeSet::Late(ns, ..) => (ns, None),
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)),
- ScopeSet::Late(ns, ..) => (ns, None),
};
// This is *the* result, resolution from the scope closest to the resolved identifier.
@@ -487,31 +487,16 @@ struct Flags: u8 {
MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined),
_ => Err(Determinacy::Determined),
},
- Scope::CrateRoot => {
- let root_ident = Ident::new(kw::PathRoot, ident.span);
- let root_module = this.resolve_crate_root(root_ident);
- let binding = this.resolve_ident_in_module(
- ModuleOrUniformRoot::Module(root_module),
- ident,
- ns,
- parent_scope,
- finalize,
- ignore_binding,
- ignore_import,
- );
- match binding {
- Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
- Err((Determinacy::Undetermined, Weak::No)) => {
- return Some(Err(Determinacy::determined(force)));
- }
- Err((Determinacy::Undetermined, Weak::Yes)) => {
- Err(Determinacy::Undetermined)
- }
- Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
- }
- }
Scope::Module(module, derive_fallback_lint_id) => {
- let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
+ let (adjusted_parent_scope, finalize) =
+ if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) {
+ (parent_scope, finalize)
+ } else {
+ (
+ &ParentScope { module, ..*parent_scope },
+ finalize.map(|f| Finalize { used: Used::Scope, ..f }),
+ )
+ };
let binding = this.resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(module),
ident,
@@ -522,7 +507,7 @@ struct Flags: u8 {
} else {
Shadowing::Restricted
},
- finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
+ finalize,
ignore_binding,
ignore_import,
);
@@ -776,7 +761,7 @@ pub(crate) fn resolve_ident_in_module(
ModuleOrUniformRoot::ExternPrelude => {
ident.span.normalize_to_macros_2_0_and_adjust(ExpnId::root());
}
- ModuleOrUniformRoot::CrateRootAndExternPrelude | ModuleOrUniformRoot::CurrentScope => {
+ ModuleOrUniformRoot::ModuleAndExternPrelude(..) | ModuleOrUniformRoot::CurrentScope => {
// No adjustments
}
}
@@ -810,11 +795,11 @@ fn resolve_ident_in_module_unadjusted(
) -> Result<NameBinding<'ra>, (Determinacy, Weak)> {
let module = match module {
ModuleOrUniformRoot::Module(module) => module,
- ModuleOrUniformRoot::CrateRootAndExternPrelude => {
+ ModuleOrUniformRoot::ModuleAndExternPrelude(module) => {
assert_eq!(shadowing, Shadowing::Unrestricted);
let binding = self.early_resolve_ident_in_lexical_scope(
ident,
- ScopeSet::AbsolutePath(ns),
+ ScopeSet::ModuleAndExternPrelude(ns, module),
parent_scope,
finalize,
finalize.is_some(),
@@ -863,8 +848,13 @@ fn resolve_ident_in_module_unadjusted(
};
let key = BindingKey::new(ident, ns);
- let resolution =
- self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports.
+ // `try_borrow_mut` is required to ensure exclusive access, even if the resulting binding
+ // doesn't need to be mutable. It will fail when there is a cycle of imports, and without
+ // the exclusive access infinite recursion will crash the compiler with stack overflow.
+ let resolution = &*self
+ .resolution_or_default(module, key)
+ .try_borrow_mut()
+ .map_err(|_| (Determined, Weak::No))?;
// If the primary binding is unusable, search further and return the shadowed glob
// binding if it exists. What we really want here is having two separate scopes in
@@ -1531,7 +1521,8 @@ pub(crate) fn resolve_path_with_ribs(
&& self.tcx.sess.at_least_rust_2018()
{
// `::a::b` from 2015 macro on 2018 global edition
- module = Some(ModuleOrUniformRoot::CrateRootAndExternPrelude);
+ let crate_root = self.resolve_crate_root(ident);
+ module = Some(ModuleOrUniformRoot::ModuleAndExternPrelude(crate_root));
continue;
}
if name == kw::PathRoot || name == kw::Crate || name == kw::DollarCrate {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 783c500..156df45 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -181,10 +181,10 @@ pub(crate) struct ImportData<'ra> {
///
/// | `module_path` | `imported_module` | remark |
/// |-|-|-|
- /// |`use prefix::foo`| `ModuleOrUniformRoot::Module(prefix)` | - |
- /// |`use ::foo` | `ModuleOrUniformRoot::ExternPrelude` | 2018+ editions |
- /// |`use ::foo` | `ModuleOrUniformRoot::CrateRootAndExternPrelude` | a special case in 2015 edition |
- /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - |
+ /// |`use prefix::foo`| `ModuleOrUniformRoot::Module(prefix)` | - |
+ /// |`use ::foo` | `ModuleOrUniformRoot::ExternPrelude` | 2018+ editions |
+ /// |`use ::foo` | `ModuleOrUniformRoot::ModuleAndExternPrelude` | a special case in 2015 edition |
+ /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - |
pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>,
pub vis: Visibility,
}
@@ -334,8 +334,7 @@ pub(crate) fn import(
}
/// Define the name or return the existing binding if there is a collision.
- /// `update` indicates if the definition is a redefinition of an existing binding.
- pub(crate) fn try_define(
+ pub(crate) fn try_define_local(
&mut self,
module: Module<'ra>,
ident: Ident,
@@ -353,7 +352,7 @@ pub(crate) fn try_define(
module.underscore_disambiguator.update(|d| d + 1);
module.underscore_disambiguator.get()
});
- self.update_resolution(module, key, warn_ambiguity, |this, resolution| {
+ self.update_local_resolution(module, key, warn_ambiguity, |this, resolution| {
if let Some(old_binding) = resolution.best_binding() {
if res == Res::Err && old_binding.res() != Res::Err {
// Do not override real bindings with `Res::Err`s from error recovery.
@@ -456,7 +455,7 @@ fn new_warn_ambiguity_binding(&self, binding: NameBinding<'ra>) -> NameBinding<'
// Use `f` to mutate the resolution of the name in the module.
// If the resolution becomes a success, define it in the module's glob importers.
- fn update_resolution<T, F>(
+ fn update_local_resolution<T, F>(
&mut self,
module: Module<'ra>,
key: BindingKey,
@@ -469,7 +468,7 @@ fn update_resolution<T, F>(
// Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
// during which the resolution might end up getting re-defined via a glob cycle.
let (binding, t, warn_ambiguity) = {
- let resolution = &mut *self.resolution(module, key).borrow_mut();
+ let resolution = &mut *self.resolution_or_default(module, key).borrow_mut();
let old_binding = resolution.binding();
let t = f(self, resolution);
@@ -497,7 +496,7 @@ fn update_resolution<T, F>(
};
if self.is_accessible_from(binding.vis, scope) {
let imported_binding = self.import(binding, *import);
- let _ = self.try_define(
+ let _ = self.try_define_local(
import.parent_scope.module,
ident,
key.ns,
@@ -523,11 +522,11 @@ fn import_dummy_binding(&mut self, import: Import<'ra>, is_indeterminate: bool)
let dummy_binding = self.import(dummy_binding, import);
self.per_ns(|this, ns| {
let module = import.parent_scope.module;
- let _ = this.try_define(module, target, ns, dummy_binding, false);
+ let _ = this.try_define_local(module, target, ns, dummy_binding, false);
// Don't remove underscores from `single_imports`, they were never added.
if target.name != kw::Underscore {
let key = BindingKey::new(target, ns);
- this.update_resolution(module, key, false, |_, resolution| {
+ this.update_local_resolution(module, key, false, |_, resolution| {
resolution.single_imports.swap_remove(&import);
})
}
@@ -651,7 +650,6 @@ pub(crate) fn lint_reexports(&mut self, exported_ambiguities: FxHashSet<NameBind
for module in self.arenas.local_modules().iter() {
for (key, resolution) in self.resolutions(*module).borrow().iter() {
let resolution = resolution.borrow();
-
let Some(binding) = resolution.best_binding() else { continue };
if let NameBindingKind::Import { import, .. } = binding.kind
@@ -903,14 +901,14 @@ fn resolve_import(&mut self, import: Import<'ra>) -> usize {
}
// We need the `target`, `source` can be extracted.
let imported_binding = this.import(binding, import);
- this.define_binding(parent, target, ns, imported_binding);
+ this.define_binding_local(parent, target, ns, imported_binding);
PendingBinding::Ready(Some(imported_binding))
}
Err(Determinacy::Determined) => {
// Don't remove underscores from `single_imports`, they were never added.
if target.name != kw::Underscore {
let key = BindingKey::new(target, ns);
- this.update_resolution(parent, key, false, |_, resolution| {
+ this.update_local_resolution(parent, key, false, |_, resolution| {
resolution.single_imports.swap_remove(&import);
});
}
@@ -1202,41 +1200,39 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
});
return if all_ns_failed {
- let resolutions = match module {
- ModuleOrUniformRoot::Module(module) => Some(self.resolutions(module).borrow()),
- _ => None,
- };
- let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter());
- let names = resolutions
- .filter_map(|(BindingKey { ident: i, .. }, resolution)| {
- if i.name == ident.name {
- return None;
- } // Never suggest the same name
- match *resolution.borrow() {
- ref resolution
- if let Some(name_binding) = resolution.best_binding() =>
- {
- match name_binding.kind {
- NameBindingKind::Import { binding, .. } => {
- match binding.kind {
- // Never suggest the name that has binding error
- // i.e., the name that cannot be previously resolved
- NameBindingKind::Res(Res::Err) => None,
- _ => Some(i.name),
+ let names = match module {
+ ModuleOrUniformRoot::Module(module) => {
+ self.resolutions(module)
+ .borrow()
+ .iter()
+ .filter_map(|(BindingKey { ident: i, .. }, resolution)| {
+ if i.name == ident.name {
+ return None;
+ } // Never suggest the same name
+
+ let resolution = resolution.borrow();
+ if let Some(name_binding) = resolution.best_binding() {
+ match name_binding.kind {
+ NameBindingKind::Import { binding, .. } => {
+ match binding.kind {
+ // Never suggest the name that has binding error
+ // i.e., the name that cannot be previously resolved
+ NameBindingKind::Res(Res::Err) => None,
+ _ => Some(i.name),
+ }
}
+ _ => Some(i.name),
}
- _ => Some(i.name),
+ } else if resolution.single_imports.is_empty() {
+ None
+ } else {
+ Some(i.name)
}
- }
- NameResolution { ref single_imports, .. }
- if single_imports.is_empty() =>
- {
- None
- }
- _ => Some(i.name),
- }
- })
- .collect::<Vec<Symbol>>();
+ })
+ .collect()
+ }
+ _ => Vec::new(),
+ };
let lev_suggestion =
find_best_match_for_name(&names, ident.name, None).map(|suggestion| {
@@ -1517,10 +1513,9 @@ fn resolve_glob_import(&mut self, import: Import<'ra>) {
let imported_binding = self.import(binding, import);
let warn_ambiguity = self
.resolution(import.parent_scope.module, key)
- .borrow()
- .binding()
+ .and_then(|r| r.binding())
.is_some_and(|binding| binding.warn_ambiguity_recursive());
- let _ = self.try_define(
+ let _ = self.try_define_local(
import.parent_scope.module,
key.ident,
key.ns,
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index a3a7705..261d099 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -910,22 +910,15 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
span,
|this| {
this.visit_generic_params(&fn_ptr.generic_params, false);
- this.with_lifetime_rib(
- LifetimeRibKind::AnonymousCreateParameter {
- binder: ty.id,
- report_in_path: false,
- },
- |this| {
- this.resolve_fn_signature(
- ty.id,
- false,
- // We don't need to deal with patterns in parameters, because
- // they are not possible for foreign or bodiless functions.
- fn_ptr.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
- &fn_ptr.decl.output,
- )
- },
- );
+ this.resolve_fn_signature(
+ ty.id,
+ false,
+ // We don't need to deal with patterns in parameters, because
+ // they are not possible for foreign or bodiless functions.
+ fn_ptr.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
+ &fn_ptr.decl.output,
+ false,
+ )
},
)
}
@@ -1042,19 +1035,12 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
self.visit_fn_header(&sig.header);
self.visit_ident(ident);
self.visit_generics(generics);
- self.with_lifetime_rib(
- LifetimeRibKind::AnonymousCreateParameter {
- binder: fn_id,
- report_in_path: false,
- },
- |this| {
- this.resolve_fn_signature(
- fn_id,
- sig.decl.has_self(),
- sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
- &sig.decl.output,
- );
- },
+ self.resolve_fn_signature(
+ fn_id,
+ sig.decl.has_self(),
+ sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
+ &sig.decl.output,
+ false,
);
return;
}
@@ -1080,22 +1066,15 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
.coroutine_kind
.map(|coroutine_kind| coroutine_kind.return_id());
- this.with_lifetime_rib(
- LifetimeRibKind::AnonymousCreateParameter {
- binder: fn_id,
- report_in_path: coro_node_id.is_some(),
- },
- |this| {
- this.resolve_fn_signature(
- fn_id,
- declaration.has_self(),
- declaration
- .inputs
- .iter()
- .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)),
- &declaration.output,
- );
- },
+ this.resolve_fn_signature(
+ fn_id,
+ declaration.has_self(),
+ declaration
+ .inputs
+ .iter()
+ .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)),
+ &declaration.output,
+ coro_node_id.is_some(),
);
if let Some(contract) = contract {
@@ -1307,19 +1286,12 @@ fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) {
kind: LifetimeBinderKind::PolyTrait,
..
} => {
- self.with_lifetime_rib(
- LifetimeRibKind::AnonymousCreateParameter {
- binder,
- report_in_path: false,
- },
- |this| {
- this.resolve_fn_signature(
- binder,
- false,
- p_args.inputs.iter().map(|ty| (None, &**ty)),
- &p_args.output,
- )
- },
+ self.resolve_fn_signature(
+ binder,
+ false,
+ p_args.inputs.iter().map(|ty| (None, &**ty)),
+ &p_args.output,
+ false,
);
break;
}
@@ -2236,25 +2208,32 @@ fn resolve_fn_signature(
has_self: bool,
inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)> + Clone,
output_ty: &'ast FnRetTy,
+ report_elided_lifetimes_in_path: bool,
) {
- // Add each argument to the rib.
- let elision_lifetime = self.resolve_fn_params(has_self, inputs);
- debug!(?elision_lifetime);
-
- let outer_failures = take(&mut self.diag_metadata.current_elision_failures);
- let output_rib = if let Ok(res) = elision_lifetime.as_ref() {
- self.r.lifetime_elision_allowed.insert(fn_id);
- LifetimeRibKind::Elided(*res)
- } else {
- LifetimeRibKind::ElisionFailure
+ let rib = LifetimeRibKind::AnonymousCreateParameter {
+ binder: fn_id,
+ report_in_path: report_elided_lifetimes_in_path,
};
- self.with_lifetime_rib(output_rib, |this| visit::walk_fn_ret_ty(this, output_ty));
- let elision_failures =
- replace(&mut self.diag_metadata.current_elision_failures, outer_failures);
- if !elision_failures.is_empty() {
- let Err(failure_info) = elision_lifetime else { bug!() };
- self.report_missing_lifetime_specifiers(elision_failures, Some(failure_info));
- }
+ self.with_lifetime_rib(rib, |this| {
+ // Add each argument to the rib.
+ let elision_lifetime = this.resolve_fn_params(has_self, inputs);
+ debug!(?elision_lifetime);
+
+ let outer_failures = take(&mut this.diag_metadata.current_elision_failures);
+ let output_rib = if let Ok(res) = elision_lifetime.as_ref() {
+ this.r.lifetime_elision_allowed.insert(fn_id);
+ LifetimeRibKind::Elided(*res)
+ } else {
+ LifetimeRibKind::ElisionFailure
+ };
+ this.with_lifetime_rib(output_rib, |this| visit::walk_fn_ret_ty(this, output_ty));
+ let elision_failures =
+ replace(&mut this.diag_metadata.current_elision_failures, outer_failures);
+ if !elision_failures.is_empty() {
+ let Err(failure_info) = elision_lifetime else { bug!() };
+ this.report_missing_lifetime_specifiers(elision_failures, Some(failure_info));
+ }
+ });
}
/// Resolve inside function parameters and parameter types.
@@ -3449,8 +3428,7 @@ fn check_trait_item<F>(
};
ident.span.normalize_to_macros_2_0_and_adjust(module.expansion);
let key = BindingKey::new(ident, ns);
- let mut binding =
- self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.best_binding());
+ let mut binding = self.r.resolution(module, key).and_then(|r| r.best_binding());
debug!(?binding);
if binding.is_none() {
// We could not find the trait item in the correct namespace.
@@ -3461,8 +3439,7 @@ fn check_trait_item<F>(
_ => ns,
};
let key = BindingKey::new(ident, ns);
- binding =
- self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.best_binding());
+ binding = self.r.resolution(module, key).and_then(|r| r.best_binding());
debug!(?binding);
}
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 6909594..98e4866 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -818,10 +818,10 @@ fn try_lookup_name_relaxed(
// If the first argument in call is `self` suggest calling a method.
if let Some((call_span, args_span)) = self.call_has_self_arg(source) {
let mut args_snippet = String::new();
- if let Some(args_span) = args_span {
- if let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(args_span) {
- args_snippet = snippet;
- }
+ if let Some(args_span) = args_span
+ && let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(args_span)
+ {
+ args_snippet = snippet;
}
err.span_suggestion(
@@ -955,59 +955,57 @@ fn suggest_trait_and_bounds(
Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
false,
) = (source, res, is_macro)
- {
- if let Some(bounds @ [first_bound, .., last_bound]) =
+ && let Some(bounds @ [first_bound, .., last_bound]) =
self.diag_metadata.current_trait_object
- {
- fallback = true;
- let spans: Vec<Span> = bounds
- .iter()
- .map(|bound| bound.span())
- .filter(|&sp| sp != base_error.span)
- .collect();
+ {
+ fallback = true;
+ let spans: Vec<Span> = bounds
+ .iter()
+ .map(|bound| bound.span())
+ .filter(|&sp| sp != base_error.span)
+ .collect();
- let start_span = first_bound.span();
- // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
- let end_span = last_bound.span();
- // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
- let last_bound_span = spans.last().cloned().unwrap();
- let mut multi_span: MultiSpan = spans.clone().into();
- for sp in spans {
- let msg = if sp == last_bound_span {
- format!(
- "...because of {these} bound{s}",
- these = pluralize!("this", bounds.len() - 1),
- s = pluralize!(bounds.len() - 1),
- )
- } else {
- String::new()
- };
- multi_span.push_span_label(sp, msg);
- }
- multi_span.push_span_label(base_error.span, "expected this type to be a trait...");
- err.span_help(
- multi_span,
- "`+` is used to constrain a \"trait object\" type with lifetimes or \
+ let start_span = first_bound.span();
+ // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
+ let end_span = last_bound.span();
+ // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
+ let last_bound_span = spans.last().cloned().unwrap();
+ let mut multi_span: MultiSpan = spans.clone().into();
+ for sp in spans {
+ let msg = if sp == last_bound_span {
+ format!(
+ "...because of {these} bound{s}",
+ these = pluralize!("this", bounds.len() - 1),
+ s = pluralize!(bounds.len() - 1),
+ )
+ } else {
+ String::new()
+ };
+ multi_span.push_span_label(sp, msg);
+ }
+ multi_span.push_span_label(base_error.span, "expected this type to be a trait...");
+ err.span_help(
+ multi_span,
+ "`+` is used to constrain a \"trait object\" type with lifetimes or \
auto-traits; structs and enums can't be bound in that way",
- );
- if bounds.iter().all(|bound| match bound {
- ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..) => true,
- ast::GenericBound::Trait(tr) => tr.span == base_error.span,
- }) {
- let mut sugg = vec![];
- if base_error.span != start_span {
- sugg.push((start_span.until(base_error.span), String::new()));
- }
- if base_error.span != end_span {
- sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));
- }
-
- err.multipart_suggestion(
- "if you meant to use a type and not a trait here, remove the bounds",
- sugg,
- Applicability::MaybeIncorrect,
- );
+ );
+ if bounds.iter().all(|bound| match bound {
+ ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..) => true,
+ ast::GenericBound::Trait(tr) => tr.span == base_error.span,
+ }) {
+ let mut sugg = vec![];
+ if base_error.span != start_span {
+ sugg.push((start_span.until(base_error.span), String::new()));
}
+ if base_error.span != end_span {
+ sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));
+ }
+
+ err.multipart_suggestion(
+ "if you meant to use a type and not a trait here, remove the bounds",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
}
}
@@ -1151,13 +1149,13 @@ fn suggest_self_ty(
}
err.code(E0411);
err.span_label(span, "`Self` is only available in impls, traits, and type definitions");
- if let Some(item) = self.diag_metadata.current_item {
- if let Some(ident) = item.kind.ident() {
- err.span_label(
- ident.span,
- format!("`Self` not allowed in {} {}", item.kind.article(), item.kind.descr()),
- );
- }
+ if let Some(item) = self.diag_metadata.current_item
+ && let Some(ident) = item.kind.ident()
+ {
+ err.span_label(
+ ident.span,
+ format!("`Self` not allowed in {} {}", item.kind.article(), item.kind.descr()),
+ );
}
true
}
@@ -1461,15 +1459,17 @@ fn get_single_associated_item(
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
self.resolve_path(mod_path, None, None)
{
- let resolutions = self.r.resolutions(module).borrow();
- let targets: Vec<_> = resolutions
+ let targets: Vec<_> = self
+ .r
+ .resolutions(module)
+ .borrow()
.iter()
.filter_map(|(key, resolution)| {
resolution
.borrow()
.best_binding()
.map(|binding| binding.res())
- .and_then(|res| if filter_fn(res) { Some((key, res)) } else { None })
+ .and_then(|res| if filter_fn(res) { Some((*key, res)) } else { None })
})
.collect();
if let [target] = targets.as_slice() {
@@ -1932,11 +1932,11 @@ fn smart_resolve_context_dependent_help(
};
let (ctor_def, ctor_vis, fields) = if let Some(struct_ctor) = struct_ctor {
- if let PathSource::Expr(Some(parent)) = source {
- if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind {
- bad_struct_syntax_suggestion(self, err, def_id);
- return true;
- }
+ if let PathSource::Expr(Some(parent)) = source
+ && let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind
+ {
+ bad_struct_syntax_suggestion(self, err, def_id);
+ return true;
}
struct_ctor
} else {
@@ -2300,8 +2300,9 @@ pub(crate) fn find_similarly_named_assoc_item(
return None;
}
- let resolutions = self.r.resolutions(*module);
- let targets = resolutions
+ let targets = self
+ .r
+ .resolutions(*module)
.borrow()
.iter()
.filter_map(|(key, res)| {
@@ -2344,19 +2345,13 @@ fn extract_node_id(t: &Ty) -> Option<NodeId> {
if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
if let Some(node_id) =
self.diag_metadata.current_self_type.as_ref().and_then(extract_node_id)
+ && let Some(resolution) = self.r.partial_res_map.get(&node_id)
+ && let Some(Res::Def(DefKind::Struct | DefKind::Union, did)) = resolution.full_res()
+ && let Some(fields) = self.r.field_idents(did)
+ && let Some(field) = fields.iter().find(|id| ident.name == id.name)
{
// Look for a field with the same name in the current self_type.
- if let Some(resolution) = self.r.partial_res_map.get(&node_id) {
- if let Some(Res::Def(DefKind::Struct | DefKind::Union, did)) =
- resolution.full_res()
- {
- if let Some(fields) = self.r.field_idents(did) {
- if let Some(field) = fields.iter().find(|id| ident.name == id.name) {
- return Some(AssocSuggestion::Field(field.span));
- }
- }
- }
- }
+ return Some(AssocSuggestion::Field(field.span));
}
}
@@ -2391,44 +2386,44 @@ fn extract_node_id(t: &Ty) -> Option<NodeId> {
}
// Look for associated items in the current trait.
- if let Some((module, _)) = self.current_trait_ref {
- if let Ok(binding) = self.r.maybe_resolve_ident_in_module(
+ if let Some((module, _)) = self.current_trait_ref
+ && let Ok(binding) = self.r.maybe_resolve_ident_in_module(
ModuleOrUniformRoot::Module(module),
ident,
ns,
&self.parent_scope,
None,
- ) {
- let res = binding.res();
- if filter_fn(res) {
- match res {
- Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => {
- let has_self = match def_id.as_local() {
- Some(def_id) => self
- .r
- .delegation_fn_sigs
- .get(&def_id)
- .is_some_and(|sig| sig.has_self),
- None => {
- self.r.tcx.fn_arg_idents(def_id).first().is_some_and(|&ident| {
- matches!(ident, Some(Ident { name: kw::SelfLower, .. }))
- })
- }
- };
- if has_self {
- return Some(AssocSuggestion::MethodWithSelf { called });
- } else {
- return Some(AssocSuggestion::AssocFn { called });
+ )
+ {
+ let res = binding.res();
+ if filter_fn(res) {
+ match res {
+ Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => {
+ let has_self = match def_id.as_local() {
+ Some(def_id) => self
+ .r
+ .delegation_fn_sigs
+ .get(&def_id)
+ .is_some_and(|sig| sig.has_self),
+ None => {
+ self.r.tcx.fn_arg_idents(def_id).first().is_some_and(|&ident| {
+ matches!(ident, Some(Ident { name: kw::SelfLower, .. }))
+ })
}
+ };
+ if has_self {
+ return Some(AssocSuggestion::MethodWithSelf { called });
+ } else {
+ return Some(AssocSuggestion::AssocFn { called });
}
- Res::Def(DefKind::AssocConst, _) => {
- return Some(AssocSuggestion::AssocConst);
- }
- Res::Def(DefKind::AssocTy, _) => {
- return Some(AssocSuggestion::AssocType);
- }
- _ => {}
}
+ Res::Def(DefKind::AssocConst, _) => {
+ return Some(AssocSuggestion::AssocConst);
+ }
+ Res::Def(DefKind::AssocTy, _) => {
+ return Some(AssocSuggestion::AssocType);
+ }
+ _ => {}
}
}
}
@@ -2630,7 +2625,7 @@ fn let_binding_suggestion(&self, err: &mut Diag<'_>, ident_span: Span) -> bool {
false
}
- fn find_module(&mut self, def_id: DefId) -> Option<(Module<'ra>, ImportSuggestion)> {
+ fn find_module(&self, def_id: DefId) -> Option<(Module<'ra>, ImportSuggestion)> {
let mut result = None;
let mut seen_modules = FxHashSet::default();
let root_did = self.r.graph_root.def_id();
@@ -2687,7 +2682,7 @@ fn find_module(&mut self, def_id: DefId) -> Option<(Module<'ra>, ImportSuggestio
result
}
- fn collect_enum_ctors(&mut self, def_id: DefId) -> Option<Vec<(Path, DefId, CtorKind)>> {
+ fn collect_enum_ctors(&self, def_id: DefId) -> Option<Vec<(Path, DefId, CtorKind)>> {
self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
let mut variants = Vec::new();
enum_module.for_each_child(self.r, |_, ident, _, name_binding| {
@@ -2704,7 +2699,7 @@ fn collect_enum_ctors(&mut self, def_id: DefId) -> Option<Vec<(Path, DefId, Ctor
/// Adds a suggestion for using an enum's variant when an enum is used instead.
fn suggest_using_enum_variant(
- &mut self,
+ &self,
err: &mut Diag<'_>,
source: PathSource<'_, '_, '_>,
def_id: DefId,
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 08f1f61..88dfb50 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -21,7 +21,7 @@
#![recursion_limit = "256"]
// tidy-alphabetical-end
-use std::cell::{Cell, RefCell};
+use std::cell::{Cell, Ref, RefCell};
use std::collections::BTreeSet;
use std::fmt;
use std::sync::Arc;
@@ -119,7 +119,6 @@ enum Scope<'ra> {
DeriveHelpers(LocalExpnId),
DeriveHelpersCompat,
MacroRules(MacroRulesScopeRef<'ra>),
- CrateRoot,
// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
// lint if it should be reported.
Module(Module<'ra>, Option<NodeId>),
@@ -139,8 +138,8 @@ enum Scope<'ra> {
enum ScopeSet<'ra> {
/// All scopes with the given namespace.
All(Namespace),
- /// Crate root, then extern prelude (used for mixed 2015-2018 mode in macros).
- AbsolutePath(Namespace),
+ /// A module, then extern prelude (used for mixed 2015-2018 mode in macros).
+ ModuleAndExternPrelude(Namespace, Module<'ra>),
/// All scopes with macro namespace and the given macro kind restriction.
Macro(MacroKind),
/// All scopes with the given namespace, used for partially performing late resolution.
@@ -419,8 +418,10 @@ enum ModuleOrUniformRoot<'ra> {
/// Regular module.
Module(Module<'ra>),
- /// Virtual module that denotes resolution in crate root with fallback to extern prelude.
- CrateRootAndExternPrelude,
+ /// Virtual module that denotes resolution in a module with fallback to extern prelude.
+ /// Used for paths starting with `::` coming from 2015 edition macros
+ /// used in 2018+ edition crates.
+ ModuleAndExternPrelude(Module<'ra>),
/// Virtual module that denotes resolution in extern prelude.
/// Used for paths starting with `::` on 2018 edition.
@@ -655,11 +656,23 @@ fn new(
}
impl<'ra> Module<'ra> {
- fn for_each_child<'tcx, R, F>(self, resolver: &mut R, mut f: F)
- where
- R: AsMut<Resolver<'ra, 'tcx>>,
- F: FnMut(&mut R, Ident, Namespace, NameBinding<'ra>),
- {
+ fn for_each_child<'tcx, R: AsRef<Resolver<'ra, 'tcx>>>(
+ self,
+ resolver: &R,
+ mut f: impl FnMut(&R, Ident, Namespace, NameBinding<'ra>),
+ ) {
+ for (key, name_resolution) in resolver.as_ref().resolutions(self).borrow().iter() {
+ if let Some(binding) = name_resolution.borrow().best_binding() {
+ f(resolver, key.ident, key.ns, binding);
+ }
+ }
+ }
+
+ fn for_each_child_mut<'tcx, R: AsMut<Resolver<'ra, 'tcx>>>(
+ self,
+ resolver: &mut R,
+ mut f: impl FnMut(&mut R, Ident, Namespace, NameBinding<'ra>),
+ ) {
for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
if let Some(binding) = name_resolution.borrow().best_binding() {
f(resolver, key.ident, key.ns, binding);
@@ -668,10 +681,7 @@ fn for_each_child<'tcx, R, F>(self, resolver: &mut R, mut f: F)
}
/// This modifies `self` in place. The traits will be stored in `self.traits`.
- fn ensure_traits<'tcx, R>(self, resolver: &mut R)
- where
- R: AsMut<Resolver<'ra, 'tcx>>,
- {
+ fn ensure_traits<'tcx>(self, resolver: &impl AsRef<Resolver<'ra, 'tcx>>) {
let mut traits = self.traits.borrow_mut();
if traits.is_none() {
let mut collected_traits = Vec::new();
@@ -680,7 +690,7 @@ fn ensure_traits<'tcx, R>(self, resolver: &mut R)
return;
}
if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() {
- collected_traits.push((name, binding, r.as_mut().get_module(def_id)))
+ collected_traits.push((name, binding, r.as_ref().get_module(def_id)))
}
});
*traits = Some(collected_traits.into_boxed_slice());
@@ -999,13 +1009,13 @@ fn determined(&self) -> bool {
#[derive(Default, Clone)]
struct ExternPreludeEntry<'ra> {
- binding: Option<NameBinding<'ra>>,
+ binding: Cell<Option<NameBinding<'ra>>>,
introduced_by_item: bool,
}
impl ExternPreludeEntry<'_> {
fn is_import(&self) -> bool {
- self.binding.is_some_and(|binding| binding.is_import())
+ self.binding.get().is_some_and(|binding| binding.is_import())
}
}
@@ -1339,6 +1349,12 @@ fn as_mut(&mut self) -> &mut Resolver<'ra, 'tcx> {
}
}
+impl<'ra, 'tcx> AsRef<Resolver<'ra, 'tcx>> for Resolver<'ra, 'tcx> {
+ fn as_ref(&self) -> &Resolver<'ra, 'tcx> {
+ self
+ }
+}
+
impl<'tcx> Resolver<'_, 'tcx> {
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
self.opt_feed(node).map(|f| f.key())
@@ -1860,7 +1876,7 @@ fn traits_in_module(
// We don't reject trait aliases (`trait_module == None`) because we don't have access to their
// associated items.
fn trait_may_have_item(
- &mut self,
+ &self,
trait_module: Option<Module<'ra>>,
assoc_item: Option<(Symbol, Namespace)>,
) -> bool {
@@ -1892,7 +1908,7 @@ fn find_transitive_imports(
import_ids
}
- fn resolutions(&mut self, module: Module<'ra>) -> &'ra Resolutions<'ra> {
+ fn resolutions(&self, module: Module<'ra>) -> &'ra Resolutions<'ra> {
if module.populate_on_access.get() {
module.populate_on_access.set(false);
self.build_reduced_graph_external(module);
@@ -1901,12 +1917,19 @@ fn resolutions(&mut self, module: Module<'ra>) -> &'ra Resolutions<'ra> {
}
fn resolution(
- &mut self,
+ &self,
+ module: Module<'ra>,
+ key: BindingKey,
+ ) -> Option<Ref<'ra, NameResolution<'ra>>> {
+ self.resolutions(module).borrow().get(&key).map(|resolution| resolution.borrow())
+ }
+
+ fn resolution_or_default(
+ &self,
module: Module<'ra>,
key: BindingKey,
) -> &'ra RefCell<NameResolution<'ra>> {
- *self
- .resolutions(module)
+ self.resolutions(module)
.borrow_mut()
.entry(key)
.or_insert_with(|| self.arenas.alloc_name_resolution())
@@ -1983,7 +2006,7 @@ fn record_use_inner(
// but not introduce it, as used if they are accessed from lexical scope.
if used == Used::Scope {
if let Some(entry) = self.extern_prelude.get(&ident.normalize_to_macros_2_0()) {
- if !entry.introduced_by_item && entry.binding == Some(used_binding) {
+ if !entry.introduced_by_item && entry.binding.get() == Some(used_binding) {
return;
}
}
@@ -2147,7 +2170,7 @@ fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<NameBin
let norm_ident = ident.normalize_to_macros_2_0();
let binding = self.extern_prelude.get(&norm_ident).cloned().and_then(|entry| {
- Some(if let Some(binding) = entry.binding {
+ Some(if let Some(binding) = entry.binding.get() {
if finalize {
if !entry.is_import() {
self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span);
@@ -2172,8 +2195,8 @@ fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<NameBin
})
});
- if let Some(entry) = self.extern_prelude.get_mut(&norm_ident) {
- entry.binding = binding;
+ if let Some(entry) = self.extern_prelude.get(&norm_ident) {
+ entry.binding.set(binding);
}
binding
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index f0225da..20504ea 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -511,7 +511,7 @@ fn register_glob_delegation(&mut self, invoc_id: LocalExpnId) {
}
fn glob_delegation_suffixes(
- &mut self,
+ &self,
trait_def_id: DefId,
impl_def_id: LocalDefId,
) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate> {
@@ -1023,40 +1023,39 @@ fn check_stability_and_deprecation(
node_id: NodeId,
) {
let span = path.span;
- if let Some(stability) = &ext.stability {
- if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. } =
+ if let Some(stability) = &ext.stability
+ && let StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. } =
stability.level
- {
- let feature = stability.feature;
+ {
+ let feature = stability.feature;
- let is_allowed =
- |feature| self.tcx.features().enabled(feature) || span.allows_unstable(feature);
- let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature));
- if !is_allowed(feature) && !allowed_by_implication {
- let lint_buffer = &mut self.lint_buffer;
- let soft_handler = |lint, span, msg: String| {
- lint_buffer.buffer_lint(
- lint,
- node_id,
- span,
- BuiltinLintDiag::UnstableFeature(
- // FIXME make this translatable
- msg.into(),
- ),
- )
- };
- stability::report_unstable(
- self.tcx.sess,
- feature,
- reason.to_opt_reason(),
- issue,
- None,
- is_soft,
+ let is_allowed =
+ |feature| self.tcx.features().enabled(feature) || span.allows_unstable(feature);
+ let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature));
+ if !is_allowed(feature) && !allowed_by_implication {
+ let lint_buffer = &mut self.lint_buffer;
+ let soft_handler = |lint, span, msg: String| {
+ lint_buffer.buffer_lint(
+ lint,
+ node_id,
span,
- soft_handler,
- stability::UnstableKind::Regular,
- );
- }
+ BuiltinLintDiag::UnstableFeature(
+ // FIXME make this translatable
+ msg.into(),
+ ),
+ )
+ };
+ stability::report_unstable(
+ self.tcx.sess,
+ feature,
+ reason.to_opt_reason(),
+ issue,
+ None,
+ is_soft,
+ span,
+ soft_handler,
+ stability::UnstableKind::Regular,
+ );
}
}
if let Some(depr) = &ext.deprecation {
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index 24e15de..6450f63 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -509,9 +509,8 @@ fn collect_link_data<'input, F: BrokenLinkCallback<'input>>(
display_text.map(String::into_boxed_str)
}
-/// Returns a tuple containing a span encompassing all the document fragments and a boolean that is
-/// `true` if any of the fragments are from a macro expansion.
-pub fn span_of_fragments_with_expansion(fragments: &[DocFragment]) -> Option<(Span, bool)> {
+/// Returns a span encompassing all the document fragments.
+pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
let (first_fragment, last_fragment) = match fragments {
[] => return None,
[first, .., last] => (first, last),
@@ -520,15 +519,7 @@ pub fn span_of_fragments_with_expansion(fragments: &[DocFragment]) -> Option<(Sp
if first_fragment.span == DUMMY_SP {
return None;
}
- Some((
- first_fragment.span.to(last_fragment.span),
- fragments.iter().any(|frag| frag.from_expansion),
- ))
-}
-
-/// Returns a span encompassing all the document fragments.
-pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
- span_of_fragments_with_expansion(fragments).map(|(sp, _)| sp)
+ Some(first_fragment.span.to(last_fragment.span))
}
/// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code.
@@ -686,7 +677,7 @@ pub fn source_span_for_markdown_range_inner(
}
}
- let (span, _) = span_of_fragments_with_expansion(fragments)?;
+ let span = span_of_fragments(fragments)?;
let src_span = span.from_inner(InnerSpan::new(
md_range.start + start_bytes,
md_range.end + start_bytes + end_bytes,
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 c69991f..52717d7 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
@@ -339,7 +339,7 @@ pub(crate) fn transform_instance<'tcx>(
} else if let ty::InstanceKind::Virtual(def_id, _) = instance.def {
// Transform self into a trait object of the trait that defines the method for virtual
// functions to match the type erasure done below.
- let upcast_ty = match tcx.trait_of_item(def_id) {
+ let upcast_ty = match tcx.trait_of_assoc(def_id) {
Some(trait_id) => trait_object_ty(
tcx,
ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)),
@@ -364,7 +364,7 @@ pub(crate) fn transform_instance<'tcx>(
};
instance.args = tcx.mk_args_trait(self_ty, instance.args.into_iter().skip(1));
} else if let ty::InstanceKind::VTableShim(def_id) = instance.def
- && let Some(trait_id) = tcx.trait_of_item(def_id)
+ && let Some(trait_id) = tcx.trait_of_assoc(def_id)
{
// Adjust the type ids of VTableShims to the type id expected in the call sites for the
// entry in the vtable (i.e., by using the signature of the closure passed as an argument
@@ -466,7 +466,7 @@ fn implemented_method<'tcx>(
let method_id;
let trait_id;
let trait_method;
- let ancestor = if let Some(impl_id) = tcx.impl_of_method(instance.def_id()) {
+ let ancestor = if let Some(impl_id) = tcx.impl_of_assoc(instance.def_id()) {
// Implementation in an `impl` block
trait_ref = tcx.impl_trait_ref(impl_id)?;
let impl_method = tcx.associated_item(instance.def_id());
@@ -480,7 +480,7 @@ fn implemented_method<'tcx>(
// Provided method in a `trait` block
trait_method = trait_method_bound;
method_id = instance.def_id();
- trait_id = tcx.trait_of_item(method_id)?;
+ trait_id = tcx.trait_of_assoc(method_id)?;
trait_ref = ty::EarlyBinder::bind(TraitRef::from_method(tcx, trait_id, instance.args));
trait_id
} else {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 7bea868..8f624e0 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -343,12 +343,12 @@ pub(crate) fn handle_cli_component(&mut self, component: &str) -> Option<()> {
if let Some(component_to_enable) = component.strip_prefix('+') {
self.explicitly_set = None;
self.enabled_components
- .insert(LinkSelfContainedComponents::from_str(component_to_enable)?);
+ .insert(LinkSelfContainedComponents::from_str(component_to_enable).ok()?);
Some(())
} else if let Some(component_to_disable) = component.strip_prefix('-') {
self.explicitly_set = None;
self.disabled_components
- .insert(LinkSelfContainedComponents::from_str(component_to_disable)?);
+ .insert(LinkSelfContainedComponents::from_str(component_to_disable).ok()?);
Some(())
} else {
None
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index b33e381..44b35e8 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1296,7 +1296,7 @@ pub(crate) fn parse_mir_strip_debuginfo(slot: &mut MirStripDebugInfo, v: Option<
}
pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavorCli>, v: Option<&str>) -> bool {
- match v.and_then(LinkerFlavorCli::from_str) {
+ match v.and_then(|v| LinkerFlavorCli::from_str(v).ok()) {
Some(lf) => *slot = Some(lf),
_ => return false,
}
@@ -2168,8 +2168,6 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
"hash algorithm of source files used to check freshness in cargo (`blake3` or `sha256`)"),
codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
"the backend to use"),
- combine_cgu: bool = (false, parse_bool, [TRACKED],
- "combine CGUs into a single one"),
contract_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
"emit runtime checks for contract pre- and post-conditions (default: no)"),
coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED],
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 9097b27..426480f 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -107,10 +107,10 @@ pub fn feature_err_issue(
let span = span.into();
// Cancel an earlier warning for this same error, if it exists.
- if let Some(span) = span.primary_span() {
- if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) {
- err.cancel()
- }
+ if let Some(span) = span.primary_span()
+ && let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning)
+ {
+ err.cancel()
}
let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() });
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 85bd834..e7097ec 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -313,6 +313,7 @@ pub fn record_trimmed_def_paths(&self) {
|| self.opts.unstable_opts.query_dep_graph
|| self.opts.unstable_opts.dump_mir.is_some()
|| self.opts.unstable_opts.unpretty.is_some()
+ || self.prof.is_args_recording_enabled()
|| self.opts.output_types.contains_key(&OutputType::Mir)
|| std::env::var_os("RUSTC_LOG").is_some()
{
@@ -1362,11 +1363,11 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
sess.dcx().emit_err(errors::InstrumentationNotSupported { us: "XRay".to_string() });
}
- if let Some(flavor) = sess.opts.cg.linker_flavor {
- if let Some(compatible_list) = sess.target.linker_flavor.check_compatibility(flavor) {
- let flavor = flavor.desc();
- sess.dcx().emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list });
- }
+ if let Some(flavor) = sess.opts.cg.linker_flavor
+ && let Some(compatible_list) = sess.target.linker_flavor.check_compatibility(flavor)
+ {
+ let flavor = flavor.desc();
+ sess.dcx().emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list });
}
if sess.opts.unstable_opts.function_return != FunctionReturn::default() {
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index c308087..97d1d9c 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -322,6 +322,7 @@ pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
/// `expn_id.outer_expn_is_descendant_of(ctxt)` is equivalent to but faster than
/// `expn_id.is_descendant_of(ctxt.outer_expn())`.
+ #[inline]
pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool {
HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt)))
}
@@ -394,6 +395,7 @@ pub(crate) fn new(edition: Edition) -> Self {
}
}
+ #[inline]
fn with<R>(f: impl FnOnce(&mut HygieneData) -> R) -> R {
with_session_globals(|session_globals| f(&mut session_globals.hygiene_data.borrow_mut()))
}
@@ -406,6 +408,7 @@ fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash {
}
}
+ #[inline]
fn local_expn_data(&self, expn_id: LocalExpnId) -> &ExpnData {
self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
}
@@ -437,23 +440,28 @@ fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool {
}
}
+ #[inline]
fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
self.syntax_context_data[ctxt.0 as usize].opaque
}
+ #[inline]
fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext {
self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque
}
+ #[inline]
fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
self.syntax_context_data[ctxt.0 as usize].outer_expn
}
+ #[inline]
fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
let data = &self.syntax_context_data[ctxt.0 as usize];
(data.outer_expn, data.outer_transparency)
}
+ #[inline]
fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext {
self.syntax_context_data[ctxt.0 as usize].parent
}
@@ -718,11 +726,13 @@ pub(crate) const fn from_u16(raw: u16) -> SyntaxContext {
SyntaxContext(raw as u32)
}
+ #[inline]
fn from_usize(raw: usize) -> SyntaxContext {
SyntaxContext(u32::try_from(raw).unwrap())
}
/// Extend a syntax context with a given expansion and transparency.
+ #[inline]
pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext {
HygieneData::with(|data| data.apply_mark(self, expn_id, transparency))
}
@@ -743,10 +753,12 @@ pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxCo
/// of g (call it g1), calling remove_mark will result in the SyntaxContext for the
/// invocation of f that created g1.
/// Returns the mark that was removed.
+ #[inline]
pub fn remove_mark(&mut self) -> ExpnId {
HygieneData::with(|data| data.remove_mark(self).0)
}
+ #[inline]
pub fn marks(self) -> Vec<(ExpnId, Transparency)> {
HygieneData::with(|data| data.marks(self))
}
@@ -776,11 +788,13 @@ pub fn marks(self) -> Vec<(ExpnId, Transparency)> {
/// ```
/// This returns the expansion whose definition scope we use to privacy check the resolution,
/// or `None` if we privacy check as usual (i.e., not w.r.t. a macro definition scope).
+ #[inline]
pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
HygieneData::with(|data| data.adjust(self, expn_id))
}
/// Like `SyntaxContext::adjust`, but also normalizes `self` to macros 2.0.
+ #[inline]
pub(crate) fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
HygieneData::with(|data| {
*self = data.normalize_to_macros_2_0(*self);
@@ -901,10 +915,12 @@ fn outer_mark(self) -> (ExpnId, Transparency) {
HygieneData::with(|data| data.outer_mark(self))
}
+ #[inline]
pub(crate) fn dollar_crate_name(self) -> Symbol {
HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name)
}
+ #[inline]
pub fn edition(self) -> Edition {
HygieneData::with(|data| data.expn_data(data.outer_expn(self)).edition)
}
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 9b0e009..3f72ccd 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -167,6 +167,7 @@ pub fn create_session_if_not_set_then<R, F>(edition: Edition, f: F) -> R
}
}
+#[inline]
pub fn with_session_globals<R, F>(f: F) -> R
where
F: FnOnce(&SessionGlobals) -> R,
@@ -715,12 +716,17 @@ pub fn parent_callsite(self) -> Option<Span> {
(!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site)
}
- /// Walk down the expansion ancestors to find a span that's contained within `outer`.
+ /// Find the first ancestor span that's contained within `outer`.
///
- /// The span returned by this method may have a different [`SyntaxContext`] as `outer`.
+ /// This method traverses the macro expansion ancestors until it finds the first span
+ /// that's contained within `outer`.
+ ///
+ /// The span returned by this method may have a different [`SyntaxContext`] than `outer`.
/// If you need to extend the span, use [`find_ancestor_inside_same_ctxt`] instead,
/// because joining spans with different syntax contexts can create unexpected results.
///
+ /// This is used to find the span of the macro call when a parent expr span, i.e. `outer`, is known.
+ ///
/// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt
pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
while !outer.contains(self) {
@@ -729,8 +735,10 @@ pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
Some(self)
}
- /// Walk down the expansion ancestors to find a span with the same [`SyntaxContext`] as
- /// `other`.
+ /// Find the first ancestor span with the same [`SyntaxContext`] as `other`.
+ ///
+ /// This method traverses the macro expansion ancestors until it finds a span
+ /// that has the same [`SyntaxContext`] as `other`.
///
/// Like [`find_ancestor_inside_same_ctxt`], but specifically for when spans might not
/// overlap. Take care when using this, and prefer [`find_ancestor_inside`] or
@@ -746,9 +754,12 @@ pub fn find_ancestor_in_same_ctxt(mut self, other: Span) -> Option<Span> {
Some(self)
}
- /// Walk down the expansion ancestors to find a span that's contained within `outer` and
+ /// Find the first ancestor span that's contained within `outer` and
/// has the same [`SyntaxContext`] as `outer`.
///
+ /// This method traverses the macro expansion ancestors until it finds a span
+ /// that is both contained within `outer` and has the same [`SyntaxContext`] as `outer`.
+ ///
/// This method is the combination of [`find_ancestor_inside`] and
/// [`find_ancestor_in_same_ctxt`] and should be preferred when extending the returned span.
/// If you do not need to modify the span, use [`find_ancestor_inside`] instead.
@@ -762,43 +773,43 @@ pub fn find_ancestor_inside_same_ctxt(mut self, outer: Span) -> Option<Span> {
Some(self)
}
- /// Recursively walk down the expansion ancestors to find the oldest ancestor span with the same
- /// [`SyntaxContext`] the initial span.
+ /// Find the first ancestor span that does not come from an external macro.
///
- /// This method is suitable for peeling through *local* macro expansions to find the "innermost"
- /// span that is still local and shares the same [`SyntaxContext`]. For example, given
+ /// This method traverses the macro expansion ancestors until it finds a span
+ /// that is either from user-written code or from a local macro (defined in the current crate).
///
- /// ```ignore (illustrative example, contains type error)
- /// macro_rules! outer {
- /// ($x: expr) => {
- /// inner!($x)
- /// }
- /// }
+ /// External macros are those defined in dependencies or the standard library.
+ /// This method is useful for reporting errors in user-controllable code and avoiding
+ /// diagnostics inside external macros.
///
- /// macro_rules! inner {
- /// ($x: expr) => {
- /// format!("error: {}", $x)
- /// //~^ ERROR mismatched types
- /// }
- /// }
+ /// # See also
///
- /// fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> {
- /// Err(outer!(x))
- /// }
- /// ```
- ///
- /// if provided the initial span of `outer!(x)` inside `bar`, this method will recurse
- /// the parent callsites until we reach `format!("error: {}", $x)`, at which point it is the
- /// oldest ancestor span that is both still local and shares the same [`SyntaxContext`] as the
- /// initial span.
- pub fn find_oldest_ancestor_in_same_ctxt(self) -> Span {
- let mut cur = self;
- while cur.eq_ctxt(self)
- && let Some(parent_callsite) = cur.parent_callsite()
- {
- cur = parent_callsite;
+ /// - [`Self::find_ancestor_not_from_macro`]
+ /// - [`Self::in_external_macro`]
+ pub fn find_ancestor_not_from_extern_macro(mut self, sm: &SourceMap) -> Option<Span> {
+ while self.in_external_macro(sm) {
+ self = self.parent_callsite()?;
}
- cur
+ Some(self)
+ }
+
+ /// Find the first ancestor span that does not come from any macro expansion.
+ ///
+ /// This method traverses the macro expansion ancestors until it finds a span
+ /// that originates from user-written code rather than any macro-generated code.
+ ///
+ /// This method is useful for reporting errors at the exact location users wrote code
+ /// and providing suggestions at directly editable locations.
+ ///
+ /// # See also
+ ///
+ /// - [`Self::find_ancestor_not_from_extern_macro`]
+ /// - [`Span::from_expansion`]
+ pub fn find_ancestor_not_from_macro(mut self) -> Option<Span> {
+ while self.from_expansion() {
+ self = self.parent_callsite()?;
+ }
+ Some(self)
}
/// Edition of the crate from which this span came.
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 8a36441..d931514 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -826,10 +826,10 @@ pub fn span_wrapped_by_angle_or_parentheses(&self, span: Span) -> bool {
/// Given a `Span`, tries to get a shorter span ending just after the first occurrence of `char`
/// `c`.
pub fn span_through_char(&self, sp: Span, c: char) -> Span {
- if let Ok(snippet) = self.span_to_snippet(sp) {
- if let Some(offset) = snippet.find(c) {
- return sp.with_hi(BytePos(sp.lo().0 + (offset + c.len_utf8()) as u32));
- }
+ if let Ok(snippet) = self.span_to_snippet(sp)
+ && let Some(offset) = snippet.find(c)
+ {
+ return sp.with_hi(BytePos(sp.lo().0 + (offset + c.len_utf8()) as u32));
}
sp
}
diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml
index 0121c75..56932c2 100644
--- a/compiler/rustc_target/Cargo.toml
+++ b/compiler/rustc_target/Cargo.toml
@@ -12,7 +12,10 @@
rustc_macros = { path = "../rustc_macros" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
+serde = "1.0.219"
+serde_derive = "1.0.219"
serde_json = "1.0.59"
+serde_path_to_error = "0.1.17"
tracing = "0.1"
# tidy-alphabetical-end
diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs
index 27b41cc0..d567ad4 100644
--- a/compiler/rustc_target/src/callconv/loongarch.rs
+++ b/compiler/rustc_target/src/callconv/loongarch.rs
@@ -314,16 +314,15 @@ fn classify_arg<'a, Ty, C>(
}
fn extend_integer_width<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64) {
- if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
- if let Primitive::Int(i, _) = scalar.primitive() {
- // 32-bit integers are always sign-extended
- if i.size().bits() == 32 && xlen > 32 {
- if let PassMode::Direct(ref mut attrs) = arg.mode {
- attrs.ext(ArgExtension::Sext);
- return;
- }
- }
- }
+ if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr
+ && let Primitive::Int(i, _) = scalar.primitive()
+ && i.size().bits() == 32
+ && xlen > 32
+ && let PassMode::Direct(ref mut attrs) = arg.mode
+ {
+ // 32-bit integers are always sign-extended
+ attrs.ext(ArgExtension::Sext);
+ return;
}
arg.extend_integer_width_to(xlen);
diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs
index 77c0cf0..0209838 100644
--- a/compiler/rustc_target/src/callconv/mips64.rs
+++ b/compiler/rustc_target/src/callconv/mips64.rs
@@ -6,15 +6,14 @@
fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
// Always sign extend u32 values on 64-bit mips
- if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
- if let Primitive::Int(i, signed) = scalar.primitive() {
- if !signed && i.size().bits() == 32 {
- if let PassMode::Direct(ref mut attrs) = arg.mode {
- attrs.ext(ArgExtension::Sext);
- return;
- }
- }
- }
+ if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr
+ && let Primitive::Int(i, signed) = scalar.primitive()
+ && !signed
+ && i.size().bits() == 32
+ && let PassMode::Direct(ref mut attrs) = arg.mode
+ {
+ attrs.ext(ArgExtension::Sext);
+ return;
}
arg.extend_integer_width_to(bits);
@@ -58,13 +57,12 @@ fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
ret.cast_to(reg);
return;
}
- } else if ret.layout.fields.count() == 2 {
- if let Some(reg0) = float_reg(cx, ret, 0) {
- if let Some(reg1) = float_reg(cx, ret, 1) {
- ret.cast_to(CastTarget::pair(reg0, reg1));
- return;
- }
- }
+ } else if ret.layout.fields.count() == 2
+ && let Some(reg0) = float_reg(cx, ret, 0)
+ && let Some(reg1) = float_reg(cx, ret, 1)
+ {
+ ret.cast_to(CastTarget::pair(reg0, reg1));
+ return;
}
}
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index ab32712..63e5674 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -495,18 +495,16 @@ pub fn pass_by_stack_offset(&mut self, byval_align: Option<Align>) {
pub fn extend_integer_width_to(&mut self, bits: u64) {
// Only integers have signedness
- if let BackendRepr::Scalar(scalar) = self.layout.backend_repr {
- if let Primitive::Int(i, signed) = scalar.primitive() {
- if i.size().bits() < bits {
- if let PassMode::Direct(ref mut attrs) = self.mode {
- if signed {
- attrs.ext(ArgExtension::Sext)
- } else {
- attrs.ext(ArgExtension::Zext)
- };
- }
- }
- }
+ if let BackendRepr::Scalar(scalar) = self.layout.backend_repr
+ && let Primitive::Int(i, signed) = scalar.primitive()
+ && i.size().bits() < bits
+ && let PassMode::Direct(ref mut attrs) = self.mode
+ {
+ if signed {
+ attrs.ext(ArgExtension::Sext)
+ } else {
+ attrs.ext(ArgExtension::Zext)
+ };
}
}
diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs
index a06f54d..161e2c1 100644
--- a/compiler/rustc_target/src/callconv/riscv.rs
+++ b/compiler/rustc_target/src/callconv/riscv.rs
@@ -393,16 +393,14 @@ fn classify_arg<'a, Ty, C>(
}
fn extend_integer_width<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64) {
- if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
- if let Primitive::Int(i, _) = scalar.primitive() {
- // 32-bit integers are always sign-extended
- if i.size().bits() == 32 && xlen > 32 {
- if let PassMode::Direct(ref mut attrs) = arg.mode {
- attrs.ext(ArgExtension::Sext);
- return;
- }
- }
- }
+ if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr
+ && let Primitive::Int(i, _) = scalar.primitive()
+ && i.size().bits() == 32
+ && xlen > 32
+ && let PassMode::Direct(ref mut attrs) = arg.mode
+ {
+ attrs.ext(ArgExtension::Sext);
+ return;
}
arg.extend_integer_width_to(xlen);
diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs
index 4fcc477..896609b 100644
--- a/compiler/rustc_target/src/json.rs
+++ b/compiler/rustc_target/src/json.rs
@@ -114,3 +114,18 @@ fn to_json(&self) -> Json {
self.to_string().to_json()
}
}
+
+macro_rules! serde_deserialize_from_str {
+ ($ty:ty) => {
+ impl<'de> serde::Deserialize<'de> for $ty {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ let s = String::deserialize(deserializer)?;
+ FromStr::from_str(&s).map_err(serde::de::Error::custom)
+ }
+ }
+ };
+}
+pub(crate) use serde_deserialize_from_str;
diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs
index 6c716f8..d27c192 100644
--- a/compiler/rustc_target/src/spec/json.rs
+++ b/compiler/rustc_target/src/spec/json.rs
@@ -1,60 +1,47 @@
-use std::borrow::Cow;
use std::collections::BTreeMap;
use std::str::FromStr;
-use rustc_abi::{Align, AlignFromBytesError, ExternAbi};
-use serde_json::Value;
+use rustc_abi::{Align, AlignFromBytesError};
-use super::{Target, TargetKind, TargetOptions, TargetWarnings};
+use super::crt_objects::CrtObjects;
+use super::{
+ BinaryFormat, CodeModel, DebuginfoKind, FloatAbi, FramePointer, LinkArgsCli,
+ LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFlavorCli, LldFlavor,
+ MergeFunctions, PanicStrategy, RelocModel, RelroLevel, RustcAbi, SanitizerSet,
+ SmallDataThresholdSupport, SplitDebuginfo, StackProbeType, StaticCow, SymbolVisibility, Target,
+ TargetKind, TargetOptions, TargetWarnings, TlsModel,
+};
use crate::json::{Json, ToJson};
use crate::spec::AbiMap;
impl Target {
/// Loads a target descriptor from a JSON object.
- pub fn from_json(obj: Json) -> Result<(Target, TargetWarnings), String> {
- // While ugly, this code must remain this way to retain
- // compatibility with existing JSON fields and the internal
- // expected naming of the Target and TargetOptions structs.
- // To ensure compatibility is retained, the built-in targets
- // are round-tripped through this code to catch cases where
- // the JSON parser is not updated to match the structs.
+ pub fn from_json(json: &str) -> Result<(Target, TargetWarnings), String> {
+ let json_deserializer = &mut serde_json::Deserializer::from_str(json);
- let mut obj = match obj {
- Value::Object(obj) => obj,
- _ => return Err("Expected JSON object for target")?,
- };
-
- let mut get_req_field = |name: &str| {
- obj.remove(name)
- .and_then(|j| j.as_str().map(str::to_string))
- .ok_or_else(|| format!("Field {name} in target specification is required"))
- };
+ let json: TargetSpecJson =
+ serde_path_to_error::deserialize(json_deserializer).map_err(|err| err.to_string())?;
let mut base = Target {
- llvm_target: get_req_field("llvm-target")?.into(),
+ llvm_target: json.llvm_target,
metadata: Default::default(),
- pointer_width: get_req_field("target-pointer-width")?
- .parse::<u32>()
- .map_err(|_| "target-pointer-width must be an integer".to_string())?,
- data_layout: get_req_field("data-layout")?.into(),
- arch: get_req_field("arch")?.into(),
+ pointer_width: json
+ .target_pointer_width
+ .parse()
+ .map_err(|err| format!("invalid target-pointer-width: {err}"))?,
+ data_layout: json.data_layout,
+ arch: json.arch,
options: Default::default(),
};
// FIXME: This doesn't properly validate anything and just ignores the data if it's invalid.
// That's okay for now, the only use of this is when generating docs, which we don't do for
// custom targets.
- if let Some(Json::Object(mut metadata)) = obj.remove("metadata") {
- base.metadata.description = metadata
- .remove("description")
- .and_then(|desc| desc.as_str().map(|desc| desc.to_owned().into()));
- base.metadata.tier = metadata
- .remove("tier")
- .and_then(|tier| tier.as_u64())
- .filter(|tier| (1..=3).contains(tier));
- base.metadata.host_tools =
- metadata.remove("host_tools").and_then(|host| host.as_bool());
- base.metadata.std = metadata.remove("std").and_then(|host| host.as_bool());
+ if let Some(metadata) = json.metadata {
+ base.metadata.description = metadata.description;
+ base.metadata.tier = metadata.tier.filter(|tier| (1..=3).contains(tier));
+ base.metadata.host_tools = metadata.host_tools;
+ base.metadata.std = metadata.std;
}
let alignment_error = |field_name: &str, error: AlignFromBytesError| -> String {
@@ -65,640 +52,188 @@ pub fn from_json(obj: Json) -> Result<(Target, TargetWarnings), String> {
format!("`{}` bits is not a valid value for {field_name}: {msg}", error.align() * 8)
};
- let mut incorrect_type = vec![];
-
- macro_rules! key {
- ($key_name:ident) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(s) = obj.remove(&name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
- base.$key_name = s;
+ macro_rules! forward {
+ ($name:ident) => {
+ if let Some($name) = json.$name {
+ base.$name = $name;
}
- } );
- ($key_name:ident = $json_name:expr) => ( {
- let name = $json_name;
- if let Some(s) = obj.remove(name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
- base.$key_name = s;
+ };
+ }
+ macro_rules! forward_opt {
+ ($name:ident) => {
+ if let Some($name) = json.$name {
+ base.$name = Some($name);
}
- } );
- ($key_name:ident = $json_name:expr, u64 as $int_ty:ty) => ( {
- let name = $json_name;
- if let Some(s) = obj.remove(name).and_then(|b| b.as_u64()) {
- base.$key_name = s as $int_ty;
- }
- } );
- ($key_name:ident, bool) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) {
- base.$key_name = s;
- }
- } );
- ($key_name:ident = $json_name:expr, bool) => ( {
- let name = $json_name;
- if let Some(s) = obj.remove(name).and_then(|b| b.as_bool()) {
- base.$key_name = s;
- }
- } );
- ($key_name:ident, u32) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
- if s < 1 || s > 5 {
- return Err("Not a valid DWARF version number".into());
- }
- base.$key_name = s as u32;
- }
- } );
- ($key_name:ident, Option<bool>) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) {
- base.$key_name = Some(s);
- }
- } );
- ($key_name:ident, Option<u64>) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
- base.$key_name = Some(s);
- }
- } );
- ($key_name:ident, Option<StaticCow<str>>) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(s) = obj.remove(&name).and_then(|b| Some(b.as_str()?.to_string())) {
- base.$key_name = Some(s.into());
- }
- } );
- ($key_name:ident, Option<Align>) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(b) = obj.remove(&name).and_then(|b| b.as_u64()) {
- match Align::from_bits(b) {
- Ok(align) => base.$key_name = Some(align),
- Err(e) => return Err(alignment_error(&name, e)),
- }
- }
- } );
- ($key_name:ident, BinaryFormat) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|f| f.as_str().and_then(|s| {
- match s.parse::<super::BinaryFormat>() {
- Ok(binary_format) => base.$key_name = binary_format,
- _ => return Some(Err(format!(
- "'{s}' is not a valid value for binary_format. \
- Use 'coff', 'elf', 'mach-o', 'wasm' or 'xcoff' "
- ))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, MergeFunctions) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
- match s.parse::<super::MergeFunctions>() {
- Ok(mergefunc) => base.$key_name = mergefunc,
- _ => return Some(Err(format!("'{}' is not a valid value for \
- merge-functions. Use 'disabled', \
- 'trampolines', or 'aliases'.",
- s))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, FloatAbi) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
- match s.parse::<super::FloatAbi>() {
- Ok(float_abi) => base.$key_name = Some(float_abi),
- _ => return Some(Err(format!("'{}' is not a valid value for \
- llvm-floatabi. Use 'soft' or 'hard'.",
- s))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, RustcAbi) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
- match s.parse::<super::RustcAbi>() {
- Ok(rustc_abi) => base.$key_name = Some(rustc_abi),
- _ => return Some(Err(format!(
- "'{s}' is not a valid value for rustc-abi. \
- Use 'x86-softfloat' or leave the field unset."
- ))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, RelocModel) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
- match s.parse::<super::RelocModel>() {
- Ok(relocation_model) => base.$key_name = relocation_model,
- _ => return Some(Err(format!("'{}' is not a valid relocation model. \
- Run `rustc --print relocation-models` to \
- see the list of supported values.", s))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, CodeModel) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
- match s.parse::<super::CodeModel>() {
- Ok(code_model) => base.$key_name = Some(code_model),
- _ => return Some(Err(format!("'{}' is not a valid code model. \
- Run `rustc --print code-models` to \
- see the list of supported values.", s))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, TlsModel) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
- match s.parse::<super::TlsModel>() {
- Ok(tls_model) => base.$key_name = tls_model,
- _ => return Some(Err(format!("'{}' is not a valid TLS model. \
- Run `rustc --print tls-models` to \
- see the list of supported values.", s))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, SmallDataThresholdSupport) => ( {
- obj.remove("small-data-threshold-support").and_then(|o| o.as_str().and_then(|s| {
- match s.parse::<super::SmallDataThresholdSupport>() {
- Ok(support) => base.small_data_threshold_support = support,
- _ => return Some(Err(format!("'{s}' is not a valid value for small-data-threshold-support."))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, PanicStrategy) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
- match s {
- "unwind" => base.$key_name = super::PanicStrategy::Unwind,
- "abort" => base.$key_name = super::PanicStrategy::Abort,
- _ => return Some(Err(format!("'{}' is not a valid value for \
- panic-strategy. Use 'unwind' or 'abort'.",
- s))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, RelroLevel) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
- match s.parse::<super::RelroLevel>() {
- Ok(level) => base.$key_name = level,
- _ => return Some(Err(format!("'{}' is not a valid value for \
- relro-level. Use 'full', 'partial, or 'off'.",
- s))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, Option<SymbolVisibility>) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
- match s.parse::<super::SymbolVisibility>() {
- Ok(level) => base.$key_name = Some(level),
- _ => return Some(Err(format!("'{}' is not a valid value for \
- symbol-visibility. Use 'hidden', 'protected, or 'interposable'.",
- s))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, DebuginfoKind) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
- match s.parse::<super::DebuginfoKind>() {
- Ok(level) => base.$key_name = level,
- _ => return Some(Err(
- format!("'{s}' is not a valid value for debuginfo-kind. Use 'dwarf', \
- 'dwarf-dsym' or 'pdb'.")
- )),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, SplitDebuginfo) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
- match s.parse::<super::SplitDebuginfo>() {
- Ok(level) => base.$key_name = level,
- _ => return Some(Err(format!("'{}' is not a valid value for \
- split-debuginfo. Use 'off' or 'dsymutil'.",
- s))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, list) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(j) = obj.remove(&name) {
- if let Some(v) = j.as_array() {
- base.$key_name = v.iter()
- .map(|a| a.as_str().unwrap().to_string().into())
- .collect();
- } else {
- incorrect_type.push(name)
- }
- }
- } );
- ($key_name:ident, opt_list) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(j) = obj.remove(&name) {
- if let Some(v) = j.as_array() {
- base.$key_name = Some(v.iter()
- .map(|a| a.as_str().unwrap().to_string().into())
- .collect());
- } else {
- incorrect_type.push(name)
- }
- }
- } );
- ($key_name:ident, fallible_list) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|j| {
- if let Some(v) = j.as_array() {
- match v.iter().map(|a| FromStr::from_str(a.as_str().unwrap())).collect() {
- Ok(l) => { base.$key_name = l },
- // FIXME: `fallible_list` can't re-use the `key!` macro for list
- // elements and the error messages from that macro, so it has a bad
- // generic message instead
- Err(_) => return Some(Err(
- format!("`{:?}` is not a valid value for `{}`", j, name)
- )),
- }
- } else {
- incorrect_type.push(name)
- }
- Some(Ok(()))
- }).unwrap_or(Ok(()))
- } );
- ($key_name:ident, optional) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(o) = obj.remove(&name) {
- base.$key_name = o
- .as_str()
- .map(|s| s.to_string().into());
- }
- } );
- ($key_name:ident = $json_name:expr, LldFlavor) => ( {
- let name = $json_name;
- obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
- if let Some(flavor) = super::LldFlavor::from_str(&s) {
- base.$key_name = flavor;
- } else {
- return Some(Err(format!(
- "'{}' is not a valid value for lld-flavor. \
- Use 'darwin', 'gnu', 'link' or 'wasm'.",
- s)))
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident = $json_name:expr, LinkerFlavorCli) => ( {
- let name = $json_name;
- obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
- match super::LinkerFlavorCli::from_str(s) {
- Some(linker_flavor) => base.$key_name = linker_flavor,
- _ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \
- Use {}", s, super::LinkerFlavorCli::one_of()))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident, StackProbeType) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| match super::StackProbeType::from_json(&o) {
- Ok(v) => {
- base.$key_name = v;
- Some(Ok(()))
- },
- Err(s) => Some(Err(
- format!("`{:?}` is not a valid value for `{}`: {}", o, name, s)
- )),
- }).unwrap_or(Ok(()))
- } );
- ($key_name:ident, SanitizerSet) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(o) = obj.remove(&name) {
- if let Some(a) = o.as_array() {
- for s in a {
- use super::SanitizerSet;
- base.$key_name |= match s.as_str() {
- Some("address") => SanitizerSet::ADDRESS,
- Some("cfi") => SanitizerSet::CFI,
- Some("dataflow") => SanitizerSet::DATAFLOW,
- Some("kcfi") => SanitizerSet::KCFI,
- Some("kernel-address") => SanitizerSet::KERNELADDRESS,
- Some("leak") => SanitizerSet::LEAK,
- Some("memory") => SanitizerSet::MEMORY,
- Some("memtag") => SanitizerSet::MEMTAG,
- Some("safestack") => SanitizerSet::SAFESTACK,
- Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
- Some("thread") => SanitizerSet::THREAD,
- Some("hwaddress") => SanitizerSet::HWADDRESS,
- Some(s) => return Err(format!("unknown sanitizer {}", s)),
- _ => return Err(format!("not a string: {:?}", s)),
- };
- }
- } else {
- incorrect_type.push(name)
- }
- }
- Ok::<(), String>(())
- } );
- ($key_name:ident, link_self_contained_components) => ( {
- // Skeleton of what needs to be parsed:
- //
- // ```
- // $name: {
- // "components": [
- // <array of strings>
- // ]
- // }
- // ```
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(o) = obj.remove(&name) {
- if let Some(o) = o.as_object() {
- let component_array = o.get("components")
- .ok_or_else(|| format!("{name}: expected a \
- JSON object with a `components` field."))?;
- let component_array = component_array.as_array()
- .ok_or_else(|| format!("{name}.components: expected a JSON array"))?;
- let mut components = super::LinkSelfContainedComponents::empty();
- for s in component_array {
- components |= match s.as_str() {
- Some(s) => {
- super::LinkSelfContainedComponents::from_str(s)
- .ok_or_else(|| format!("unknown \
- `-Clink-self-contained` component: {s}"))?
- },
- _ => return Err(format!("not a string: {:?}", s)),
- };
- }
- base.$key_name = super::LinkSelfContainedDefault::WithComponents(components);
- } else {
- incorrect_type.push(name)
- }
- }
- Ok::<(), String>(())
- } );
- ($key_name:ident = $json_name:expr, link_self_contained_backwards_compatible) => ( {
- let name = $json_name;
- obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
- match s.parse::<super::LinkSelfContainedDefault>() {
- Ok(lsc_default) => base.$key_name = lsc_default,
- _ => return Some(Err(format!("'{}' is not a valid `-Clink-self-contained` default. \
- Use 'false', 'true', 'musl' or 'mingw'", s))),
- }
- Some(Ok(()))
- })).unwrap_or(Ok(()))
- } );
- ($key_name:ident = $json_name:expr, link_objects) => ( {
- let name = $json_name;
- if let Some(val) = obj.remove(name) {
- let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
- JSON object with fields per CRT object kind.", name))?;
- let mut args = super::CrtObjects::new();
- for (k, v) in obj {
- let kind = super::LinkOutputKind::from_str(&k).ok_or_else(|| {
- format!("{}: '{}' is not a valid value for CRT object kind. \
- Use '(dynamic,static)-(nopic,pic)-exe' or \
- '(dynamic,static)-dylib' or 'wasi-reactor-exe'", name, k)
- })?;
-
- let v = v.as_array().ok_or_else(||
- format!("{}.{}: expected a JSON array", name, k)
- )?.iter().enumerate()
- .map(|(i,s)| {
- let s = s.as_str().ok_or_else(||
- format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
- Ok(s.to_string().into())
- })
- .collect::<Result<Vec<_>, String>>()?;
-
- args.insert(kind, v);
- }
- base.$key_name = args;
- }
- } );
- ($key_name:ident = $json_name:expr, link_args) => ( {
- let name = $json_name;
- if let Some(val) = obj.remove(name) {
- let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
- JSON object with fields per linker-flavor.", name))?;
- let mut args = super::LinkArgsCli::new();
- for (k, v) in obj {
- let flavor = super::LinkerFlavorCli::from_str(&k).ok_or_else(|| {
- format!("{}: '{}' is not a valid value for linker-flavor. \
- Use 'em', 'gcc', 'ld' or 'msvc'", name, k)
- })?;
-
- let v = v.as_array().ok_or_else(||
- format!("{}.{}: expected a JSON array", name, k)
- )?.iter().enumerate()
- .map(|(i,s)| {
- let s = s.as_str().ok_or_else(||
- format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
- Ok(s.to_string().into())
- })
- .collect::<Result<Vec<_>, String>>()?;
-
- args.insert(flavor, v);
- }
- base.$key_name = args;
- }
- } );
- ($key_name:ident, env) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(o) = obj.remove(&name) {
- if let Some(a) = o.as_array() {
- for o in a {
- if let Some(s) = o.as_str() {
- if let [k, v] = *s.split('=').collect::<Vec<_>>() {
- base.$key_name
- .to_mut()
- .push((k.to_string().into(), v.to_string().into()))
- }
- }
- }
- } else {
- incorrect_type.push(name)
- }
- }
- } );
- ($key_name:ident, target_families) => ( {
- if let Some(value) = obj.remove("target-family") {
- if let Some(v) = value.as_array() {
- base.$key_name = v.iter()
- .map(|a| a.as_str().unwrap().to_string().into())
- .collect();
- } else if let Some(v) = value.as_str() {
- base.$key_name = vec![v.to_string().into()].into();
- }
- }
- } );
+ };
}
- if let Some(j) = obj.remove("target-endian") {
- if let Some(s) = j.as_str() {
- base.endian = s.parse()?;
- } else {
- incorrect_type.push("target-endian".into())
- }
+ if let Some(target_endian) = json.target_endian {
+ base.endian = target_endian.0;
}
- if let Some(fp) = obj.remove("frame-pointer") {
- if let Some(s) = fp.as_str() {
- base.frame_pointer = s
- .parse()
- .map_err(|()| format!("'{s}' is not a valid value for frame-pointer"))?;
- } else {
- incorrect_type.push("frame-pointer".into())
- }
- }
+ forward!(frame_pointer);
+ forward!(c_int_width);
+ forward_opt!(c_enum_min_bits); // if None, matches c_int_width
+ forward!(os);
+ forward!(env);
+ forward!(abi);
+ forward!(vendor);
+ forward_opt!(linker);
+ forward!(linker_flavor_json);
+ forward!(lld_flavor_json);
+ forward!(linker_is_gnu_json);
+ forward!(pre_link_objects);
+ forward!(post_link_objects);
+ forward!(pre_link_objects_self_contained);
+ forward!(post_link_objects_self_contained);
- key!(c_int_width = "target-c-int-width", u64 as u16);
- key!(c_enum_min_bits, Option<u64>); // if None, matches c_int_width
- key!(os);
- key!(env);
- key!(abi);
- key!(vendor);
- key!(linker, optional);
- key!(linker_flavor_json = "linker-flavor", LinkerFlavorCli)?;
- key!(lld_flavor_json = "lld-flavor", LldFlavor)?;
- key!(linker_is_gnu_json = "linker-is-gnu", bool);
- key!(pre_link_objects = "pre-link-objects", link_objects);
- key!(post_link_objects = "post-link-objects", link_objects);
- key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects);
- key!(post_link_objects_self_contained = "post-link-objects-fallback", link_objects);
// Deserializes the backwards-compatible variants of `-Clink-self-contained`
- key!(
- link_self_contained = "crt-objects-fallback",
- link_self_contained_backwards_compatible
- )?;
+ if let Some(link_self_contained) = json.link_self_contained_backwards_compatible {
+ base.link_self_contained = link_self_contained;
+ }
// Deserializes the components variant of `-Clink-self-contained`
- key!(link_self_contained, link_self_contained_components)?;
- key!(pre_link_args_json = "pre-link-args", link_args);
- key!(late_link_args_json = "late-link-args", link_args);
- key!(late_link_args_dynamic_json = "late-link-args-dynamic", link_args);
- key!(late_link_args_static_json = "late-link-args-static", link_args);
- key!(post_link_args_json = "post-link-args", link_args);
- key!(link_script, optional);
- key!(link_env, env);
- key!(link_env_remove, list);
- key!(asm_args, list);
- key!(cpu);
- key!(need_explicit_cpu, bool);
- key!(features);
- key!(dynamic_linking, bool);
- key!(direct_access_external_data, Option<bool>);
- key!(dll_tls_export, bool);
- key!(only_cdylib, bool);
- key!(executables, bool);
- key!(relocation_model, RelocModel)?;
- key!(code_model, CodeModel)?;
- key!(tls_model, TlsModel)?;
- key!(disable_redzone, bool);
- key!(function_sections, bool);
- key!(dll_prefix);
- key!(dll_suffix);
- key!(exe_suffix);
- key!(staticlib_prefix);
- key!(staticlib_suffix);
- key!(families, target_families);
- key!(abi_return_struct_as_int, bool);
- key!(is_like_aix, bool);
- key!(is_like_darwin, bool);
- key!(is_like_solaris, bool);
- key!(is_like_windows, bool);
- key!(is_like_msvc, bool);
- key!(is_like_wasm, bool);
- key!(is_like_android, bool);
- key!(binary_format, BinaryFormat)?;
- key!(default_dwarf_version, u32);
- key!(allows_weak_linkage, bool);
- key!(has_rpath, bool);
- key!(no_default_libraries, bool);
- key!(position_independent_executables, bool);
- key!(static_position_independent_executables, bool);
- key!(plt_by_default, bool);
- key!(relro_level, RelroLevel)?;
- key!(archive_format);
- key!(allow_asm, bool);
- key!(main_needs_argc_argv, bool);
- key!(has_thread_local, bool);
- key!(obj_is_bitcode, bool);
- key!(bitcode_llvm_cmdline);
- key!(max_atomic_width, Option<u64>);
- key!(min_atomic_width, Option<u64>);
- key!(atomic_cas, bool);
- key!(panic_strategy, PanicStrategy)?;
- key!(crt_static_allows_dylibs, bool);
- key!(crt_static_default, bool);
- key!(crt_static_respected, bool);
- key!(stack_probes, StackProbeType)?;
- key!(min_global_align, Option<Align>);
- key!(default_codegen_units, Option<u64>);
- key!(default_codegen_backend, Option<StaticCow<str>>);
- key!(trap_unreachable, bool);
- key!(requires_lto, bool);
- key!(singlethread, bool);
- key!(no_builtins, bool);
- key!(default_visibility, Option<SymbolVisibility>)?;
- key!(emit_debug_gdb_scripts, bool);
- key!(requires_uwtable, bool);
- key!(default_uwtable, bool);
- key!(simd_types_indirect, bool);
- key!(limit_rdylib_exports, bool);
- key!(override_export_symbols, opt_list);
- key!(merge_functions, MergeFunctions)?;
- key!(mcount = "target-mcount");
- key!(llvm_mcount_intrinsic, optional);
- key!(llvm_abiname);
- key!(llvm_floatabi, FloatAbi)?;
- key!(rustc_abi, RustcAbi)?;
- key!(relax_elf_relocations, bool);
- key!(llvm_args, list);
- key!(use_ctors_section, bool);
- key!(eh_frame_header, bool);
- key!(has_thumb_interworking, bool);
- key!(debuginfo_kind, DebuginfoKind)?;
- key!(split_debuginfo, SplitDebuginfo)?;
- key!(supported_split_debuginfo, fallible_list)?;
- key!(supported_sanitizers, SanitizerSet)?;
- key!(generate_arange_section, bool);
- key!(supports_stack_protector, bool);
- key!(small_data_threshold_support, SmallDataThresholdSupport)?;
- key!(entry_name);
- key!(supports_xray, bool);
+ if let Some(link_self_contained) = json.link_self_contained {
+ let components = link_self_contained
+ .components
+ .into_iter()
+ .fold(LinkSelfContainedComponents::empty(), |a, b| a | b);
+ base.link_self_contained = LinkSelfContainedDefault::WithComponents(components);
+ }
+
+ forward!(pre_link_args_json);
+ forward!(late_link_args_json);
+ forward!(late_link_args_dynamic_json);
+ forward!(late_link_args_static_json);
+ forward!(post_link_args_json);
+ forward_opt!(link_script);
+
+ if let Some(link_env) = json.link_env {
+ for s in link_env {
+ if let [k, v] = *s.split('=').collect::<Vec<_>>() {
+ base.link_env.to_mut().push((k.to_string().into(), v.to_string().into()))
+ } else {
+ return Err(format!("link-env value '{s}' must be of the pattern 'KEY=VALUE'"));
+ }
+ }
+ }
+
+ forward!(link_env_remove);
+ forward!(asm_args);
+ forward!(cpu);
+ forward!(need_explicit_cpu);
+ forward!(features);
+ forward!(dynamic_linking);
+ forward_opt!(direct_access_external_data);
+ forward!(dll_tls_export);
+ forward!(only_cdylib);
+ forward!(executables);
+ forward!(relocation_model);
+ forward_opt!(code_model);
+ forward!(tls_model);
+ forward!(disable_redzone);
+ forward!(function_sections);
+ forward!(dll_prefix);
+ forward!(dll_suffix);
+ forward!(exe_suffix);
+ forward!(staticlib_prefix);
+ forward!(staticlib_suffix);
+
+ if let Some(target_family) = json.target_family {
+ match target_family {
+ TargetFamiliesJson::Array(families) => base.families = families,
+ TargetFamiliesJson::String(family) => base.families = vec![family].into(),
+ }
+ }
+
+ forward!(abi_return_struct_as_int);
+ forward!(is_like_aix);
+ forward!(is_like_darwin);
+ forward!(is_like_solaris);
+ forward!(is_like_windows);
+ forward!(is_like_msvc);
+ forward!(is_like_wasm);
+ forward!(is_like_android);
+ forward!(binary_format);
+ forward!(default_dwarf_version);
+ forward!(allows_weak_linkage);
+ forward!(has_rpath);
+ forward!(no_default_libraries);
+ forward!(position_independent_executables);
+ forward!(static_position_independent_executables);
+ forward!(plt_by_default);
+ forward!(relro_level);
+ forward!(archive_format);
+ forward!(allow_asm);
+ forward!(main_needs_argc_argv);
+ forward!(has_thread_local);
+ forward!(obj_is_bitcode);
+ forward!(bitcode_llvm_cmdline);
+ forward_opt!(max_atomic_width);
+ forward_opt!(min_atomic_width);
+ forward!(atomic_cas);
+ forward!(panic_strategy);
+ forward!(crt_static_allows_dylibs);
+ forward!(crt_static_default);
+ forward!(crt_static_respected);
+ forward!(stack_probes);
+
+ if let Some(min_global_align) = json.min_global_align {
+ match Align::from_bits(min_global_align) {
+ Ok(align) => base.min_global_align = Some(align),
+ Err(e) => return Err(alignment_error("min-global-align", e)),
+ }
+ }
+
+ forward_opt!(default_codegen_units);
+ forward_opt!(default_codegen_backend);
+ forward!(trap_unreachable);
+ forward!(requires_lto);
+ forward!(singlethread);
+ forward!(no_builtins);
+ forward_opt!(default_visibility);
+ forward!(emit_debug_gdb_scripts);
+ forward!(requires_uwtable);
+ forward!(default_uwtable);
+ forward!(simd_types_indirect);
+ forward!(limit_rdylib_exports);
+ forward_opt!(override_export_symbols);
+ forward!(merge_functions);
+ forward!(mcount);
+ forward_opt!(llvm_mcount_intrinsic);
+ forward!(llvm_abiname);
+ forward_opt!(llvm_floatabi);
+ forward_opt!(rustc_abi);
+ forward!(relax_elf_relocations);
+ forward!(llvm_args);
+ forward!(use_ctors_section);
+ forward!(eh_frame_header);
+ forward!(has_thumb_interworking);
+ forward!(debuginfo_kind);
+ forward!(split_debuginfo);
+ forward!(supported_split_debuginfo);
+
+ if let Some(supported_sanitizers) = json.supported_sanitizers {
+ base.supported_sanitizers =
+ supported_sanitizers.into_iter().fold(SanitizerSet::empty(), |a, b| a | b);
+ }
+
+ forward!(generate_arange_section);
+ forward!(supports_stack_protector);
+ forward!(small_data_threshold_support);
+ forward!(entry_name);
+ forward!(supports_xray);
// we're going to run `update_from_cli`, but that won't change the target's AbiMap
// FIXME: better factor the Target definition so we enforce this on a type level
let abi_map = AbiMap::from_target(&base);
-
- if let Some(abi_str) = obj.remove("entry-abi") {
- if let Json::String(abi_str) = abi_str {
- match abi_str.parse::<ExternAbi>() {
- Ok(abi) => base.options.entry_abi = abi_map.canonize_abi(abi, false).unwrap(),
- Err(_) => return Err(format!("{abi_str} is not a valid ExternAbi")),
- }
- } else {
- incorrect_type.push("entry-abi".to_owned())
- }
+ if let Some(entry_abi) = json.entry_abi {
+ base.options.entry_abi = abi_map.canonize_abi(entry_abi.0, false).unwrap();
}
base.update_from_cli();
base.check_consistency(TargetKind::Json)?;
- // Each field should have been read using `Json::remove` so any keys remaining are unused.
- let remaining_keys = obj.keys();
- Ok((
- base,
- TargetWarnings { unused_fields: remaining_keys.cloned().collect(), incorrect_type },
- ))
+ Ok((base, TargetWarnings { unused_fields: vec![] }))
}
}
@@ -877,3 +412,189 @@ macro_rules! target_option_val {
Json::Object(d)
}
}
+
+#[derive(serde_derive::Deserialize)]
+struct LinkSelfContainedComponentsWrapper {
+ components: Vec<LinkSelfContainedComponents>,
+}
+
+#[derive(serde_derive::Deserialize)]
+#[serde(untagged)]
+enum TargetFamiliesJson {
+ Array(StaticCow<[StaticCow<str>]>),
+ String(StaticCow<str>),
+}
+
+/// `Endian` is in `rustc_abi`, which doesn't have access to the macro and serde.
+struct EndianWrapper(rustc_abi::Endian);
+impl FromStr for EndianWrapper {
+ type Err = String;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ rustc_abi::Endian::from_str(s).map(Self)
+ }
+}
+crate::json::serde_deserialize_from_str!(EndianWrapper);
+
+/// `ExternAbi` is in `rustc_abi`, which doesn't have access to the macro and serde.
+struct ExternAbiWrapper(rustc_abi::ExternAbi);
+impl FromStr for ExternAbiWrapper {
+ type Err = String;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ rustc_abi::ExternAbi::from_str(s)
+ .map(Self)
+ .map_err(|_| format!("{s} is not a valid extern ABI"))
+ }
+}
+crate::json::serde_deserialize_from_str!(ExternAbiWrapper);
+
+#[derive(serde_derive::Deserialize)]
+struct TargetSpecJsonMetadata {
+ description: Option<StaticCow<str>>,
+ tier: Option<u64>,
+ host_tools: Option<bool>,
+ std: Option<bool>,
+}
+
+#[derive(serde_derive::Deserialize)]
+#[serde(rename_all = "kebab-case")]
+// Ensure that all unexpected fields get turned into errors.
+// This helps users stay up to date when the schema changes instead of silently
+// ignoring their old values.
+#[serde(deny_unknown_fields)]
+struct TargetSpecJson {
+ llvm_target: StaticCow<str>,
+ target_pointer_width: String,
+ data_layout: StaticCow<str>,
+ arch: StaticCow<str>,
+
+ metadata: Option<TargetSpecJsonMetadata>,
+
+ // options:
+ target_endian: Option<EndianWrapper>,
+ frame_pointer: Option<FramePointer>,
+ #[serde(rename = "target-c-int-width")]
+ c_int_width: Option<u16>,
+ c_enum_min_bits: Option<u64>,
+ os: Option<StaticCow<str>>,
+ env: Option<StaticCow<str>>,
+ abi: Option<StaticCow<str>>,
+ vendor: Option<StaticCow<str>>,
+ linker: Option<StaticCow<str>>,
+ #[serde(rename = "linker-flavor")]
+ linker_flavor_json: Option<LinkerFlavorCli>,
+ #[serde(rename = "lld-flavor")]
+ lld_flavor_json: Option<LldFlavor>,
+ #[serde(rename = "linker-is-gnu")]
+ linker_is_gnu_json: Option<bool>,
+ #[serde(rename = "pre-link-objects")]
+ pre_link_objects: Option<CrtObjects>,
+ #[serde(rename = "post-link-objects")]
+ post_link_objects: Option<CrtObjects>,
+ #[serde(rename = "pre-link-objects-fallback")]
+ pre_link_objects_self_contained: Option<CrtObjects>,
+ #[serde(rename = "post-link-objects-fallback")]
+ post_link_objects_self_contained: Option<CrtObjects>,
+ #[serde(rename = "crt-objects-fallback")]
+ link_self_contained_backwards_compatible: Option<LinkSelfContainedDefault>,
+ link_self_contained: Option<LinkSelfContainedComponentsWrapper>,
+ #[serde(rename = "pre-link-args")]
+ pre_link_args_json: Option<LinkArgsCli>,
+ #[serde(rename = "late-link-args")]
+ late_link_args_json: Option<LinkArgsCli>,
+ #[serde(rename = "late-link-args-dynamic")]
+ late_link_args_dynamic_json: Option<LinkArgsCli>,
+ #[serde(rename = "late-link-args-static")]
+ late_link_args_static_json: Option<LinkArgsCli>,
+ #[serde(rename = "post-link-args")]
+ post_link_args_json: Option<LinkArgsCli>,
+ link_script: Option<StaticCow<str>>,
+ link_env: Option<Vec<StaticCow<str>>>,
+ link_env_remove: Option<StaticCow<[StaticCow<str>]>>,
+ asm_args: Option<StaticCow<[StaticCow<str>]>>,
+ cpu: Option<StaticCow<str>>,
+ need_explicit_cpu: Option<bool>,
+ features: Option<StaticCow<str>>,
+ dynamic_linking: Option<bool>,
+ direct_access_external_data: Option<bool>,
+ dll_tls_export: Option<bool>,
+ only_cdylib: Option<bool>,
+ executables: Option<bool>,
+ relocation_model: Option<RelocModel>,
+ code_model: Option<CodeModel>,
+ tls_model: Option<TlsModel>,
+ disable_redzone: Option<bool>,
+ function_sections: Option<bool>,
+ dll_prefix: Option<StaticCow<str>>,
+ dll_suffix: Option<StaticCow<str>>,
+ exe_suffix: Option<StaticCow<str>>,
+ staticlib_prefix: Option<StaticCow<str>>,
+ staticlib_suffix: Option<StaticCow<str>>,
+ target_family: Option<TargetFamiliesJson>,
+ abi_return_struct_as_int: Option<bool>,
+ is_like_aix: Option<bool>,
+ is_like_darwin: Option<bool>,
+ is_like_solaris: Option<bool>,
+ is_like_windows: Option<bool>,
+ is_like_msvc: Option<bool>,
+ is_like_wasm: Option<bool>,
+ is_like_android: Option<bool>,
+ binary_format: Option<BinaryFormat>,
+ default_dwarf_version: Option<u32>,
+ allows_weak_linkage: Option<bool>,
+ has_rpath: Option<bool>,
+ no_default_libraries: Option<bool>,
+ position_independent_executables: Option<bool>,
+ static_position_independent_executables: Option<bool>,
+ plt_by_default: Option<bool>,
+ relro_level: Option<RelroLevel>,
+ archive_format: Option<StaticCow<str>>,
+ allow_asm: Option<bool>,
+ main_needs_argc_argv: Option<bool>,
+ has_thread_local: Option<bool>,
+ obj_is_bitcode: Option<bool>,
+ bitcode_llvm_cmdline: Option<StaticCow<str>>,
+ max_atomic_width: Option<u64>,
+ min_atomic_width: Option<u64>,
+ atomic_cas: Option<bool>,
+ panic_strategy: Option<PanicStrategy>,
+ crt_static_allows_dylibs: Option<bool>,
+ crt_static_default: Option<bool>,
+ crt_static_respected: Option<bool>,
+ stack_probes: Option<StackProbeType>,
+ min_global_align: Option<u64>,
+ default_codegen_units: Option<u64>,
+ default_codegen_backend: Option<StaticCow<str>>,
+ trap_unreachable: Option<bool>,
+ requires_lto: Option<bool>,
+ singlethread: Option<bool>,
+ no_builtins: Option<bool>,
+ default_visibility: Option<SymbolVisibility>,
+ emit_debug_gdb_scripts: Option<bool>,
+ requires_uwtable: Option<bool>,
+ default_uwtable: Option<bool>,
+ simd_types_indirect: Option<bool>,
+ limit_rdylib_exports: Option<bool>,
+ override_export_symbols: Option<StaticCow<[StaticCow<str>]>>,
+ merge_functions: Option<MergeFunctions>,
+ #[serde(rename = "target-mcount")]
+ mcount: Option<StaticCow<str>>,
+ llvm_mcount_intrinsic: Option<StaticCow<str>>,
+ llvm_abiname: Option<StaticCow<str>>,
+ llvm_floatabi: Option<FloatAbi>,
+ rustc_abi: Option<RustcAbi>,
+ relax_elf_relocations: Option<bool>,
+ llvm_args: Option<StaticCow<[StaticCow<str>]>>,
+ use_ctors_section: Option<bool>,
+ eh_frame_header: Option<bool>,
+ has_thumb_interworking: Option<bool>,
+ debuginfo_kind: Option<DebuginfoKind>,
+ split_debuginfo: Option<SplitDebuginfo>,
+ supported_split_debuginfo: Option<StaticCow<[SplitDebuginfo]>>,
+ supported_sanitizers: Option<Vec<SanitizerSet>>,
+ generate_arange_section: Option<bool>,
+ supports_stack_protector: Option<bool>,
+ small_data_threshold_support: Option<SmallDataThresholdSupport>,
+ entry_name: Option<StaticCow<str>>,
+ supports_xray: Option<bool>,
+ entry_abi: Option<ExternAbiWrapper>,
+}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 4bc0d88..033590e 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -37,6 +37,7 @@
//!
//! [JSON]: https://json.org
+use core::result::Result;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::hash::{Hash, Hasher};
@@ -198,18 +199,29 @@ pub fn as_str(&self) -> &'static str {
LldFlavor::Link => "link",
}
}
+}
- fn from_str(s: &str) -> Option<Self> {
- Some(match s {
+impl FromStr for LldFlavor {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ Ok(match s {
"darwin" => LldFlavor::Ld64,
"gnu" => LldFlavor::Ld,
"link" => LldFlavor::Link,
"wasm" => LldFlavor::Wasm,
- _ => return None,
+ _ => {
+ return Err(
+ "invalid value for lld flavor: '{s}', expected one of 'darwin', 'gnu', 'link', 'wasm'"
+ .into(),
+ );
+ }
})
}
}
+crate::json::serde_deserialize_from_str!(LldFlavor);
+
impl ToJson for LldFlavor {
fn to_json(&self) -> Json {
self.as_str().to_json()
@@ -494,19 +506,23 @@ pub const fn one_of() -> &'static str {
concat!("one of: ", $($string, " ",)*)
}
- pub fn from_str(s: &str) -> Option<LinkerFlavorCli> {
- Some(match s {
- $($string => $($flavor)*,)*
- _ => return None,
- })
- }
-
pub fn desc(self) -> &'static str {
match self {
$($($flavor)* => $string,)*
}
}
}
+
+ impl FromStr for LinkerFlavorCli {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<LinkerFlavorCli, Self::Err> {
+ Ok(match s {
+ $($string => $($flavor)*,)*
+ _ => return Err(format!("invalid linker flavor, allowed values: {}", Self::one_of())),
+ })
+ }
+ }
)
}
@@ -540,6 +556,8 @@ pub fn desc(self) -> &'static str {
(LinkerFlavorCli::Em) "em"
}
+crate::json::serde_deserialize_from_str!(LinkerFlavorCli);
+
impl ToJson for LinkerFlavorCli {
fn to_json(&self) -> Json {
self.desc().to_json()
@@ -573,19 +591,26 @@ pub enum LinkSelfContainedDefault {
/// Parses a backwards-compatible `-Clink-self-contained` option string, without components.
impl FromStr for LinkSelfContainedDefault {
- type Err = ();
+ type Err = String;
- fn from_str(s: &str) -> Result<LinkSelfContainedDefault, ()> {
+ fn from_str(s: &str) -> Result<LinkSelfContainedDefault, Self::Err> {
Ok(match s {
"false" => LinkSelfContainedDefault::False,
"true" | "wasm" => LinkSelfContainedDefault::True,
"musl" => LinkSelfContainedDefault::InferredForMusl,
"mingw" => LinkSelfContainedDefault::InferredForMingw,
- _ => return Err(()),
+ _ => {
+ return Err(format!(
+ "'{s}' is not a valid `-Clink-self-contained` default. \
+ Use 'false', 'true', 'wasm', 'musl' or 'mingw'",
+ ));
+ }
})
}
}
+crate::json::serde_deserialize_from_str!(LinkSelfContainedDefault);
+
impl ToJson for LinkSelfContainedDefault {
fn to_json(&self) -> Json {
match *self {
@@ -652,19 +677,6 @@ pub struct LinkSelfContainedComponents: u8 {
rustc_data_structures::external_bitflags_debug! { LinkSelfContainedComponents }
impl LinkSelfContainedComponents {
- /// Parses a single `-Clink-self-contained` well-known component, not a set of flags.
- pub fn from_str(s: &str) -> Option<LinkSelfContainedComponents> {
- Some(match s {
- "crto" => LinkSelfContainedComponents::CRT_OBJECTS,
- "libc" => LinkSelfContainedComponents::LIBC,
- "unwind" => LinkSelfContainedComponents::UNWIND,
- "linker" => LinkSelfContainedComponents::LINKER,
- "sanitizers" => LinkSelfContainedComponents::SANITIZERS,
- "mingw" => LinkSelfContainedComponents::MINGW,
- _ => return None,
- })
- }
-
/// Return the component's name.
///
/// Returns `None` if the bitflags aren't a singular component (but a mix of multiple flags).
@@ -708,6 +720,29 @@ pub fn is_crt_objects_enabled(self) -> bool {
}
}
+impl FromStr for LinkSelfContainedComponents {
+ type Err = String;
+
+ /// Parses a single `-Clink-self-contained` well-known component, not a set of flags.
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ Ok(match s {
+ "crto" => LinkSelfContainedComponents::CRT_OBJECTS,
+ "libc" => LinkSelfContainedComponents::LIBC,
+ "unwind" => LinkSelfContainedComponents::UNWIND,
+ "linker" => LinkSelfContainedComponents::LINKER,
+ "sanitizers" => LinkSelfContainedComponents::SANITIZERS,
+ "mingw" => LinkSelfContainedComponents::MINGW,
+ _ => {
+ return Err(format!(
+ "'{s}' is not a valid link-self-contained component, expected 'crto', 'libc', 'unwind', 'linker', 'sanitizers', 'mingw'"
+ ));
+ }
+ })
+ }
+}
+
+crate::json::serde_deserialize_from_str!(LinkSelfContainedComponents);
+
impl ToJson for LinkSelfContainedComponents {
fn to_json(&self) -> Json {
let components: Vec<_> = Self::all_components()
@@ -821,6 +856,25 @@ pub const fn desc_symbol(&self) -> Symbol {
}
}
+impl FromStr for PanicStrategy {
+ type Err = String;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ Ok(match s {
+ "unwind" => PanicStrategy::Unwind,
+ "abort" => PanicStrategy::Abort,
+ _ => {
+ return Err(format!(
+ "'{}' is not a valid value for \
+ panic-strategy. Use 'unwind' or 'abort'.",
+ s
+ ));
+ }
+ })
+ }
+}
+
+crate::json::serde_deserialize_from_str!(PanicStrategy);
+
impl ToJson for PanicStrategy {
fn to_json(&self) -> Json {
match *self {
@@ -867,18 +921,24 @@ pub fn desc(&self) -> &str {
}
impl FromStr for SymbolVisibility {
- type Err = ();
+ type Err = String;
- fn from_str(s: &str) -> Result<SymbolVisibility, ()> {
+ fn from_str(s: &str) -> Result<SymbolVisibility, Self::Err> {
match s {
"hidden" => Ok(SymbolVisibility::Hidden),
"protected" => Ok(SymbolVisibility::Protected),
"interposable" => Ok(SymbolVisibility::Interposable),
- _ => Err(()),
+ _ => Err(format!(
+ "'{}' is not a valid value for \
+ symbol-visibility. Use 'hidden', 'protected, or 'interposable'.",
+ s
+ )),
}
}
}
+crate::json::serde_deserialize_from_str!(SymbolVisibility);
+
impl ToJson for SymbolVisibility {
fn to_json(&self) -> Json {
match *self {
@@ -890,19 +950,25 @@ fn to_json(&self) -> Json {
}
impl FromStr for RelroLevel {
- type Err = ();
+ type Err = String;
- fn from_str(s: &str) -> Result<RelroLevel, ()> {
+ fn from_str(s: &str) -> Result<RelroLevel, Self::Err> {
match s {
"full" => Ok(RelroLevel::Full),
"partial" => Ok(RelroLevel::Partial),
"off" => Ok(RelroLevel::Off),
"none" => Ok(RelroLevel::None),
- _ => Err(()),
+ _ => Err(format!(
+ "'{}' is not a valid value for \
+ relro-level. Use 'full', 'partial, 'off', or 'none'.",
+ s
+ )),
}
}
}
+crate::json::serde_deserialize_from_str!(RelroLevel);
+
impl ToJson for RelroLevel {
fn to_json(&self) -> Json {
match *self {
@@ -923,7 +989,7 @@ pub enum SmallDataThresholdSupport {
}
impl FromStr for SmallDataThresholdSupport {
- type Err = ();
+ type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "none" {
@@ -935,11 +1001,13 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
} else if let Some(arg) = s.strip_prefix("llvm-arg=") {
Ok(Self::LlvmArg(arg.to_string().into()))
} else {
- Err(())
+ Err(format!("'{s}' is not a valid value for small-data-threshold-support."))
}
}
}
+crate::json::serde_deserialize_from_str!(SmallDataThresholdSupport);
+
impl ToJson for SmallDataThresholdSupport {
fn to_json(&self) -> Value {
match self {
@@ -969,18 +1037,25 @@ pub fn desc(&self) -> &str {
}
impl FromStr for MergeFunctions {
- type Err = ();
+ type Err = String;
- fn from_str(s: &str) -> Result<MergeFunctions, ()> {
+ fn from_str(s: &str) -> Result<MergeFunctions, Self::Err> {
match s {
"disabled" => Ok(MergeFunctions::Disabled),
"trampolines" => Ok(MergeFunctions::Trampolines),
"aliases" => Ok(MergeFunctions::Aliases),
- _ => Err(()),
+ _ => Err(format!(
+ "'{}' is not a valid value for \
+ merge-functions. Use 'disabled', \
+ 'trampolines', or 'aliases'.",
+ s
+ )),
}
}
}
+crate::json::serde_deserialize_from_str!(MergeFunctions);
+
impl ToJson for MergeFunctions {
fn to_json(&self) -> Json {
match *self {
@@ -1040,9 +1115,9 @@ pub const fn desc_symbol(&self) -> Symbol {
}
impl FromStr for RelocModel {
- type Err = ();
+ type Err = String;
- fn from_str(s: &str) -> Result<RelocModel, ()> {
+ fn from_str(s: &str) -> Result<RelocModel, Self::Err> {
Ok(match s {
"static" => RelocModel::Static,
"pic" => RelocModel::Pic,
@@ -1051,11 +1126,19 @@ fn from_str(s: &str) -> Result<RelocModel, ()> {
"ropi" => RelocModel::Ropi,
"rwpi" => RelocModel::Rwpi,
"ropi-rwpi" => RelocModel::RopiRwpi,
- _ => return Err(()),
+ _ => {
+ return Err(format!(
+ "invalid relocation model '{s}'.
+ Run `rustc --print relocation-models` to \
+ see the list of supported values.'"
+ ));
+ }
})
}
}
+crate::json::serde_deserialize_from_str!(RelocModel);
+
impl ToJson for RelocModel {
fn to_json(&self) -> Json {
self.desc().to_json()
@@ -1072,20 +1155,28 @@ pub enum CodeModel {
}
impl FromStr for CodeModel {
- type Err = ();
+ type Err = String;
- fn from_str(s: &str) -> Result<CodeModel, ()> {
+ fn from_str(s: &str) -> Result<CodeModel, Self::Err> {
Ok(match s {
"tiny" => CodeModel::Tiny,
"small" => CodeModel::Small,
"kernel" => CodeModel::Kernel,
"medium" => CodeModel::Medium,
"large" => CodeModel::Large,
- _ => return Err(()),
+ _ => {
+ return Err(format!(
+ "'{s}' is not a valid code model. \
+ Run `rustc --print code-models` to \
+ see the list of supported values."
+ ));
+ }
})
}
}
+crate::json::serde_deserialize_from_str!(CodeModel);
+
impl ToJson for CodeModel {
fn to_json(&self) -> Json {
match *self {
@@ -1107,17 +1198,25 @@ pub enum FloatAbi {
}
impl FromStr for FloatAbi {
- type Err = ();
+ type Err = String;
- fn from_str(s: &str) -> Result<FloatAbi, ()> {
+ fn from_str(s: &str) -> Result<FloatAbi, Self::Err> {
Ok(match s {
"soft" => FloatAbi::Soft,
"hard" => FloatAbi::Hard,
- _ => return Err(()),
+ _ => {
+ return Err(format!(
+ "'{}' is not a valid value for \
+ llvm-floatabi. Use 'soft' or 'hard'.",
+ s
+ ));
+ }
})
}
}
+crate::json::serde_deserialize_from_str!(FloatAbi);
+
impl ToJson for FloatAbi {
fn to_json(&self) -> Json {
match *self {
@@ -1138,17 +1237,24 @@ pub enum RustcAbi {
}
impl FromStr for RustcAbi {
- type Err = ();
+ type Err = String;
- fn from_str(s: &str) -> Result<RustcAbi, ()> {
+ fn from_str(s: &str) -> Result<RustcAbi, Self::Err> {
Ok(match s {
"x86-sse2" => RustcAbi::X86Sse2,
"x86-softfloat" => RustcAbi::X86Softfloat,
- _ => return Err(()),
+ _ => {
+ return Err(format!(
+ "'{s}' is not a valid value for rustc-abi. \
+ Use 'x86-softfloat' or leave the field unset."
+ ));
+ }
})
}
}
+crate::json::serde_deserialize_from_str!(RustcAbi);
+
impl ToJson for RustcAbi {
fn to_json(&self) -> Json {
match *self {
@@ -1169,9 +1275,9 @@ pub enum TlsModel {
}
impl FromStr for TlsModel {
- type Err = ();
+ type Err = String;
- fn from_str(s: &str) -> Result<TlsModel, ()> {
+ fn from_str(s: &str) -> Result<TlsModel, Self::Err> {
Ok(match s {
// Note the difference "general" vs "global" difference. The model name is "general",
// but the user-facing option name is "global" for consistency with other compilers.
@@ -1180,11 +1286,19 @@ fn from_str(s: &str) -> Result<TlsModel, ()> {
"initial-exec" => TlsModel::InitialExec,
"local-exec" => TlsModel::LocalExec,
"emulated" => TlsModel::Emulated,
- _ => return Err(()),
+ _ => {
+ return Err(format!(
+ "'{s}' is not a valid TLS model. \
+ Run `rustc --print tls-models` to \
+ see the list of supported values."
+ ));
+ }
})
}
}
+crate::json::serde_deserialize_from_str!(TlsModel);
+
impl ToJson for TlsModel {
fn to_json(&self) -> Json {
match *self {
@@ -1230,19 +1344,6 @@ fn as_str(&self) -> &'static str {
}
}
- pub(super) fn from_str(s: &str) -> Option<LinkOutputKind> {
- Some(match s {
- "dynamic-nopic-exe" => LinkOutputKind::DynamicNoPicExe,
- "dynamic-pic-exe" => LinkOutputKind::DynamicPicExe,
- "static-nopic-exe" => LinkOutputKind::StaticNoPicExe,
- "static-pic-exe" => LinkOutputKind::StaticPicExe,
- "dynamic-dylib" => LinkOutputKind::DynamicDylib,
- "static-dylib" => LinkOutputKind::StaticDylib,
- "wasi-reactor-exe" => LinkOutputKind::WasiReactorExe,
- _ => return None,
- })
- }
-
pub fn can_link_dylib(self) -> bool {
match self {
LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => false,
@@ -1255,6 +1356,31 @@ pub fn can_link_dylib(self) -> bool {
}
}
+impl FromStr for LinkOutputKind {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<LinkOutputKind, Self::Err> {
+ Ok(match s {
+ "dynamic-nopic-exe" => LinkOutputKind::DynamicNoPicExe,
+ "dynamic-pic-exe" => LinkOutputKind::DynamicPicExe,
+ "static-nopic-exe" => LinkOutputKind::StaticNoPicExe,
+ "static-pic-exe" => LinkOutputKind::StaticPicExe,
+ "dynamic-dylib" => LinkOutputKind::DynamicDylib,
+ "static-dylib" => LinkOutputKind::StaticDylib,
+ "wasi-reactor-exe" => LinkOutputKind::WasiReactorExe,
+ _ => {
+ return Err(format!(
+ "invalid value for CRT object kind. \
+ Use '(dynamic,static)-(nopic,pic)-exe' or \
+ '(dynamic,static)-dylib' or 'wasi-reactor-exe'"
+ ));
+ }
+ })
+ }
+}
+
+crate::json::serde_deserialize_from_str!(LinkOutputKind);
+
impl fmt::Display for LinkOutputKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
@@ -1290,18 +1416,25 @@ fn as_str(&self) -> &'static str {
}
impl FromStr for DebuginfoKind {
- type Err = ();
+ type Err = String;
- fn from_str(s: &str) -> Result<Self, ()> {
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"dwarf" => DebuginfoKind::Dwarf,
"dwarf-dsym" => DebuginfoKind::DwarfDsym,
"pdb" => DebuginfoKind::Pdb,
- _ => return Err(()),
+ _ => {
+ return Err(format!(
+ "'{s}' is not a valid value for debuginfo-kind. Use 'dwarf', \
+ 'dwarf-dsym' or 'pdb'."
+ ));
+ }
})
}
}
+crate::json::serde_deserialize_from_str!(DebuginfoKind);
+
impl ToJson for DebuginfoKind {
fn to_json(&self) -> Json {
self.as_str().to_json()
@@ -1354,18 +1487,25 @@ fn as_str(&self) -> &'static str {
}
impl FromStr for SplitDebuginfo {
- type Err = ();
+ type Err = String;
- fn from_str(s: &str) -> Result<Self, ()> {
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"off" => SplitDebuginfo::Off,
"unpacked" => SplitDebuginfo::Unpacked,
"packed" => SplitDebuginfo::Packed,
- _ => return Err(()),
+ _ => {
+ return Err(format!(
+ "'{s}' is not a valid value for \
+ split-debuginfo. Use 'off', 'unpacked', or 'packed'.",
+ ));
+ }
})
}
}
+crate::json::serde_deserialize_from_str!(SplitDebuginfo);
+
impl ToJson for SplitDebuginfo {
fn to_json(&self) -> Json {
self.as_str().to_json()
@@ -1378,7 +1518,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, serde_derive::Deserialize)]
+#[serde(tag = "kind")]
+#[serde(rename_all = "kebab-case")]
pub enum StackProbeType {
/// Don't emit any stack probes.
None,
@@ -1390,44 +1532,10 @@ pub enum StackProbeType {
Call,
/// Use inline option for LLVM versions later than specified in `min_llvm_version_for_inline`
/// and call `__rust_probestack` otherwise.
- InlineOrCall { min_llvm_version_for_inline: (u32, u32, u32) },
-}
-
-impl StackProbeType {
- fn from_json(json: &Json) -> Result<Self, String> {
- let object = json.as_object().ok_or_else(|| "expected a JSON object")?;
- let kind = object
- .get("kind")
- .and_then(|o| o.as_str())
- .ok_or_else(|| "expected `kind` to be a string")?;
- match kind {
- "none" => Ok(StackProbeType::None),
- "inline" => Ok(StackProbeType::Inline),
- "call" => Ok(StackProbeType::Call),
- "inline-or-call" => {
- let min_version = object
- .get("min-llvm-version-for-inline")
- .and_then(|o| o.as_array())
- .ok_or_else(|| "expected `min-llvm-version-for-inline` to be an array")?;
- let mut iter = min_version.into_iter().map(|v| {
- let int = v.as_u64().ok_or_else(
- || "expected `min-llvm-version-for-inline` values to be integers",
- )?;
- u32::try_from(int)
- .map_err(|_| "`min-llvm-version-for-inline` values don't convert to u32")
- });
- let min_llvm_version_for_inline = (
- iter.next().unwrap_or(Ok(11))?,
- iter.next().unwrap_or(Ok(0))?,
- iter.next().unwrap_or(Ok(0))?,
- );
- Ok(StackProbeType::InlineOrCall { min_llvm_version_for_inline })
- }
- _ => Err(String::from(
- "`kind` expected to be one of `none`, `inline`, `call` or `inline-or-call`",
- )),
- }
- }
+ InlineOrCall {
+ #[serde(rename = "min-llvm-version-for-inline")]
+ min_llvm_version_for_inline: (u32, u32, u32),
+ },
}
impl ToJson for StackProbeType {
@@ -1549,6 +1657,29 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
+impl FromStr for SanitizerSet {
+ type Err = String;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ Ok(match s {
+ "address" => SanitizerSet::ADDRESS,
+ "cfi" => SanitizerSet::CFI,
+ "dataflow" => SanitizerSet::DATAFLOW,
+ "kcfi" => SanitizerSet::KCFI,
+ "kernel-address" => SanitizerSet::KERNELADDRESS,
+ "leak" => SanitizerSet::LEAK,
+ "memory" => SanitizerSet::MEMORY,
+ "memtag" => SanitizerSet::MEMTAG,
+ "safestack" => SanitizerSet::SAFESTACK,
+ "shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
+ "thread" => SanitizerSet::THREAD,
+ "hwaddress" => SanitizerSet::HWADDRESS,
+ s => return Err(format!("unknown sanitizer {s}")),
+ })
+ }
+}
+
+crate::json::serde_deserialize_from_str!(SanitizerSet);
+
impl ToJson for SanitizerSet {
fn to_json(&self) -> Json {
self.into_iter()
@@ -1587,17 +1718,19 @@ pub fn ratchet(&mut self, rhs: FramePointer) -> FramePointer {
}
impl FromStr for FramePointer {
- type Err = ();
- fn from_str(s: &str) -> Result<Self, ()> {
+ type Err = String;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"always" => Self::Always,
"non-leaf" => Self::NonLeaf,
"may-omit" => Self::MayOmit,
- _ => return Err(()),
+ _ => return Err(format!("'{s}' is not a valid value for frame-pointer")),
})
}
}
+crate::json::serde_deserialize_from_str!(FramePointer);
+
impl ToJson for FramePointer {
fn to_json(&self) -> Json {
match *self {
@@ -1685,7 +1818,7 @@ pub fn to_object(&self) -> object::BinaryFormat {
}
impl FromStr for BinaryFormat {
- type Err = ();
+ type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"coff" => Ok(Self::Coff),
@@ -1693,11 +1826,16 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
"mach-o" => Ok(Self::MachO),
"wasm" => Ok(Self::Wasm),
"xcoff" => Ok(Self::Xcoff),
- _ => Err(()),
+ _ => Err(format!(
+ "'{s}' is not a valid value for binary_format. \
+ Use 'coff', 'elf', 'mach-o', 'wasm' or 'xcoff' "
+ )),
}
}
}
+crate::json::serde_deserialize_from_str!(BinaryFormat);
+
impl ToJson for BinaryFormat {
fn to_json(&self) -> Json {
match self {
@@ -2130,12 +2268,11 @@ macro_rules! cvs {
#[derive(Debug, PartialEq)]
pub struct TargetWarnings {
unused_fields: Vec<String>,
- incorrect_type: Vec<String>,
}
impl TargetWarnings {
pub fn empty() -> Self {
- Self { unused_fields: Vec::new(), incorrect_type: Vec::new() }
+ Self { unused_fields: Vec::new() }
}
pub fn warning_messages(&self) -> Vec<String> {
@@ -2146,12 +2283,6 @@ pub fn warning_messages(&self) -> Vec<String> {
self.unused_fields.join(", ")
));
}
- if !self.incorrect_type.is_empty() {
- warnings.push(format!(
- "target json file contains fields whose value doesn't have the correct json type: {}",
- self.incorrect_type.join(", ")
- ));
- }
warnings
}
}
@@ -3325,7 +3456,8 @@ macro_rules! check_matches {
/// Test target self-consistency and JSON encoding/decoding roundtrip.
#[cfg(test)]
fn test_target(mut self) {
- let recycled_target = Target::from_json(self.to_json()).map(|(j, _)| j);
+ let recycled_target =
+ Target::from_json(&serde_json::to_string(&self.to_json()).unwrap()).map(|(j, _)| j);
self.update_to_cli();
self.check_consistency(TargetKind::Builtin).unwrap();
assert_eq!(recycled_target, Ok(self));
@@ -3373,8 +3505,7 @@ pub fn search(
fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
let contents = fs::read_to_string(path).map_err(|e| e.to_string())?;
- let obj = serde_json::from_str(&contents).map_err(|e| e.to_string())?;
- Target::from_json(obj)
+ Target::from_json(&contents)
}
match *target_tuple {
@@ -3422,10 +3553,7 @@ fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
Err(format!("could not find specification for target {target_tuple:?}"))
}
}
- TargetTuple::TargetJson { ref contents, .. } => {
- let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?;
- Target::from_json(obj)
- }
+ TargetTuple::TargetJson { ref contents, .. } => Target::from_json(contents),
}
}
@@ -3470,6 +3598,7 @@ pub fn object_architecture(
),
"x86" => (Architecture::I386, None),
"s390x" => (Architecture::S390x, None),
+ "m68k" => (Architecture::M68k, None),
"mips" | "mips32r6" => (Architecture::Mips, None),
"mips64" | "mips64r6" => (
// While there are currently no builtin targets
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs
index 58daaa0..478726f 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs
@@ -6,7 +6,7 @@ pub(crate) fn target() -> Target {
let mut base = base::linux_musl::opts();
base.max_atomic_width = Some(128);
base.supports_xray = true;
- base.features = "+v8a".into();
+ base.features = "+v8a,+outline-atomics".into();
base.stack_probes = StackProbeType::Inline;
base.supported_sanitizers = SanitizerSet::ADDRESS
| SanitizerSet::CFI
diff --git a/compiler/rustc_target/src/tests.rs b/compiler/rustc_target/src/tests.rs
index 7637517..ee847a8 100644
--- a/compiler/rustc_target/src/tests.rs
+++ b/compiler/rustc_target/src/tests.rs
@@ -2,8 +2,7 @@
#[test]
fn report_unused_fields() {
- let json = serde_json::from_str(
- r#"
+ let json = r#"
{
"arch": "powerpc64",
"data-layout": "e-m:e-i64:64-n32:64",
@@ -11,47 +10,8 @@ fn report_unused_fields() {
"target-pointer-width": "64",
"code-mode": "foo"
}
- "#,
- )
- .unwrap();
- let warnings = Target::from_json(json).unwrap().1;
- assert_eq!(warnings.warning_messages().len(), 1);
- assert!(warnings.warning_messages().join("\n").contains("code-mode"));
-}
-
-#[test]
-fn report_incorrect_json_type() {
- let json = serde_json::from_str(
- r#"
- {
- "arch": "powerpc64",
- "data-layout": "e-m:e-i64:64-n32:64",
- "llvm-target": "powerpc64le-elf",
- "target-pointer-width": "64",
- "link-env-remove": "foo"
- }
- "#,
- )
- .unwrap();
- let warnings = Target::from_json(json).unwrap().1;
- assert_eq!(warnings.warning_messages().len(), 1);
- assert!(warnings.warning_messages().join("\n").contains("link-env-remove"));
-}
-
-#[test]
-fn no_warnings_for_valid_target() {
- let json = serde_json::from_str(
- r#"
- {
- "arch": "powerpc64",
- "data-layout": "e-m:e-i64:64-n32:64",
- "llvm-target": "powerpc64le-elf",
- "target-pointer-width": "64",
- "link-env-remove": ["foo"]
- }
- "#,
- )
- .unwrap();
- let warnings = Target::from_json(json).unwrap().1;
- assert_eq!(warnings.warning_messages().len(), 0);
+ "#;
+ let result = Target::from_json(json);
+ eprintln!("{result:#?}");
+ assert!(result.is_err());
}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index 1db05ce..022d549 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -1303,7 +1303,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
&& let Some(args) = self.node_args_opt(expr.hir_id)
&& args.iter().any(|arg| self.generic_arg_contains_target(arg))
&& let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
- && self.tecx.tcx.trait_of_item(def_id).is_some()
+ && self.tecx.tcx.trait_of_assoc(def_id).is_some()
&& !has_impl_trait(def_id)
// FIXME(fn_delegation): In delegation item argument spans are equal to last path
// segment. This leads to ICE's when emitting `multipart_suggestion`.
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 772a7f0..2a3268d 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
@@ -104,10 +104,9 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) {
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))
+ && let Some(decl) = self.tcx().hir_fn_decl_by_hir_id(hir_id)
{
- if let Some(decl) = self.tcx().hir_fn_decl_by_hir_id(hir_id) {
- visitor.visit_fn_decl(decl);
- }
+ visitor.visit_fn_decl(decl);
}
}
_ => {}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
index c0daf08..44baa21 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -91,51 +91,51 @@ pub(super) fn suggest_tuple_pattern(
) {
// Heavily inspired by `FnCtxt::suggest_compatible_variants`, with
// some modifications due to that being in typeck and this being in infer.
- if let ObligationCauseCode::Pattern { .. } = cause.code() {
- if let ty::Adt(expected_adt, args) = exp_found.expected.kind() {
- let compatible_variants: Vec<_> = expected_adt
- .variants()
- .iter()
- .filter(|variant| {
- variant.fields.len() == 1 && variant.ctor_kind() == Some(CtorKind::Fn)
- })
- .filter_map(|variant| {
- let sole_field = &variant.single_field();
- let sole_field_ty = sole_field.ty(self.tcx, args);
- if self.same_type_modulo_infer(sole_field_ty, exp_found.found) {
- let variant_path =
- with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
- // FIXME #56861: DRYer prelude filtering
- if let Some(path) = variant_path.strip_prefix("std::prelude::") {
- if let Some((_, path)) = path.split_once("::") {
- return Some(path.to_string());
- }
- }
- Some(variant_path)
- } else {
- None
+ if let ObligationCauseCode::Pattern { .. } = cause.code()
+ && let ty::Adt(expected_adt, args) = exp_found.expected.kind()
+ {
+ let compatible_variants: Vec<_> = expected_adt
+ .variants()
+ .iter()
+ .filter(|variant| {
+ variant.fields.len() == 1 && variant.ctor_kind() == Some(CtorKind::Fn)
+ })
+ .filter_map(|variant| {
+ let sole_field = &variant.single_field();
+ let sole_field_ty = sole_field.ty(self.tcx, args);
+ if self.same_type_modulo_infer(sole_field_ty, exp_found.found) {
+ let variant_path =
+ with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
+ // FIXME #56861: DRYer prelude filtering
+ if let Some(path) = variant_path.strip_prefix("std::prelude::")
+ && let Some((_, path)) = path.split_once("::")
+ {
+ return Some(path.to_string());
}
- })
- .collect();
- match &compatible_variants[..] {
- [] => {}
- [variant] => {
- let sugg = SuggestTuplePatternOne {
- variant: variant.to_owned(),
- span_low: cause.span.shrink_to_lo(),
- span_high: cause.span.shrink_to_hi(),
- };
- diag.subdiagnostic(sugg);
+ Some(variant_path)
+ } else {
+ None
}
- _ => {
- // More than one matching variant.
- let sugg = SuggestTuplePatternMany {
- path: self.tcx.def_path_str(expected_adt.did()),
- cause_span: cause.span,
- compatible_variants,
- };
- diag.subdiagnostic(sugg);
- }
+ })
+ .collect();
+ match &compatible_variants[..] {
+ [] => {}
+ [variant] => {
+ let sugg = SuggestTuplePatternOne {
+ variant: variant.to_owned(),
+ span_low: cause.span.shrink_to_lo(),
+ span_high: cause.span.shrink_to_hi(),
+ };
+ diag.subdiagnostic(sugg);
+ }
+ _ => {
+ // More than one matching variant.
+ let sugg = SuggestTuplePatternMany {
+ path: self.tcx.def_path_str(expected_adt.did()),
+ cause_span: cause.span,
+ compatible_variants,
+ };
+ diag.subdiagnostic(sugg);
}
}
}
@@ -288,19 +288,17 @@ pub(super) fn suggest_accessing_field_where_appropriate(
.filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
.map(|field| (field.name, field.ty(self.tcx, expected_args)))
.find(|(_, ty)| self.same_type_modulo_infer(*ty, exp_found.found))
+ && let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code()
+ && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
{
- if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() {
- if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
- let suggestion = if expected_def.is_struct() {
- SuggestAccessingField::Safe { span, snippet, name, ty }
- } else if expected_def.is_union() {
- SuggestAccessingField::Unsafe { span, snippet, name, ty }
- } else {
- return;
- };
- diag.subdiagnostic(suggestion);
- }
- }
+ let suggestion = if expected_def.is_struct() {
+ SuggestAccessingField::Safe { span, snippet, name, ty }
+ } else if expected_def.is_union() {
+ SuggestAccessingField::Unsafe { span, snippet, name, ty }
+ } else {
+ return;
+ };
+ diag.subdiagnostic(suggestion);
}
}
}
@@ -540,38 +538,35 @@ fn should_suggest_as_ref_kind(
) -> Option<SuggestAsRefKind> {
if let (ty::Adt(exp_def, exp_args), ty::Ref(_, found_ty, _)) =
(expected.kind(), found.kind())
+ && let ty::Adt(found_def, found_args) = *found_ty.kind()
{
- if let ty::Adt(found_def, found_args) = *found_ty.kind() {
- if exp_def == &found_def {
- let have_as_ref = &[
- (sym::Option, SuggestAsRefKind::Option),
- (sym::Result, SuggestAsRefKind::Result),
- ];
- if let Some(msg) = have_as_ref.iter().find_map(|(name, msg)| {
- self.tcx.is_diagnostic_item(*name, exp_def.did()).then_some(msg)
- }) {
- let mut show_suggestion = true;
- for (exp_ty, found_ty) in
- std::iter::zip(exp_args.types(), found_args.types())
- {
- match *exp_ty.kind() {
- ty::Ref(_, exp_ty, _) => {
- match (exp_ty.kind(), found_ty.kind()) {
- (_, ty::Param(_))
- | (_, ty::Infer(_))
- | (ty::Param(_), _)
- | (ty::Infer(_), _) => {}
- _ if self.same_type_modulo_infer(exp_ty, found_ty) => {}
- _ => show_suggestion = false,
- };
- }
- ty::Param(_) | ty::Infer(_) => {}
- _ => show_suggestion = false,
+ if exp_def == &found_def {
+ let have_as_ref = &[
+ (sym::Option, SuggestAsRefKind::Option),
+ (sym::Result, SuggestAsRefKind::Result),
+ ];
+ if let Some(msg) = have_as_ref.iter().find_map(|(name, msg)| {
+ self.tcx.is_diagnostic_item(*name, exp_def.did()).then_some(msg)
+ }) {
+ let mut show_suggestion = true;
+ for (exp_ty, found_ty) in std::iter::zip(exp_args.types(), found_args.types()) {
+ match *exp_ty.kind() {
+ ty::Ref(_, exp_ty, _) => {
+ match (exp_ty.kind(), found_ty.kind()) {
+ (_, ty::Param(_))
+ | (_, ty::Infer(_))
+ | (ty::Param(_), _)
+ | (ty::Infer(_), _) => {}
+ _ if self.same_type_modulo_infer(exp_ty, found_ty) => {}
+ _ => show_suggestion = false,
+ };
}
+ ty::Param(_) | ty::Infer(_) => {}
+ _ => show_suggestion = false,
}
- if show_suggestion {
- return Some(*msg);
- }
+ }
+ if show_suggestion {
+ return Some(*msg);
}
}
}
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 98f6725..cdf1402 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -360,7 +360,7 @@ pub(super) fn maybe_report_ambiguity(
},
] = path.segments
&& data.trait_ref.def_id == *trait_id
- && self.tcx.trait_of_item(*item_id) == Some(*trait_id)
+ && self.tcx.trait_of_assoc(*item_id) == Some(*trait_id)
&& let None = self.tainted_by_errors()
{
let assoc_item = self.tcx.associated_item(item_id);
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 2344bc7..5765dfd 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
@@ -381,15 +381,15 @@ pub fn maybe_emit_warning<'tcx>(
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(
- 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 },
- );
- }
+ if let (Some(new_item), Some(old_item)) = (new, old)
+ && let Some(item_def_id) = item_def_id.as_local()
+ {
+ tcx.emit_node_span_lint(
+ 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 bf7d425..c182fd9 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -987,7 +987,7 @@ pub(super) fn suggest_add_clone_to_arg(
else {
return false;
};
- if self.tcx.trait_of_item(did) != Some(clone_trait) {
+ if self.tcx.trait_of_assoc(did) != Some(clone_trait) {
return false;
}
Some(ident.span)
@@ -2213,26 +2213,26 @@ pub(super) fn suggest_fully_qualified_path(
span: Span,
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 {
- err.note(format!(
- "{}s cannot be accessed directly on a `trait`, they can only be \
+ if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id)
+ && 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.as_def_kind(), item_def_id)
- ));
+ self.tcx.def_kind_descr(assoc_item.as_def_kind(), item_def_id)
+ ));
- if !assoc_item.is_impl_trait_in_trait() {
- err.span_suggestion_verbose(
- span,
- "use the fully qualified path to an implementation",
- format!(
- "<Type as {}>::{}",
- self.tcx.def_path_str(trait_ref),
- assoc_item.name()
- ),
- Applicability::HasPlaceholders,
- );
- }
+ if !assoc_item.is_impl_trait_in_trait() {
+ err.span_suggestion_verbose(
+ span,
+ "use the fully qualified path to an implementation",
+ format!(
+ "<Type as {}>::{}",
+ self.tcx.def_path_str(trait_ref),
+ assoc_item.name()
+ ),
+ Applicability::HasPlaceholders,
+ );
}
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index f50f01a..07e78da 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -695,15 +695,14 @@ fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) {
source: CandidateSource::Impl(def_id),
result: Ok(_),
} = cand.kind()
+ && let ty::ImplPolarity::Reservation = infcx.tcx.impl_polarity(def_id)
{
- if let ty::ImplPolarity::Reservation = infcx.tcx.impl_polarity(def_id) {
- let message = infcx
- .tcx
- .get_attr(def_id, sym::rustc_reservation_impl)
- .and_then(|a| a.value_str());
- if let Some(message) = message {
- self.causes.insert(IntercrateAmbiguityCause::ReservationImpl { message });
- }
+ let message = infcx
+ .tcx
+ .get_attr(def_id, sym::rustc_reservation_impl)
+ .and_then(|a| a.value_str());
+ if let Some(message) = message {
+ self.causes.insert(IntercrateAmbiguityCause::ReservationImpl { message });
}
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 91c4154..9b5e59c 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -759,7 +759,7 @@ fn instantiate_and_check_impossible_predicates<'tcx>(
// Specifically check trait fulfillment to avoid an error when trying to resolve
// associated items.
- if let Some(trait_def_id) = tcx.trait_of_item(key.0) {
+ if let Some(trait_def_id) = tcx.trait_of_assoc(key.0) {
let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, key.1);
predicates.push(trait_ref.upcast(tcx));
}
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 28b5b7cf..581191b 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1507,7 +1507,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
let tcx = selcx.tcx();
let self_ty = obligation.predicate.self_ty();
let item_def_id = obligation.predicate.def_id;
- let trait_def_id = tcx.trait_of_item(item_def_id).unwrap();
+ let trait_def_id = tcx.trait_of_assoc(item_def_id).unwrap();
let args = tcx.mk_args(&[self_ty.into()]);
let (term, obligations) = if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) {
let discriminant_def_id =
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index f90316f..d7c3543 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -781,16 +781,14 @@ fn evaluate_predicate_recursively<'o>(
self,
&project_obligation,
)
- {
- if let Some(cached_res) = self
+ && let Some(cached_res) = self
.infcx
.inner
.borrow_mut()
.projection_cache()
.is_complete(key)
- {
- break 'compute_res Ok(cached_res);
- }
+ {
+ break 'compute_res Ok(cached_res);
}
// Need to explicitly set the depth of nested goals here as
@@ -1436,24 +1434,23 @@ fn filter_reservation_impls(
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
let tcx = self.tcx();
// Treat reservation impls as ambiguity.
- if let ImplCandidate(def_id) = candidate {
- if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
- if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
- let message = tcx
- .get_attr(def_id, sym::rustc_reservation_impl)
- .and_then(|a| a.value_str());
- if let Some(message) = message {
- debug!(
- "filter_reservation_impls: \
+ if let ImplCandidate(def_id) = candidate
+ && let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id)
+ {
+ if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
+ let message =
+ tcx.get_attr(def_id, sym::rustc_reservation_impl).and_then(|a| a.value_str());
+ if let Some(message) = message {
+ debug!(
+ "filter_reservation_impls: \
reservation impl ambiguity on {:?}",
- def_id
- );
- intercrate_ambiguity_clauses
- .insert(IntercrateAmbiguityCause::ReservationImpl { message });
- }
+ def_id
+ );
+ intercrate_ambiguity_clauses
+ .insert(IntercrateAmbiguityCause::ReservationImpl { message });
}
- return Ok(None);
}
+ return Ok(None);
}
Ok(Some(candidate))
}
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index f0ff503..af2e000 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -642,11 +642,11 @@ fn unadjust<'tcx>(arg: &mut ArgAbi<'tcx, Ty<'tcx>>) {
// The `deduced_param_attrs` list could be empty if this is a type of function
// we can't deduce any parameters for, so make sure the argument index is in
// bounds.
- if let Some(deduced_param_attrs) = deduced_param_attrs.get(arg_idx) {
- if deduced_param_attrs.read_only {
- attrs.regular.insert(ArgAttribute::ReadOnly);
- debug!("added deduced read-only attribute");
- }
+ if let Some(deduced_param_attrs) = deduced_param_attrs.get(arg_idx)
+ && deduced_param_attrs.read_only
+ {
+ attrs.regular.insert(ArgAttribute::ReadOnly);
+ debug!("added deduced read-only attribute");
}
}
}
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 166e8f1..e6c3568 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -21,7 +21,7 @@ fn resolve_instance_raw<'tcx>(
) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
let PseudoCanonicalInput { typing_env, value: (def_id, args) } = key;
- let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
+ let result = if let Some(trait_def_id) = tcx.trait_of_assoc(def_id) {
debug!(" => associated item, attempting to find impl in typing_env {:#?}", typing_env);
resolve_associated_item(
tcx,
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 163e2b3..79f7e22 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -603,12 +603,6 @@ fn layout_of_uncached<'tcx>(
.flatten()
};
- let dont_niche_optimize_enum = def.repr().inhibit_enum_layout_opt()
- || def
- .variants()
- .iter_enumerated()
- .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32()));
-
let maybe_unsized = def.is_struct()
&& def.non_enum_variant().tail_opt().is_some_and(|last_field| {
let typing_env = ty::TypingEnv::post_analysis(tcx, def.did());
@@ -625,7 +619,6 @@ fn layout_of_uncached<'tcx>(
tcx.layout_scalar_valid_range(def.did()),
get_discriminant_type,
discriminants_iter(),
- dont_niche_optimize_enum,
!maybe_unsized,
)
.map_err(|err| map_error(cx, ty, err))?;
@@ -651,7 +644,6 @@ fn layout_of_uncached<'tcx>(
tcx.layout_scalar_valid_range(def.did()),
get_discriminant_type,
discriminants_iter(),
- dont_niche_optimize_enum,
!maybe_unsized,
) else {
bug!("failed to compute unsized layout of {ty:?}");
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index f8d7934..2e0b16d 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -80,8 +80,11 @@ fn sizedness_constraint_for_ty<'tcx>(
fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
match tcx.hir_node_by_def_id(def_id) {
- hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.defaultness,
- hir::Node::ImplItem(hir::ImplItem { defaultness, .. })
+ hir::Node::Item(hir::Item {
+ kind: hir::ItemKind::Impl(hir::Impl { defaultness, of_trait: Some(_), .. }),
+ ..
+ })
+ | hir::Node::ImplItem(hir::ImplItem { defaultness, .. })
| hir::Node::TraitItem(hir::TraitItem { defaultness, .. }) => *defaultness,
node => {
bug!("`defaultness` called on {:?}", node);
@@ -106,10 +109,10 @@ fn adt_sizedness_constraint<'tcx>(
tcx: TyCtxt<'tcx>,
(def_id, sizedness): (DefId, SizedTraitKind),
) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
- if let Some(def_id) = def_id.as_local() {
- if let ty::Representability::Infinite(_) = tcx.representability(def_id) {
- return None;
- }
+ if let Some(def_id) = def_id.as_local()
+ && let ty::Representability::Infinite(_) = tcx.representability(def_id)
+ {
+ return None;
}
let def = tcx.adt_def(def_id);
diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs
index e3c4a79..3a00fe8 100644
--- a/compiler/rustc_type_ir/src/relate.rs
+++ b/compiler/rustc_type_ir/src/relate.rs
@@ -400,8 +400,12 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
(ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a),
(ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def == b_def => {
- let args = relation.relate_item_args(a_def.def_id(), a_args, b_args)?;
- Ok(Ty::new_adt(cx, a_def, args))
+ Ok(if a_args.is_empty() {
+ a
+ } else {
+ let args = relation.relate_item_args(a_def.def_id(), a_args, b_args)?;
+ if args == a_args { a } else { Ty::new_adt(cx, a_def, args) }
+ })
}
(ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(cx, a_id)),
@@ -515,8 +519,12 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
}
(ty::FnDef(a_def_id, a_args), ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => {
- let args = relation.relate_item_args(a_def_id, a_args, b_args)?;
- Ok(Ty::new_fn_def(cx, a_def_id, args))
+ Ok(if a_args.is_empty() {
+ a
+ } else {
+ let args = relation.relate_item_args(a_def_id, a_args, b_args)?;
+ if args == a_args { a } else { Ty::new_fn_def(cx, a_def_id, args) }
+ })
}
(ty::FnPtr(a_sig_tys, a_hdr), ty::FnPtr(b_sig_tys, b_hdr)) => {
diff --git a/library/Cargo.lock b/library/Cargo.lock
index 94155e0..a9a611f 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -78,9 +78,9 @@
[[package]]
name = "dlmalloc"
-version = "0.2.9"
+version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d01597dde41c0b9da50d5f8c219023d63d8f27f39a27095070fd191fddc83891"
+checksum = "fa3a2dbee57b69fbb5dbe852fa9c0925697fb0c7fbcb1593e90e5ffaedf13d51"
dependencies = [
"cfg-if",
"libc",
@@ -90,11 +90,10 @@
[[package]]
name = "fortanix-sgx-abi"
-version = "0.5.0"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5"
+checksum = "5efc85edd5b83e8394f4371dd0da6859dff63dd387dab8568fece6af4cde6f84"
dependencies = [
- "compiler_builtins",
"rustc-std-workspace-core",
]
@@ -238,9 +237,9 @@
[[package]]
name = "rand"
-version = "0.9.1"
+version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_core",
]
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index 017c790..9ba7c5b 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -21,9 +21,7 @@
[features]
compiler-builtins-mem = ['compiler_builtins/mem']
compiler-builtins-c = ["compiler_builtins/c"]
-compiler-builtins-no-asm = ["compiler_builtins/no-asm"]
compiler-builtins-no-f16-f128 = ["compiler_builtins/no-f16-f128"]
-compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"]
# Make panics and failed asserts immediately abort without formatting any message
panic_immediate_abort = ["core/panic_immediate_abort"]
# Choose algorithms that are optimized for binary size instead of runtime performance
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 6b6e4df..c091e49 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -94,7 +94,6 @@
// tidy-alphabetical-start
#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
-#![feature(array_chunks)]
#![feature(array_into_iter_constructors)]
#![feature(array_windows)]
#![feature(ascii_char)]
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index b4da565..ce9f967 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -16,10 +16,6 @@
use core::mem::MaybeUninit;
#[cfg(not(no_global_oom_handling))]
use core::ptr;
-#[unstable(feature = "array_chunks", issue = "74985")]
-pub use core::slice::ArrayChunks;
-#[unstable(feature = "array_chunks", issue = "74985")]
-pub use core::slice::ArrayChunksMut;
#[unstable(feature = "array_windows", issue = "75027")]
pub use core::slice::ArrayWindows;
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index a189c00..d58240f 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -787,12 +787,12 @@ pub fn from_utf16_lossy(v: &[u16]) -> String {
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "str_from_utf16_endian", issue = "116258")]
pub fn from_utf16le(v: &[u8]) -> Result<String, FromUtf16Error> {
- if v.len() % 2 != 0 {
+ let (chunks, []) = v.as_chunks::<2>() else {
return Err(FromUtf16Error(()));
- }
+ };
match (cfg!(target_endian = "little"), unsafe { v.align_to::<u16>() }) {
(true, ([], v, [])) => Self::from_utf16(v),
- _ => char::decode_utf16(v.array_chunks::<2>().copied().map(u16::from_le_bytes))
+ _ => char::decode_utf16(chunks.iter().copied().map(u16::from_le_bytes))
.collect::<Result<_, _>>()
.map_err(|_| FromUtf16Error(())),
}
@@ -830,11 +830,11 @@ pub fn from_utf16le_lossy(v: &[u8]) -> String {
(true, ([], v, [])) => Self::from_utf16_lossy(v),
(true, ([], v, [_remainder])) => Self::from_utf16_lossy(v) + "\u{FFFD}",
_ => {
- let mut iter = v.array_chunks::<2>();
- let string = char::decode_utf16(iter.by_ref().copied().map(u16::from_le_bytes))
+ let (chunks, remainder) = v.as_chunks::<2>();
+ let string = char::decode_utf16(chunks.iter().copied().map(u16::from_le_bytes))
.map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER))
.collect();
- if iter.remainder().is_empty() { string } else { string + "\u{FFFD}" }
+ if remainder.is_empty() { string } else { string + "\u{FFFD}" }
}
}
}
@@ -862,12 +862,12 @@ pub fn from_utf16le_lossy(v: &[u8]) -> String {
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "str_from_utf16_endian", issue = "116258")]
pub fn from_utf16be(v: &[u8]) -> Result<String, FromUtf16Error> {
- if v.len() % 2 != 0 {
+ let (chunks, []) = v.as_chunks::<2>() else {
return Err(FromUtf16Error(()));
- }
+ };
match (cfg!(target_endian = "big"), unsafe { v.align_to::<u16>() }) {
(true, ([], v, [])) => Self::from_utf16(v),
- _ => char::decode_utf16(v.array_chunks::<2>().copied().map(u16::from_be_bytes))
+ _ => char::decode_utf16(chunks.iter().copied().map(u16::from_be_bytes))
.collect::<Result<_, _>>()
.map_err(|_| FromUtf16Error(())),
}
@@ -905,11 +905,11 @@ pub fn from_utf16be_lossy(v: &[u8]) -> String {
(true, ([], v, [])) => Self::from_utf16_lossy(v),
(true, ([], v, [_remainder])) => Self::from_utf16_lossy(v) + "\u{FFFD}",
_ => {
- let mut iter = v.array_chunks::<2>();
- let string = char::decode_utf16(iter.by_ref().copied().map(u16::from_be_bytes))
+ let (chunks, remainder) = v.as_chunks::<2>();
+ let string = char::decode_utf16(chunks.iter().copied().map(u16::from_be_bytes))
.map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER))
.collect();
- if iter.remainder().is_empty() { string } else { string + "\u{FFFD}" }
+ if remainder.is_empty() { string } else { string + "\u{FFFD}" }
}
}
}
diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs
index ccb1cc4..da05f236 100644
--- a/library/core/src/borrow.rs
+++ b/library/core/src/borrow.rs
@@ -223,20 +223,20 @@ fn borrow_mut(&mut self) -> &mut T {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Borrow<T> for &T {
fn borrow(&self) -> &T {
- &**self
+ self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Borrow<T> for &mut T {
fn borrow(&self) -> &T {
- &**self
+ self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> BorrowMut<T> for &mut T {
fn borrow_mut(&mut self) -> &mut T {
- &mut **self
+ self
}
}
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index a34d1b4..51d037d 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -590,7 +590,7 @@ impl<T: PointeeSized> Clone for &T {
#[inline(always)]
#[rustc_diagnostic_item = "noop_method_clone"]
fn clone(&self) -> Self {
- *self
+ self
}
}
diff --git a/library/core/src/iter/adapters/rev.rs b/library/core/src/iter/adapters/rev.rs
index 06ab15d..17d3eef 100644
--- a/library/core/src/iter/adapters/rev.rs
+++ b/library/core/src/iter/adapters/rev.rs
@@ -20,6 +20,25 @@ impl<T> Rev<T> {
pub(in crate::iter) fn new(iter: T) -> Rev<T> {
Rev { iter }
}
+
+ /// Consumes the `Rev`, returning the inner iterator.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// #![feature(rev_into_inner)]
+ ///
+ /// let s = "foobar";
+ /// let mut rev = s.chars().rev();
+ /// assert_eq!(rev.next(), Some('r'));
+ /// assert_eq!(rev.next(), Some('a'));
+ /// assert_eq!(rev.next(), Some('b'));
+ /// assert_eq!(rev.into_inner().collect::<String>(), "foo");
+ /// ```
+ #[unstable(feature = "rev_into_inner", issue = "144277")]
+ pub fn into_inner(self) -> T {
+ self.iter
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 8ac6ce2..3d57da6 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -426,8 +426,10 @@ macro_rules! debug_assert_ne {
#[macro_export]
#[stable(feature = "matches_macro", since = "1.42.0")]
#[rustc_diagnostic_item = "matches_macro"]
+#[allow_internal_unstable(non_exhaustive_omitted_patterns_lint, stmt_expr_attributes)]
macro_rules! matches {
($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => {
+ #[allow(non_exhaustive_omitted_patterns)]
match $expression {
$pattern $(if $guard)? => true,
_ => false
diff --git a/library/core/src/mem/drop_guard.rs b/library/core/src/mem/drop_guard.rs
new file mode 100644
index 0000000..fecc94b
--- /dev/null
+++ b/library/core/src/mem/drop_guard.rs
@@ -0,0 +1,155 @@
+use crate::fmt::{self, Debug};
+use crate::mem::ManuallyDrop;
+use crate::ops::{Deref, DerefMut};
+
+/// Wrap a value and run a closure when dropped.
+///
+/// This is useful for quickly creating destructors inline.
+///
+/// # Examples
+///
+/// ```rust
+/// # #![allow(unused)]
+/// #![feature(drop_guard)]
+///
+/// use std::mem::DropGuard;
+///
+/// {
+/// // Create a new guard around a string that will
+/// // print its value when dropped.
+/// let s = String::from("Chashu likes tuna");
+/// let mut s = DropGuard::new(s, |s| println!("{s}"));
+///
+/// // Modify the string contained in the guard.
+/// s.push_str("!!!");
+///
+/// // The guard will be dropped here, printing:
+/// // "Chashu likes tuna!!!"
+/// }
+/// ```
+#[unstable(feature = "drop_guard", issue = "144426")]
+#[doc(alias = "ScopeGuard")]
+#[doc(alias = "defer")]
+pub struct DropGuard<T, F>
+where
+ F: FnOnce(T),
+{
+ inner: ManuallyDrop<T>,
+ f: ManuallyDrop<F>,
+}
+
+impl<T, F> DropGuard<T, F>
+where
+ F: FnOnce(T),
+{
+ /// Create a new instance of `DropGuard`.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # #![allow(unused)]
+ /// #![feature(drop_guard)]
+ ///
+ /// use std::mem::DropGuard;
+ ///
+ /// let value = String::from("Chashu likes tuna");
+ /// let guard = DropGuard::new(value, |s| println!("{s}"));
+ /// ```
+ #[unstable(feature = "drop_guard", issue = "144426")]
+ #[must_use]
+ pub const fn new(inner: T, f: F) -> Self {
+ Self { inner: ManuallyDrop::new(inner), f: ManuallyDrop::new(f) }
+ }
+
+ /// Consumes the `DropGuard`, returning the wrapped value.
+ ///
+ /// This will not execute the closure. This is implemented as an associated
+ /// function to prevent any potential conflicts with any other methods called
+ /// `into_inner` from the `Deref` and `DerefMut` impls.
+ ///
+ /// It is typically preferred to call this function instead of `mem::forget`
+ /// because it will return the stored value and drop variables captured
+ /// by the closure instead of leaking their owned resources.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # #![allow(unused)]
+ /// #![feature(drop_guard)]
+ ///
+ /// use std::mem::DropGuard;
+ ///
+ /// let value = String::from("Nori likes chicken");
+ /// let guard = DropGuard::new(value, |s| println!("{s}"));
+ /// assert_eq!(DropGuard::into_inner(guard), "Nori likes chicken");
+ /// ```
+ #[unstable(feature = "drop_guard", issue = "144426")]
+ #[inline]
+ pub fn into_inner(guard: Self) -> T {
+ // First we ensure that dropping the guard will not trigger
+ // its destructor
+ let mut guard = ManuallyDrop::new(guard);
+
+ // Next we manually read the stored value from the guard.
+ //
+ // SAFETY: this is safe because we've taken ownership of the guard.
+ let value = unsafe { ManuallyDrop::take(&mut guard.inner) };
+
+ // Finally we drop the stored closure. We do this *after* having read
+ // the value, so that even if the closure's `drop` function panics,
+ // unwinding still tries to drop the value.
+ //
+ // SAFETY: this is safe because we've taken ownership of the guard.
+ unsafe { ManuallyDrop::drop(&mut guard.f) };
+ value
+ }
+}
+
+#[unstable(feature = "drop_guard", issue = "144426")]
+impl<T, F> Deref for DropGuard<T, F>
+where
+ F: FnOnce(T),
+{
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &*self.inner
+ }
+}
+
+#[unstable(feature = "drop_guard", issue = "144426")]
+impl<T, F> DerefMut for DropGuard<T, F>
+where
+ F: FnOnce(T),
+{
+ fn deref_mut(&mut self) -> &mut T {
+ &mut *self.inner
+ }
+}
+
+#[unstable(feature = "drop_guard", issue = "144426")]
+impl<T, F> Drop for DropGuard<T, F>
+where
+ F: FnOnce(T),
+{
+ fn drop(&mut self) {
+ // SAFETY: `DropGuard` is in the process of being dropped.
+ let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
+
+ // SAFETY: `DropGuard` is in the process of being dropped.
+ let f = unsafe { ManuallyDrop::take(&mut self.f) };
+
+ f(inner);
+ }
+}
+
+#[unstable(feature = "drop_guard", issue = "144426")]
+impl<T, F> Debug for DropGuard<T, F>
+where
+ T: Debug,
+ F: FnOnce(T),
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&**self, f)
+ }
+}
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 2198d09..db4c8e9 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -21,6 +21,10 @@
#[unstable(feature = "transmutability", issue = "99571")]
pub use transmutability::{Assume, TransmuteFrom};
+mod drop_guard;
+#[unstable(feature = "drop_guard", issue = "144426")]
+pub use drop_guard::DropGuard;
+
// This one has to be a re-export (rather than wrapping the underlying intrinsic) so that we can do
// the special magic "types have equal size" check at the call site.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -960,7 +964,7 @@ pub fn drop<T>(_x: T) {}
///
/// This function is not magic; it is literally defined as
/// ```
-/// pub fn copy<T: Copy>(x: &T) -> T { *x }
+/// pub const fn copy<T: Copy>(x: &T) -> T { *x }
/// ```
///
/// It is useful when you want to pass a function pointer to a combinator, rather than defining a new closure.
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index 9d9d180..c2dede9 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -158,7 +158,7 @@ impl<T: ?Sized> const Deref for &T {
#[rustc_diagnostic_item = "noop_method_deref"]
fn deref(&self) -> &T {
- *self
+ self
}
}
@@ -171,7 +171,7 @@ impl<T: ?Sized> const Deref for &mut T {
type Target = T;
fn deref(&self) -> &T {
- *self
+ self
}
}
@@ -280,7 +280,7 @@ pub trait DerefMut: ~const Deref + PointeeSized {
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
impl<T: ?Sized> const DerefMut for &mut T {
fn deref_mut(&mut self) -> &mut T {
- *self
+ self
}
}
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index ad3b643..f33a33e 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -1141,6 +1141,12 @@ fn end_bound(&self) -> Bound<&T> {
}
}
+// This impl intentionally does not have `T: ?Sized`;
+// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
+//
+/// If you need to use this implementation where `T` is unsized,
+/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
+/// i.e. replace `start..` with `(Bound::Included(start), Bound::Unbounded)`.
#[stable(feature = "collections_range", since = "1.28.0")]
impl<T> RangeBounds<T> for RangeFrom<&T> {
fn start_bound(&self) -> Bound<&T> {
@@ -1151,6 +1157,12 @@ fn end_bound(&self) -> Bound<&T> {
}
}
+// This impl intentionally does not have `T: ?Sized`;
+// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
+//
+/// If you need to use this implementation where `T` is unsized,
+/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
+/// i.e. replace `..end` with `(Bound::Unbounded, Bound::Excluded(end))`.
#[stable(feature = "collections_range", since = "1.28.0")]
impl<T> RangeBounds<T> for RangeTo<&T> {
fn start_bound(&self) -> Bound<&T> {
@@ -1161,6 +1173,12 @@ fn end_bound(&self) -> Bound<&T> {
}
}
+// This impl intentionally does not have `T: ?Sized`;
+// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
+//
+/// If you need to use this implementation where `T` is unsized,
+/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
+/// i.e. replace `start..end` with `(Bound::Included(start), Bound::Excluded(end))`.
#[stable(feature = "collections_range", since = "1.28.0")]
impl<T> RangeBounds<T> for Range<&T> {
fn start_bound(&self) -> Bound<&T> {
@@ -1171,6 +1189,12 @@ fn end_bound(&self) -> Bound<&T> {
}
}
+// This impl intentionally does not have `T: ?Sized`;
+// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
+//
+/// If you need to use this implementation where `T` is unsized,
+/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
+/// i.e. replace `start..=end` with `(Bound::Included(start), Bound::Included(end))`.
#[stable(feature = "collections_range", since = "1.28.0")]
impl<T> RangeBounds<T> for RangeInclusive<&T> {
fn start_bound(&self) -> Bound<&T> {
@@ -1181,6 +1205,12 @@ fn end_bound(&self) -> Bound<&T> {
}
}
+// This impl intentionally does not have `T: ?Sized`;
+// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
+//
+/// If you need to use this implementation where `T` is unsized,
+/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
+/// i.e. replace `..=end` with `(Bound::Unbounded, Bound::Included(end))`.
#[stable(feature = "collections_range", since = "1.28.0")]
impl<T> RangeBounds<T> for RangeToInclusive<&T> {
fn start_bound(&self) -> Bound<&T> {
diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs
index 9722702..6ef7d5a 100644
--- a/library/core/src/panic/location.rs
+++ b/library/core/src/panic/location.rs
@@ -1,5 +1,7 @@
+use crate::cmp::Ordering;
use crate::ffi::CStr;
use crate::fmt;
+use crate::hash::{Hash, Hasher};
use crate::marker::PhantomData;
use crate::ptr::NonNull;
@@ -32,7 +34,7 @@
/// Files are compared as strings, not `Path`, which could be unexpected.
/// See [`Location::file`]'s documentation for more discussion.
#[lang = "panic_location"]
-#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[derive(Copy, Clone)]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub struct Location<'a> {
// A raw pointer is used rather than a reference because the pointer is valid for one more byte
@@ -45,6 +47,44 @@ pub struct Location<'a> {
}
#[stable(feature = "panic_hooks", since = "1.10.0")]
+impl PartialEq for Location<'_> {
+ fn eq(&self, other: &Self) -> bool {
+ // Compare col / line first as they're cheaper to compare and more likely to differ,
+ // while not impacting the result.
+ self.col == other.col && self.line == other.line && self.file() == other.file()
+ }
+}
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+impl Eq for Location<'_> {}
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+impl Ord for Location<'_> {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.file()
+ .cmp(other.file())
+ .then_with(|| self.line.cmp(&other.line))
+ .then_with(|| self.col.cmp(&other.col))
+ }
+}
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+impl PartialOrd for Location<'_> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+impl Hash for Location<'_> {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.file().hash(state);
+ self.line.hash(state);
+ self.col.hash(state);
+ }
+}
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
impl fmt::Debug for Location<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Location")
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index dbe3999..1a2a518 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -974,9 +974,10 @@ pub const fn dangling_mut<T>() -> *mut T {
#[must_use]
#[inline(always)]
#[stable(feature = "exposed_provenance", since = "1.84.0")]
+#[rustc_const_unstable(feature = "const_exposed_provenance", issue = "144538")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
-pub fn with_exposed_provenance<T>(addr: usize) -> *const T {
+pub const fn with_exposed_provenance<T>(addr: usize) -> *const T {
addr as *const T
}
@@ -1014,9 +1015,10 @@ pub fn with_exposed_provenance<T>(addr: usize) -> *const T {
#[must_use]
#[inline(always)]
#[stable(feature = "exposed_provenance", since = "1.84.0")]
+#[rustc_const_unstable(feature = "const_exposed_provenance", issue = "144538")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
-pub fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T {
+pub const fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T {
addr as *mut T
}
diff --git a/library/core/src/range.rs b/library/core/src/range.rs
index 5cd7956..7158fa0 100644
--- a/library/core/src/range.rs
+++ b/library/core/src/range.rs
@@ -167,6 +167,12 @@ fn end_bound(&self) -> Bound<&T> {
}
}
+// This impl intentionally does not have `T: ?Sized`;
+// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
+//
+/// If you need to use this implementation where `T` is unsized,
+/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
+/// i.e. replace `start..end` with `(Bound::Included(start), Bound::Excluded(end))`.
#[unstable(feature = "new_range_api", issue = "125687")]
impl<T> RangeBounds<T> for Range<&T> {
fn start_bound(&self) -> Bound<&T> {
@@ -346,6 +352,12 @@ fn end_bound(&self) -> Bound<&T> {
}
}
+// This impl intentionally does not have `T: ?Sized`;
+// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
+//
+/// If you need to use this implementation where `T` is unsized,
+/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
+/// i.e. replace `start..=end` with `(Bound::Included(start), Bound::Included(end))`.
#[unstable(feature = "new_range_api", issue = "125687")]
impl<T> RangeBounds<T> for RangeInclusive<&T> {
fn start_bound(&self) -> Bound<&T> {
@@ -491,6 +503,12 @@ fn end_bound(&self) -> Bound<&T> {
}
}
+// This impl intentionally does not have `T: ?Sized`;
+// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
+//
+/// If you need to use this implementation where `T` is unsized,
+/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
+/// i.e. replace `start..` with `(Bound::Included(start), Bound::Unbounded)`.
#[unstable(feature = "new_range_api", issue = "125687")]
impl<T> RangeBounds<T> for RangeFrom<&T> {
fn start_bound(&self) -> Bound<&T> {
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 33132dc..ae910e0 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -2301,255 +2301,6 @@ fn is_empty(&self) -> bool {
}
}
-/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a
-/// time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last
-/// up to `N-1` elements will be omitted but can be retrieved from
-/// the [`remainder`] function from the iterator.
-///
-/// This struct is created by the [`array_chunks`] method on [slices].
-///
-/// # Example
-///
-/// ```
-/// #![feature(array_chunks)]
-///
-/// let slice = ['l', 'o', 'r', 'e', 'm'];
-/// let mut iter = slice.array_chunks::<2>();
-/// assert_eq!(iter.next(), Some(&['l', 'o']));
-/// assert_eq!(iter.next(), Some(&['r', 'e']));
-/// assert_eq!(iter.next(), None);
-/// ```
-///
-/// [`array_chunks`]: slice::array_chunks
-/// [`remainder`]: ArrayChunks::remainder
-/// [slices]: slice
-#[derive(Debug)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-pub struct ArrayChunks<'a, T: 'a, const N: usize> {
- iter: Iter<'a, [T; N]>,
- rem: &'a [T],
-}
-
-impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
- #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")]
- #[inline]
- pub(super) const fn new(slice: &'a [T]) -> Self {
- let (array_slice, rem) = slice.as_chunks();
- Self { iter: array_slice.iter(), rem }
- }
-
- /// Returns the remainder of the original slice that is not going to be
- /// returned by the iterator. The returned slice has at most `N-1`
- /// elements.
- #[must_use]
- #[unstable(feature = "array_chunks", issue = "74985")]
- pub fn remainder(&self) -> &'a [T] {
- self.rem
- }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> Clone for ArrayChunks<'_, T, N> {
- fn clone(&self) -> Self {
- ArrayChunks { iter: self.iter.clone(), rem: self.rem }
- }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> {
- type Item = &'a [T; N];
-
- #[inline]
- fn next(&mut self) -> Option<&'a [T; N]> {
- self.iter.next()
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-
- #[inline]
- fn count(self) -> usize {
- self.iter.count()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<Self::Item> {
- self.iter.nth(n)
- }
-
- #[inline]
- fn last(self) -> Option<Self::Item> {
- self.iter.last()
- }
-
- unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a [T; N] {
- // SAFETY: The safety guarantees of `__iterator_get_unchecked` are
- // transferred to the caller.
- unsafe { self.iter.__iterator_get_unchecked(i) }
- }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a [T; N]> {
- self.iter.next_back()
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- self.iter.nth_back(n)
- }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> ExactSizeIterator for ArrayChunks<'_, T, N> {
- fn is_empty(&self) -> bool {
- self.iter.is_empty()
- }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T, const N: usize> TrustedLen for ArrayChunks<'_, T, N> {}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> FusedIterator for ArrayChunks<'_, T, N> {}
-
-#[doc(hidden)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> {}
-
-#[doc(hidden)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-unsafe impl<'a, T, const N: usize> TrustedRandomAccessNoCoerce for ArrayChunks<'a, T, N> {
- const MAY_HAVE_SIDE_EFFECT: bool = false;
-}
-
-/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements
-/// at a time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last
-/// up to `N-1` elements will be omitted but can be retrieved from
-/// the [`into_remainder`] function from the iterator.
-///
-/// This struct is created by the [`array_chunks_mut`] method on [slices].
-///
-/// # Example
-///
-/// ```
-/// #![feature(array_chunks)]
-///
-/// let mut slice = ['l', 'o', 'r', 'e', 'm'];
-/// let iter = slice.array_chunks_mut::<2>();
-/// ```
-///
-/// [`array_chunks_mut`]: slice::array_chunks_mut
-/// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder
-/// [slices]: slice
-#[derive(Debug)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-pub struct ArrayChunksMut<'a, T: 'a, const N: usize> {
- iter: IterMut<'a, [T; N]>,
- rem: &'a mut [T],
-}
-
-impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> {
- #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")]
- #[inline]
- pub(super) const fn new(slice: &'a mut [T]) -> Self {
- let (array_slice, rem) = slice.as_chunks_mut();
- Self { iter: array_slice.iter_mut(), rem }
- }
-
- /// Returns the remainder of the original slice that is not going to be
- /// returned by the iterator. The returned slice has at most `N-1`
- /// elements.
- #[must_use = "`self` will be dropped if the result is not used"]
- #[unstable(feature = "array_chunks", issue = "74985")]
- pub fn into_remainder(self) -> &'a mut [T] {
- self.rem
- }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> {
- type Item = &'a mut [T; N];
-
- #[inline]
- fn next(&mut self) -> Option<&'a mut [T; N]> {
- self.iter.next()
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-
- #[inline]
- fn count(self) -> usize {
- self.iter.count()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<Self::Item> {
- self.iter.nth(n)
- }
-
- #[inline]
- fn last(self) -> Option<Self::Item> {
- self.iter.last()
- }
-
- unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a mut [T; N] {
- // SAFETY: The safety guarantees of `__iterator_get_unchecked` are transferred to
- // the caller.
- unsafe { self.iter.__iterator_get_unchecked(i) }
- }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a mut [T; N]> {
- self.iter.next_back()
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- self.iter.nth_back(n)
- }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> ExactSizeIterator for ArrayChunksMut<'_, T, N> {
- fn is_empty(&self) -> bool {
- self.iter.is_empty()
- }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T, const N: usize> TrustedLen for ArrayChunksMut<'_, T, N> {}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> FusedIterator for ArrayChunksMut<'_, T, N> {}
-
-#[doc(hidden)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> {}
-
-#[doc(hidden)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-unsafe impl<'a, T, const N: usize> TrustedRandomAccessNoCoerce for ArrayChunksMut<'a, T, N> {
- const MAY_HAVE_SIDE_EFFECT: bool = false;
-}
-
/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
/// time), starting at the end of the slice.
///
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 6fe5aff..1404299 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -52,8 +52,6 @@
pub use index::{range, try_range};
#[unstable(feature = "array_windows", issue = "75027")]
pub use iter::ArrayWindows;
-#[unstable(feature = "array_chunks", issue = "74985")]
-pub use iter::{ArrayChunks, ArrayChunksMut};
#[stable(feature = "slice_group_by", since = "1.77.0")]
pub use iter::{ChunkBy, ChunkByMut};
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1232,7 +1230,7 @@ pub const fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> {
///
/// [`chunks`]: slice::chunks
/// [`rchunks_exact`]: slice::rchunks_exact
- /// [`as_chunks`]: slice::chunks
+ /// [`as_chunks`]: slice::as_chunks
#[stable(feature = "chunks_exact", since = "1.31.0")]
#[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")]
#[inline]
@@ -1448,42 +1446,6 @@ pub const fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_
(remainder, array_slice)
}
- /// Returns an iterator over `N` elements of the slice at a time, starting at the
- /// beginning of the slice.
- ///
- /// The chunks are array references and do not overlap. If `N` does not divide the
- /// length of the slice, then the last up to `N-1` elements will be omitted and can be
- /// retrieved from the `remainder` function of the iterator.
- ///
- /// This method is the const generic equivalent of [`chunks_exact`].
- ///
- /// # Panics
- ///
- /// Panics if `N` is zero. This check will most probably get changed to a compile time
- /// error before this method gets stabilized.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(array_chunks)]
- /// let slice = ['l', 'o', 'r', 'e', 'm'];
- /// let mut iter = slice.array_chunks();
- /// assert_eq!(iter.next().unwrap(), &['l', 'o']);
- /// assert_eq!(iter.next().unwrap(), &['r', 'e']);
- /// assert!(iter.next().is_none());
- /// assert_eq!(iter.remainder(), &['m']);
- /// ```
- ///
- /// [`chunks_exact`]: slice::chunks_exact
- #[unstable(feature = "array_chunks", issue = "74985")]
- #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")]
- #[inline]
- #[track_caller]
- pub const fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
- assert!(N != 0, "chunk size must be non-zero");
- ArrayChunks::new(self)
- }
-
/// Splits the slice into a slice of `N`-element arrays,
/// assuming that there's no remainder.
///
@@ -1646,44 +1608,6 @@ pub const fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
(remainder, array_slice)
}
- /// Returns an iterator over `N` elements of the slice at a time, starting at the
- /// beginning of the slice.
- ///
- /// The chunks are mutable array references and do not overlap. If `N` does not divide
- /// the length of the slice, then the last up to `N-1` elements will be omitted and
- /// can be retrieved from the `into_remainder` function of the iterator.
- ///
- /// This method is the const generic equivalent of [`chunks_exact_mut`].
- ///
- /// # Panics
- ///
- /// Panics if `N` is zero. This check will most probably get changed to a compile time
- /// error before this method gets stabilized.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(array_chunks)]
- /// let v = &mut [0, 0, 0, 0, 0];
- /// let mut count = 1;
- ///
- /// for chunk in v.array_chunks_mut() {
- /// *chunk = [count; 2];
- /// count += 1;
- /// }
- /// assert_eq!(v, &[1, 1, 2, 2, 0]);
- /// ```
- ///
- /// [`chunks_exact_mut`]: slice::chunks_exact_mut
- #[unstable(feature = "array_chunks", issue = "74985")]
- #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")]
- #[inline]
- #[track_caller]
- pub const fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N> {
- assert!(N != 0, "chunk size must be non-zero");
- ArrayChunksMut::new(self)
- }
-
/// Returns an iterator over overlapping windows of `N` elements of a slice,
/// starting at the beginning of the slice.
///
diff --git a/library/core/src/slice/sort/select.rs b/library/core/src/slice/sort/select.rs
index 82194db..fc31013 100644
--- a/library/core/src/slice/sort/select.rs
+++ b/library/core/src/slice/sort/select.rs
@@ -101,8 +101,7 @@ fn partition_at_index_loop<'a, T, F>(
// slice. Partition the slice into elements equal to and elements greater than the pivot.
// This case is usually hit when the slice contains many duplicate elements.
if let Some(p) = ancestor_pivot {
- // SAFETY: choose_pivot promises to return a valid pivot position.
- let pivot = unsafe { v.get_unchecked(pivot_pos) };
+ let pivot = &v[pivot_pos];
if !is_less(p, pivot) {
let num_lt = partition(v, pivot_pos, &mut |a, b| !is_less(b, a));
diff --git a/library/core/src/slice/sort/shared/pivot.rs b/library/core/src/slice/sort/shared/pivot.rs
index 3aace48..9eb60f8 100644
--- a/library/core/src/slice/sort/shared/pivot.rs
+++ b/library/core/src/slice/sort/shared/pivot.rs
@@ -1,6 +1,6 @@
//! This module contains the logic for pivot selection.
-use crate::intrinsics;
+use crate::{hint, intrinsics};
// Recursively select a pseudomedian if above this threshold.
const PSEUDO_MEDIAN_REC_THRESHOLD: usize = 64;
@@ -9,6 +9,7 @@
///
/// This chooses a pivot by sampling an adaptive amount of points, approximating
/// the quality of a median of sqrt(n) elements.
+#[inline]
pub fn choose_pivot<T, F: FnMut(&T, &T) -> bool>(v: &[T], is_less: &mut F) -> usize {
// We use unsafe code and raw pointers here because we're dealing with
// heavy recursion. Passing safe slices around would involve a lot of
@@ -22,7 +23,7 @@ pub fn choose_pivot<T, F: FnMut(&T, &T) -> bool>(v: &[T], is_less: &mut F) -> us
// SAFETY: a, b, c point to initialized regions of len_div_8 elements,
// satisfying median3 and median3_rec's preconditions as v_base points
// to an initialized region of n = len elements.
- unsafe {
+ let index = unsafe {
let v_base = v.as_ptr();
let len_div_8 = len / 8;
@@ -35,6 +36,11 @@ pub fn choose_pivot<T, F: FnMut(&T, &T) -> bool>(v: &[T], is_less: &mut F) -> us
} else {
median3_rec(a, b, c, len_div_8, is_less).offset_from_unsigned(v_base)
}
+ };
+ // SAFETY: preconditions must have been met for offset_from_unsigned()
+ unsafe {
+ hint::assert_unchecked(index < v.len());
+ index
}
}
diff --git a/library/core/src/slice/sort/stable/quicksort.rs b/library/core/src/slice/sort/stable/quicksort.rs
index 3c96887..0439ba8 100644
--- a/library/core/src/slice/sort/stable/quicksort.rs
+++ b/library/core/src/slice/sort/stable/quicksort.rs
@@ -37,10 +37,6 @@ pub fn quicksort<T, F: FnMut(&T, &T) -> bool>(
limit -= 1;
let pivot_pos = choose_pivot(v, is_less);
- // SAFETY: choose_pivot promises to return a valid pivot index.
- unsafe {
- intrinsics::assume(pivot_pos < v.len());
- }
// SAFETY: We only access the temporary copy for Freeze types, otherwise
// self-modifications via `is_less` would not be observed and this would
diff --git a/library/core/src/slice/sort/unstable/quicksort.rs b/library/core/src/slice/sort/unstable/quicksort.rs
index 98efee2..bdf56a8 100644
--- a/library/core/src/slice/sort/unstable/quicksort.rs
+++ b/library/core/src/slice/sort/unstable/quicksort.rs
@@ -48,8 +48,7 @@ pub(crate) fn quicksort<'a, T, F>(
// slice. Partition the slice into elements equal to and elements greater than the pivot.
// This case is usually hit when the slice contains many duplicate elements.
if let Some(p) = ancestor_pivot {
- // SAFETY: We assume choose_pivot yields an in-bounds position.
- if !is_less(p, unsafe { v.get_unchecked(pivot_pos) }) {
+ if !is_less(p, &v[pivot_pos]) {
let num_lt = partition(v, pivot_pos, &mut |a, b| !is_less(b, a));
// Continue sorting elements greater than the pivot. We know that `num_lt` contains
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index bcf8864..d2985d8 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -52,7 +52,7 @@ fn advance_by(&mut self, mut remainder: usize) -> Result<(), NonZero<usize>> {
const CHUNK_SIZE: usize = 32;
if remainder >= CHUNK_SIZE {
- let mut chunks = self.iter.as_slice().array_chunks::<CHUNK_SIZE>();
+ let mut chunks = self.iter.as_slice().as_chunks::<CHUNK_SIZE>().0.iter();
let mut bytes_skipped: usize = 0;
while remainder > CHUNK_SIZE
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 029abf1..c40af4d 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -407,17 +407,22 @@ pub const fn is_char_boundary(&self, index: usize) -> bool {
/// ```
#[unstable(feature = "round_char_boundary", issue = "93743")]
#[inline]
- pub fn floor_char_boundary(&self, index: usize) -> usize {
+ pub const fn floor_char_boundary(&self, index: usize) -> usize {
if index >= self.len() {
self.len()
} else {
- let lower_bound = index.saturating_sub(3);
- let new_index = self.as_bytes()[lower_bound..=index]
- .iter()
- .rposition(|b| b.is_utf8_char_boundary());
+ let mut i = index;
+ while i > 0 {
+ if self.as_bytes()[i].is_utf8_char_boundary() {
+ break;
+ }
+ i -= 1;
+ }
- // SAFETY: we know that the character boundary will be within four bytes
- unsafe { lower_bound + new_index.unwrap_unchecked() }
+ // The character boundary will be within four bytes of the index
+ debug_assert!(i >= index.saturating_sub(3));
+
+ i
}
}
@@ -445,15 +450,22 @@ pub fn floor_char_boundary(&self, index: usize) -> usize {
/// ```
#[unstable(feature = "round_char_boundary", issue = "93743")]
#[inline]
- pub fn ceil_char_boundary(&self, index: usize) -> usize {
+ pub const fn ceil_char_boundary(&self, index: usize) -> usize {
if index >= self.len() {
self.len()
} else {
- let upper_bound = Ord::min(index + 4, self.len());
- self.as_bytes()[index..upper_bound]
- .iter()
- .position(|b| b.is_utf8_char_boundary())
- .map_or(upper_bound, |pos| pos + index)
+ let mut i = index;
+ while i < self.len() {
+ if self.as_bytes()[i].is_utf8_char_boundary() {
+ break;
+ }
+ i += 1;
+ }
+
+ // The character boundary will be within four bytes of the index
+ debug_assert!(i <= index + 3);
+
+ i
}
}
diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs
index bcbbb11..e116b13 100644
--- a/library/core/src/str/pattern.rs
+++ b/library/core/src/str/pattern.rs
@@ -996,7 +996,10 @@ fn is_contained_in(self, haystack: &str) -> bool {
return haystack.as_bytes().contains(&self.as_bytes()[0]);
}
- #[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
+ #[cfg(any(
+ all(target_arch = "x86_64", target_feature = "sse2"),
+ all(target_arch = "loongarch64", target_feature = "lsx")
+ ))]
if self.len() <= 32 {
if let Some(result) = simd_contains(self, haystack) {
return result;
@@ -1770,11 +1773,18 @@ fn matching(a: usize, b: usize) -> Self::Output {
/// If we ever ship std with for x86-64-v3 or adapt this for other platforms then wider vectors
/// should be evaluated.
///
+/// Similarly, on LoongArch the 128-bit LSX vector extension is the baseline,
+/// so we also use `u8x16` there. Wider vector widths may be considered
+/// for future LoongArch extensions (e.g., LASX).
+///
/// For haystacks smaller than vector-size + needle length it falls back to
/// a naive O(n*m) search so this implementation should not be called on larger needles.
///
/// [0]: http://0x80.pl/articles/simd-strfind.html#sse-avx2
-#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
+#[cfg(any(
+ all(target_arch = "x86_64", target_feature = "sse2"),
+ all(target_arch = "loongarch64", target_feature = "lsx")
+))]
#[inline]
fn simd_contains(needle: &str, haystack: &str) -> Option<bool> {
let needle = needle.as_bytes();
@@ -1906,7 +1916,10 @@ fn simd_contains(needle: &str, haystack: &str) -> Option<bool> {
/// # Safety
///
/// Both slices must have the same length.
-#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] // only called on x86
+#[cfg(any(
+ all(target_arch = "x86_64", target_feature = "sse2"),
+ all(target_arch = "loongarch64", target_feature = "lsx")
+))]
#[inline]
unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool {
debug_assert_eq!(x.len(), y.len());
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 546f3d9..70c02ea 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -563,8 +563,8 @@ pub const fn new(v: bool) -> AtomicBool {
/// `align_of::<AtomicBool>() == 1`).
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
/// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not
- /// allowed to mix atomic and non-atomic accesses, or atomic accesses of different sizes,
- /// without synchronization.
+ /// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different
+ /// sizes, without synchronization.
///
/// [valid]: crate::ptr#safety
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
@@ -1245,8 +1245,8 @@ pub fn fetch_not(&self, order: Ordering) -> bool {
/// Returning an `*mut` pointer from a shared reference to this atomic is safe because the
/// atomic types work with interior mutability. All modifications of an atomic change the value
/// through a shared reference, and can do so safely as long as they use atomic operations. Any
- /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
- /// restriction: operations on it must be atomic.
+ /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the
+ /// requirements of the [memory model].
///
/// # Examples
///
@@ -1264,6 +1264,8 @@ pub fn fetch_not(&self, order: Ordering) -> bool {
/// }
/// # }
/// ```
+ ///
+ /// [memory model]: self#memory-model-for-atomic-accesses
#[inline]
#[stable(feature = "atomic_as_ptr", since = "1.70.0")]
#[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")]
@@ -1519,8 +1521,8 @@ pub const fn new(p: *mut T) -> AtomicPtr<T> {
/// can be bigger than `align_of::<*mut T>()`).
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
/// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not
- /// allowed to mix atomic and non-atomic accesses, or atomic accesses of different sizes,
- /// without synchronization.
+ /// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different
+ /// sizes, without synchronization.
///
/// [valid]: crate::ptr#safety
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
@@ -2487,8 +2489,8 @@ pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T {
/// Returning an `*mut` pointer from a shared reference to this atomic is safe because the
/// atomic types work with interior mutability. All modifications of an atomic change the value
/// through a shared reference, and can do so safely as long as they use atomic operations. Any
- /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
- /// restriction: operations on it must be atomic.
+ /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the
+ /// requirements of the [memory model].
///
/// # Examples
///
@@ -2507,6 +2509,8 @@ pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T {
/// my_atomic_op(atomic.as_ptr());
/// }
/// ```
+ ///
+ /// [memory model]: self#memory-model-for-atomic-accesses
#[inline]
#[stable(feature = "atomic_as_ptr", since = "1.70.0")]
#[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")]
@@ -2698,8 +2702,8 @@ pub const fn new(v: $int_type) -> Self {
}]
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
/// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not
- /// allowed to mix atomic and non-atomic accesses, or atomic accesses of different sizes,
- /// without synchronization.
+ /// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different
+ /// sizes, without synchronization.
///
/// [valid]: crate::ptr#safety
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
@@ -3619,8 +3623,8 @@ pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
/// Returning an `*mut` pointer from a shared reference to this atomic is safe because the
/// atomic types work with interior mutability. All modifications of an atomic change the value
/// through a shared reference, and can do so safely as long as they use atomic operations. Any
- /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
- /// restriction: operations on it must be atomic.
+ /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the
+ /// requirements of the [memory model].
///
/// # Examples
///
@@ -3640,6 +3644,8 @@ pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
/// }
/// # }
/// ```
+ ///
+ /// [memory model]: self#memory-model-for-atomic-accesses
#[inline]
#[stable(feature = "atomic_as_ptr", since = "1.70.0")]
#[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")]
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index 4cfac9e..029a7b0 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -2,7 +2,6 @@
#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
#![cfg_attr(test, feature(cfg_select))]
#![feature(alloc_layout_extra)]
-#![feature(array_chunks)]
#![feature(array_ptr_get)]
#![feature(array_try_from_fn)]
#![feature(array_windows)]
@@ -30,6 +29,7 @@
#![feature(core_private_diy_float)]
#![feature(cstr_display)]
#![feature(dec2flt)]
+#![feature(drop_guard)]
#![feature(duration_constants)]
#![feature(duration_constructors)]
#![feature(duration_constructors_lite)]
@@ -76,6 +76,7 @@
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(next_index)]
+#![feature(non_exhaustive_omitted_patterns_lint)]
#![feature(numfmt)]
#![feature(pattern)]
#![feature(pointer_is_aligned_to)]
diff --git a/library/coretests/tests/macros.rs b/library/coretests/tests/macros.rs
index 1c6aa90..50b5eb6 100644
--- a/library/coretests/tests/macros.rs
+++ b/library/coretests/tests/macros.rs
@@ -213,3 +213,9 @@ fn _expression() {
}
);
}
+
+#[deny(non_exhaustive_omitted_patterns)]
+fn _matches_does_not_trigger_non_exhaustive_omitted_patterns_lint(o: core::sync::atomic::Ordering) {
+ // Ordering is a #[non_exhaustive] enum from a separate crate
+ let _m = matches!(o, core::sync::atomic::Ordering::Relaxed);
+}
diff --git a/library/coretests/tests/mem.rs b/library/coretests/tests/mem.rs
index 9c15be4..e896c61 100644
--- a/library/coretests/tests/mem.rs
+++ b/library/coretests/tests/mem.rs
@@ -1,5 +1,6 @@
use core::mem::*;
use core::{array, ptr};
+use std::cell::Cell;
#[cfg(panic = "unwind")]
use std::rc::Rc;
@@ -795,3 +796,48 @@ unsafe impl Sync for FooPtr {}
assert_eq!(unsafe { (*UNINIT.0.cast::<[[u8; SIZE]; 1]>())[0] }, [0u8; SIZE]);
}
+
+#[test]
+fn drop_guards_only_dropped_by_closure_when_run() {
+ let value_drops = Cell::new(0);
+ let value = DropGuard::new((), |()| value_drops.set(1 + value_drops.get()));
+ let closure_drops = Cell::new(0);
+ let guard = DropGuard::new(value, |_| closure_drops.set(1 + closure_drops.get()));
+ assert_eq!(value_drops.get(), 0);
+ assert_eq!(closure_drops.get(), 0);
+ drop(guard);
+ assert_eq!(value_drops.get(), 1);
+ assert_eq!(closure_drops.get(), 1);
+}
+
+#[test]
+fn drop_guard_into_inner() {
+ let dropped = Cell::new(false);
+ let value = DropGuard::new(42, |_| dropped.set(true));
+ let guard = DropGuard::new(value, |_| dropped.set(true));
+ let inner = DropGuard::into_inner(guard);
+ assert_eq!(dropped.get(), false);
+ assert_eq!(*inner, 42);
+}
+
+#[test]
+#[cfg(panic = "unwind")]
+fn drop_guard_always_drops_value_if_closure_drop_unwinds() {
+ // Create a value with a destructor, which we will validate ran successfully.
+ let mut value_was_dropped = false;
+ let value_with_tracked_destruction = DropGuard::new((), |_| value_was_dropped = true);
+
+ // Create a closure that will begin unwinding when dropped.
+ let drop_bomb = DropGuard::new((), |_| panic!());
+ let closure_that_panics_on_drop = move |_| {
+ let _drop_bomb = drop_bomb;
+ };
+
+ // This will run the closure, which will panic when dropped. This should
+ // run the destructor of the value we passed, which we validate.
+ let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
+ let guard = DropGuard::new(value_with_tracked_destruction, closure_that_panics_on_drop);
+ DropGuard::into_inner(guard);
+ }));
+ assert!(value_was_dropped);
+}
diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs
index 193d588..8bf4094 100644
--- a/library/coretests/tests/num/dec2flt/float.rs
+++ b/library/coretests/tests/num/dec2flt/float.rs
@@ -1,13 +1,14 @@
use core::num::dec2flt::float::RawFloat;
+use crate::num::{ldexp_f32, ldexp_f64};
+
// FIXME(f16_f128): enable on all targets once possible.
#[test]
#[cfg(target_has_reliable_f16)]
fn test_f16_integer_decode() {
assert_eq!(3.14159265359f16.integer_decode(), (1608, -9, 1));
assert_eq!((-8573.5918555f16).integer_decode(), (1072, 3, -1));
- #[cfg(not(miri))] // miri doesn't have powf16
- assert_eq!(2f16.powf(14.0).integer_decode(), (1 << 10, 4, 1));
+ assert_eq!(crate::num::ldexp_f16(1.0, 14).integer_decode(), (1 << 10, 4, 1));
assert_eq!(0f16.integer_decode(), (0, -25, 1));
assert_eq!((-0f16).integer_decode(), (0, -25, -1));
assert_eq!(f16::INFINITY.integer_decode(), (1 << 10, 6, 1));
@@ -23,8 +24,7 @@ fn test_f16_integer_decode() {
fn test_f32_integer_decode() {
assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1));
assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1));
- // Set 2^100 directly instead of using powf, because it doesn't guarantee precision
- assert_eq!(1.2676506e30_f32.integer_decode(), (8388608, 77, 1));
+ assert_eq!(ldexp_f32(1.0, 100).integer_decode(), (8388608, 77, 1));
assert_eq!(0f32.integer_decode(), (0, -150, 1));
assert_eq!((-0f32).integer_decode(), (0, -150, -1));
assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1));
@@ -40,8 +40,7 @@ fn test_f32_integer_decode() {
fn test_f64_integer_decode() {
assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1));
assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1));
- // Set 2^100 directly instead of using powf, because it doesn't guarantee precision
- assert_eq!(1.2676506002282294e30_f64.integer_decode(), (4503599627370496, 48, 1));
+ assert_eq!(ldexp_f64(1.0, 100).integer_decode(), (4503599627370496, 48, 1));
assert_eq!(0f64.integer_decode(), (0, -1075, 1));
assert_eq!((-0f64).integer_decode(), (0, -1075, -1));
assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1));
diff --git a/library/coretests/tests/num/flt2dec/estimator.rs b/library/coretests/tests/num/flt2dec/estimator.rs
index da203b5..f532826 100644
--- a/library/coretests/tests/num/flt2dec/estimator.rs
+++ b/library/coretests/tests/num/flt2dec/estimator.rs
@@ -1,5 +1,7 @@
use core::num::flt2dec::estimator::*;
+use crate::num::ldexp_f64;
+
#[test]
fn test_estimate_scaling_factor() {
macro_rules! assert_almost_eq {
@@ -56,7 +58,7 @@ macro_rules! assert_almost_eq {
let step = if cfg!(miri) { 37 } else { 1 };
for i in (-1074..972).step_by(step) {
- let expected = super::ldexp_f64(1.0, i).log10().ceil();
+ let expected = ldexp_f64(1.0, i).log10().ceil();
assert_almost_eq!(estimate_scaling_factor(1, i as i16), expected as i16);
}
}
diff --git a/library/coretests/tests/num/flt2dec/mod.rs b/library/coretests/tests/num/flt2dec/mod.rs
index ce36db3..4e73bd1 100644
--- a/library/coretests/tests/num/flt2dec/mod.rs
+++ b/library/coretests/tests/num/flt2dec/mod.rs
@@ -6,6 +6,8 @@
use std::mem::MaybeUninit;
use std::{fmt, str};
+use crate::num::{ldexp_f32, ldexp_f64};
+
mod estimator;
mod strategy {
mod dragon;
@@ -75,24 +77,6 @@ macro_rules! try_fixed {
})
}
-#[cfg(target_has_reliable_f16)]
-fn ldexp_f16(a: f16, b: i32) -> f16 {
- ldexp_f64(a as f64, b) as f16
-}
-
-fn ldexp_f32(a: f32, b: i32) -> f32 {
- ldexp_f64(a as f64, b) as f32
-}
-
-fn ldexp_f64(a: f64, b: i32) -> f64 {
- unsafe extern "C" {
- fn ldexp(x: f64, n: i32) -> f64;
- }
- // SAFETY: assuming a correct `ldexp` has been supplied, the given arguments cannot possibly
- // cause undefined behavior
- unsafe { ldexp(a, b) }
-}
-
fn check_exact<F, T>(mut f: F, v: T, vstr: &str, expected: &[u8], expectedk: i16)
where
T: DecodableFloat,
@@ -268,7 +252,7 @@ pub fn f16_shortest_sanity_test<F>(mut f: F)
// 10^2 * 0.31984375
// 10^2 * 0.32
// 10^2 * 0.3203125
- check_shortest!(f(ldexp_f16(1.0, 5)) => b"32", 2);
+ check_shortest!(f(crate::num::ldexp_f16(1.0, 5)) => b"32", 2);
// 10^5 * 0.65472
// 10^5 * 0.65504
@@ -283,7 +267,7 @@ pub fn f16_shortest_sanity_test<F>(mut f: F)
// 10^-9 * 0
// 10^-9 * 0.59604644775390625
// 10^-8 * 0.11920928955078125
- let minf16 = ldexp_f16(1.0, -24);
+ let minf16 = crate::num::ldexp_f16(1.0, -24);
check_shortest!(f(minf16) => b"6", -7);
}
@@ -292,7 +276,7 @@ pub fn f16_exact_sanity_test<F>(mut f: F)
where
F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16),
{
- let minf16 = ldexp_f16(1.0, -24);
+ let minf16 = crate::num::ldexp_f16(1.0, -24);
check_exact!(f(0.1f16) => b"999755859375 ", -1);
check_exact!(f(0.5f16) => b"5 ", 0);
@@ -642,7 +626,7 @@ fn to_string<T, F>(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String
assert_eq!(to_string(f, f16::MAX, Minus, 1), "65500.0");
assert_eq!(to_string(f, f16::MAX, Minus, 8), "65500.00000000");
- let minf16 = ldexp_f16(1.0, -24);
+ let minf16 = crate::num::ldexp_f16(1.0, -24);
assert_eq!(to_string(f, minf16, Minus, 0), "0.00000006");
assert_eq!(to_string(f, minf16, Minus, 8), "0.00000006");
assert_eq!(to_string(f, minf16, Minus, 9), "0.000000060");
@@ -766,7 +750,7 @@ fn to_string<T, F>(f: &mut F, v: T, sign: Sign, exp_bounds: (i16, i16), upper: b
assert_eq!(to_string(f, f16::MAX, Minus, (-4, 4), false), "6.55e4");
assert_eq!(to_string(f, f16::MAX, Minus, (-5, 5), false), "65500");
- let minf16 = ldexp_f16(1.0, -24);
+ let minf16 = crate::num::ldexp_f16(1.0, -24);
assert_eq!(to_string(f, minf16, Minus, (-2, 2), false), "6e-8");
assert_eq!(to_string(f, minf16, Minus, (-7, 7), false), "6e-8");
assert_eq!(to_string(f, minf16, Minus, (-8, 8), false), "0.00000006");
@@ -922,7 +906,7 @@ fn to_string<T, F>(f: &mut F, v: T, sign: Sign, ndigits: usize, upper: bool) ->
assert_eq!(to_string(f, f16::MAX, Minus, 6, false), "6.55040e4");
assert_eq!(to_string(f, f16::MAX, Minus, 16, false), "6.550400000000000e4");
- let minf16 = ldexp_f16(1.0, -24);
+ let minf16 = crate::num::ldexp_f16(1.0, -24);
assert_eq!(to_string(f, minf16, Minus, 1, false), "6e-8");
assert_eq!(to_string(f, minf16, Minus, 2, false), "6.0e-8");
assert_eq!(to_string(f, minf16, Minus, 4, false), "5.960e-8");
@@ -1229,7 +1213,7 @@ fn to_string<T, F>(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String
#[cfg(target_has_reliable_f16)]
{
- let minf16 = ldexp_f16(1.0, -24);
+ let minf16 = crate::num::ldexp_f16(1.0, -24);
assert_eq!(to_string(f, minf16, Minus, 0), "0");
assert_eq!(to_string(f, minf16, Minus, 1), "0.0");
assert_eq!(to_string(f, minf16, Minus, 2), "0.00");
diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs
index f340926..54e54f7 100644
--- a/library/coretests/tests/num/mod.rs
+++ b/library/coretests/tests/num/mod.rs
@@ -54,6 +54,27 @@ macro_rules! assume_usize_width {
}
}
+/// Return `a * 2^b`.
+#[cfg(target_has_reliable_f16)]
+fn ldexp_f16(a: f16, b: i32) -> f16 {
+ ldexp_f64(a as f64, b) as f16
+}
+
+/// Return `a * 2^b`.
+fn ldexp_f32(a: f32, b: i32) -> f32 {
+ ldexp_f64(a as f64, b) as f32
+}
+
+/// Return `a * 2^b`.
+fn ldexp_f64(a: f64, b: i32) -> f64 {
+ unsafe extern "C" {
+ fn ldexp(x: f64, n: i32) -> f64;
+ }
+ // SAFETY: assuming a correct `ldexp` has been supplied, the given arguments cannot possibly
+ // cause undefined behavior
+ unsafe { ldexp(a, b) }
+}
+
/// Helper function for testing numeric operations
pub fn test_num<T>(ten: T, two: T)
where
diff --git a/library/coretests/tests/panic/location.rs b/library/coretests/tests/panic/location.rs
index 5ce0b06..910001b 100644
--- a/library/coretests/tests/panic/location.rs
+++ b/library/coretests/tests/panic/location.rs
@@ -3,6 +3,23 @@
// Note: Some of the following tests depend on the source location,
// so please be careful when editing this file.
+mod file_a;
+mod file_b;
+mod file_c;
+
+// A small shuffled set of locations for testing, along with their true order.
+const LOCATIONS: [(usize, &'static Location<'_>); 9] = [
+ (7, file_c::two()),
+ (0, file_a::one()),
+ (3, file_b::one()),
+ (5, file_b::three()),
+ (8, file_c::three()),
+ (6, file_c::one()),
+ (2, file_a::three()),
+ (4, file_b::two()),
+ (1, file_a::two()),
+];
+
#[test]
fn location_const_caller() {
const _CALLER_REFERENCE: &Location<'static> = Location::caller();
@@ -20,7 +37,7 @@ fn location_const_file() {
fn location_const_line() {
const CALLER: &Location<'static> = Location::caller();
const LINE: u32 = CALLER.line();
- assert_eq!(LINE, 21);
+ assert_eq!(LINE, 38);
}
#[test]
@@ -34,6 +51,28 @@ fn location_const_column() {
fn location_debug() {
let f = format!("{:?}", Location::caller());
assert!(f.contains(&format!("{:?}", file!())));
- assert!(f.contains("35"));
+ assert!(f.contains("52"));
assert!(f.contains("29"));
}
+
+#[test]
+fn location_eq() {
+ for (i, a) in LOCATIONS {
+ for (j, b) in LOCATIONS {
+ if i == j {
+ assert_eq!(a, b);
+ } else {
+ assert_ne!(a, b);
+ }
+ }
+ }
+}
+
+#[test]
+fn location_ord() {
+ let mut locations = LOCATIONS.clone();
+ locations.sort_by_key(|(_o, l)| **l);
+ for (correct, (order, _l)) in locations.iter().enumerate() {
+ assert_eq!(correct, *order);
+ }
+}
diff --git a/library/coretests/tests/panic/location/file_a.rs b/library/coretests/tests/panic/location/file_a.rs
new file mode 100644
index 0000000..1ceb225
--- /dev/null
+++ b/library/coretests/tests/panic/location/file_a.rs
@@ -0,0 +1,15 @@
+use core::panic::Location;
+
+// Used for test super::location_{ord, eq}. Must be in a dedicated file.
+
+pub const fn one() -> &'static Location<'static> {
+ Location::caller()
+}
+
+pub const fn two() -> &'static Location<'static> {
+ Location::caller()
+}
+
+pub const fn three() -> &'static Location<'static> {
+ Location::caller()
+}
diff --git a/library/coretests/tests/panic/location/file_b.rs b/library/coretests/tests/panic/location/file_b.rs
new file mode 100644
index 0000000..1ceb225
--- /dev/null
+++ b/library/coretests/tests/panic/location/file_b.rs
@@ -0,0 +1,15 @@
+use core::panic::Location;
+
+// Used for test super::location_{ord, eq}. Must be in a dedicated file.
+
+pub const fn one() -> &'static Location<'static> {
+ Location::caller()
+}
+
+pub const fn two() -> &'static Location<'static> {
+ Location::caller()
+}
+
+pub const fn three() -> &'static Location<'static> {
+ Location::caller()
+}
diff --git a/library/coretests/tests/panic/location/file_c.rs b/library/coretests/tests/panic/location/file_c.rs
new file mode 100644
index 0000000..2ac416c
--- /dev/null
+++ b/library/coretests/tests/panic/location/file_c.rs
@@ -0,0 +1,11 @@
+// Used for test super::location_{ord, eq}. Must be in a dedicated file.
+
+// This is used for testing column ordering of Location, hence this ugly one-liner.
+// We must fmt skip the entire containing module or else tidy will still complain.
+#[rustfmt::skip]
+mod no_fmt {
+ use core::panic::Location;
+ pub const fn one() -> &'static Location<'static> { Location::caller() } pub const fn two() -> &'static Location<'static> { Location::caller() } pub const fn three() -> &'static Location<'static> { Location::caller() }
+}
+
+pub use no_fmt::*;
diff --git a/library/coretests/tests/slice.rs b/library/coretests/tests/slice.rs
index d17e681..992f24c 100644
--- a/library/coretests/tests/slice.rs
+++ b/library/coretests/tests/slice.rs
@@ -612,190 +612,6 @@ fn test_chunks_exact_mut_zip() {
}
#[test]
-fn test_array_chunks_infer() {
- let v: &[i32] = &[0, 1, 2, 3, 4, -4];
- let c = v.array_chunks();
- for &[a, b, c] in c {
- assert_eq!(a + b + c, 3);
- }
-
- let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
- let total = v2.array_chunks().map(|&[a, b]| a * b).sum::<i32>();
- assert_eq!(total, 2 * 3 + 4 * 5);
-}
-
-#[test]
-fn test_array_chunks_count() {
- let v: &[i32] = &[0, 1, 2, 3, 4, 5];
- let c = v.array_chunks::<3>();
- assert_eq!(c.count(), 2);
-
- let v2: &[i32] = &[0, 1, 2, 3, 4];
- let c2 = v2.array_chunks::<2>();
- assert_eq!(c2.count(), 2);
-
- let v3: &[i32] = &[];
- let c3 = v3.array_chunks::<2>();
- assert_eq!(c3.count(), 0);
-}
-
-#[test]
-fn test_array_chunks_nth() {
- let v: &[i32] = &[0, 1, 2, 3, 4, 5];
- let mut c = v.array_chunks::<2>();
- assert_eq!(c.nth(1).unwrap(), &[2, 3]);
- assert_eq!(c.next().unwrap(), &[4, 5]);
-
- let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
- let mut c2 = v2.array_chunks::<3>();
- assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
- assert_eq!(c2.next(), None);
-}
-
-#[test]
-fn test_array_chunks_nth_back() {
- let v: &[i32] = &[0, 1, 2, 3, 4, 5];
- let mut c = v.array_chunks::<2>();
- assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
- assert_eq!(c.next().unwrap(), &[0, 1]);
- assert_eq!(c.next(), None);
-
- let v2: &[i32] = &[0, 1, 2, 3, 4];
- let mut c2 = v2.array_chunks::<3>();
- assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]);
- assert_eq!(c2.next(), None);
- assert_eq!(c2.next_back(), None);
-
- let v3: &[i32] = &[0, 1, 2, 3, 4];
- let mut c3 = v3.array_chunks::<10>();
- assert_eq!(c3.nth_back(0), None);
-}
-
-#[test]
-fn test_array_chunks_last() {
- let v: &[i32] = &[0, 1, 2, 3, 4, 5];
- let c = v.array_chunks::<2>();
- assert_eq!(c.last().unwrap(), &[4, 5]);
-
- let v2: &[i32] = &[0, 1, 2, 3, 4];
- let c2 = v2.array_chunks::<2>();
- assert_eq!(c2.last().unwrap(), &[2, 3]);
-}
-
-#[test]
-fn test_array_chunks_remainder() {
- let v: &[i32] = &[0, 1, 2, 3, 4];
- let c = v.array_chunks::<2>();
- assert_eq!(c.remainder(), &[4]);
-}
-
-#[test]
-fn test_array_chunks_zip() {
- let v1: &[i32] = &[0, 1, 2, 3, 4];
- let v2: &[i32] = &[6, 7, 8, 9, 10];
-
- let res = v1
- .array_chunks::<2>()
- .zip(v2.array_chunks::<2>())
- .map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
- .collect::<Vec<_>>();
- assert_eq!(res, vec![14, 22]);
-}
-
-#[test]
-fn test_array_chunks_mut_infer() {
- let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
- for a in v.array_chunks_mut() {
- let sum = a.iter().sum::<i32>();
- *a = [sum; 3];
- }
- assert_eq!(v, &[3, 3, 3, 12, 12, 12, 6]);
-
- let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
- v2.array_chunks_mut().for_each(|[a, b]| core::mem::swap(a, b));
- assert_eq!(v2, &[1, 0, 3, 2, 5, 4, 6]);
-}
-
-#[test]
-fn test_array_chunks_mut_count() {
- let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
- let c = v.array_chunks_mut::<3>();
- assert_eq!(c.count(), 2);
-
- let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
- let c2 = v2.array_chunks_mut::<2>();
- assert_eq!(c2.count(), 2);
-
- let v3: &mut [i32] = &mut [];
- let c3 = v3.array_chunks_mut::<2>();
- assert_eq!(c3.count(), 0);
-}
-
-#[test]
-fn test_array_chunks_mut_nth() {
- let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
- let mut c = v.array_chunks_mut::<2>();
- assert_eq!(c.nth(1).unwrap(), &[2, 3]);
- assert_eq!(c.next().unwrap(), &[4, 5]);
-
- let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
- let mut c2 = v2.array_chunks_mut::<3>();
- assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
- assert_eq!(c2.next(), None);
-}
-
-#[test]
-fn test_array_chunks_mut_nth_back() {
- let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
- let mut c = v.array_chunks_mut::<2>();
- assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
- assert_eq!(c.next().unwrap(), &[0, 1]);
- assert_eq!(c.next(), None);
-
- let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
- let mut c2 = v2.array_chunks_mut::<3>();
- assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]);
- assert_eq!(c2.next(), None);
- assert_eq!(c2.next_back(), None);
-
- let v3: &mut [i32] = &mut [0, 1, 2, 3, 4];
- let mut c3 = v3.array_chunks_mut::<10>();
- assert_eq!(c3.nth_back(0), None);
-}
-
-#[test]
-fn test_array_chunks_mut_last() {
- let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
- let c = v.array_chunks_mut::<2>();
- assert_eq!(c.last().unwrap(), &[4, 5]);
-
- let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
- let c2 = v2.array_chunks_mut::<2>();
- assert_eq!(c2.last().unwrap(), &[2, 3]);
-}
-
-#[test]
-fn test_array_chunks_mut_remainder() {
- let v: &mut [i32] = &mut [0, 1, 2, 3, 4];
- let c = v.array_chunks_mut::<2>();
- assert_eq!(c.into_remainder(), &[4]);
-}
-
-#[test]
-fn test_array_chunks_mut_zip() {
- let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
- let v2: &[i32] = &[6, 7, 8, 9, 10];
-
- for (a, b) in v1.array_chunks_mut::<2>().zip(v2.array_chunks::<2>()) {
- let sum = b.iter().sum::<i32>();
- for v in a {
- *v += sum;
- }
- }
- assert_eq!(v1, [13, 14, 19, 20, 4]);
-}
-
-#[test]
fn test_array_windows_infer() {
let v: &[i32] = &[0, 1, 0, 1];
assert_eq!(v.array_windows::<2>().count(), 3);
diff --git a/library/rustc-std-workspace-alloc/Cargo.toml b/library/rustc-std-workspace-alloc/Cargo.toml
index 5a17780..a5b5105 100644
--- a/library/rustc-std-workspace-alloc/Cargo.toml
+++ b/library/rustc-std-workspace-alloc/Cargo.toml
@@ -9,6 +9,9 @@
[lib]
path = "lib.rs"
+test = false
+bench = false
+doc = false
[dependencies]
alloc = { path = "../alloc" }
diff --git a/library/rustc-std-workspace-core/Cargo.toml b/library/rustc-std-workspace-core/Cargo.toml
index 1ddc112..d68965c 100644
--- a/library/rustc-std-workspace-core/Cargo.toml
+++ b/library/rustc-std-workspace-core/Cargo.toml
@@ -11,6 +11,9 @@
[lib]
path = "lib.rs"
+test = false
+bench = false
+doc = false
[dependencies]
core = { path = "../core", public = true }
diff --git a/library/rustc-std-workspace-std/Cargo.toml b/library/rustc-std-workspace-std/Cargo.toml
index f70994e..6079dc8 100644
--- a/library/rustc-std-workspace-std/Cargo.toml
+++ b/library/rustc-std-workspace-std/Cargo.toml
@@ -9,6 +9,9 @@
[lib]
path = "lib.rs"
+test = false
+bench = false
+doc = false
[dependencies]
std = { path = "../std" }
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index ba1e1f5..29ab9be 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -63,10 +63,10 @@
rand_xorshift = "0.4.0"
[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
-dlmalloc = { version = "0.2.4", features = ['rustc-dep-of-std'] }
+dlmalloc = { version = "0.2.10", features = ['rustc-dep-of-std'] }
[target.x86_64-fortanix-unknown-sgx.dependencies]
-fortanix-sgx-abi = { version = "0.5.0", features = [
+fortanix-sgx-abi = { version = "0.6.1", features = [
'rustc-dep-of-std',
], public = true }
@@ -97,9 +97,7 @@
panic-unwind = ["dep:panic_unwind"]
compiler-builtins-c = ["alloc/compiler-builtins-c"]
compiler-builtins-mem = ["alloc/compiler-builtins-mem"]
-compiler-builtins-no-asm = ["alloc/compiler-builtins-no-asm"]
compiler-builtins-no-f16-f128 = ["alloc/compiler-builtins-no-f16-f128"]
-compiler-builtins-mangled-names = ["alloc/compiler-builtins-mangled-names"]
llvm-libunwind = ["unwind/llvm-libunwind"]
system-llvm-libunwind = ["unwind/system-llvm-libunwind"]
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 6d7d576..9f17ff7 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -617,7 +617,7 @@ fn description(&self) -> &str {
/// # Unix
///
/// - Returns the value of the 'HOME' environment variable if it is set
-/// (including to an empty string).
+/// (and not an empty string).
/// - Otherwise, it tries to determine the home directory by invoking the `getpwuid_r` function
/// using the UID of the current user. An empty home directory field returned from the
/// `getpwuid_r` function is considered to be a valid value.
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 323742a..77301d7 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -324,13 +324,13 @@
//
// Library features (core):
// tidy-alphabetical-start
-#![feature(array_chunks)]
#![feature(bstr)]
#![feature(bstr_internals)]
#![feature(char_internals)]
#![feature(clone_to_uninit)]
#![feature(core_intrinsics)]
#![feature(core_io_borrowed_buf)]
+#![feature(drop_guard)]
#![feature(duration_constants)]
#![feature(error_generic_member_access)]
#![feature(error_iter)]
diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs
index e67b4f6..6ef3bf2 100644
--- a/library/std/src/sync/mod.rs
+++ b/library/std/src/sync/mod.rs
@@ -225,6 +225,8 @@
pub mod mpmc;
pub mod mpsc;
+#[unstable(feature = "sync_nonpoison", issue = "134645")]
+pub mod nonpoison;
#[unstable(feature = "sync_poison_mod", issue = "134646")]
pub mod poison;
diff --git a/library/std/src/sync/nonpoison.rs b/library/std/src/sync/nonpoison.rs
new file mode 100644
index 0000000..2bbf226
--- /dev/null
+++ b/library/std/src/sync/nonpoison.rs
@@ -0,0 +1,37 @@
+//! Non-poisoning synchronous locks.
+//!
+//! The difference from the locks in the [`poison`] module is that the locks in this module will not
+//! become poisoned when a thread panics while holding a guard.
+//!
+//! [`poison`]: super::poison
+
+use crate::fmt;
+
+/// A type alias for the result of a nonblocking locking method.
+#[unstable(feature = "sync_nonpoison", issue = "134645")]
+pub type TryLockResult<Guard> = Result<Guard, WouldBlock>;
+
+/// A lock could not be acquired at this time because the operation would otherwise block.
+#[unstable(feature = "sync_nonpoison", issue = "134645")]
+pub struct WouldBlock;
+
+#[unstable(feature = "sync_nonpoison", issue = "134645")]
+impl fmt::Debug for WouldBlock {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "WouldBlock".fmt(f)
+ }
+}
+
+#[unstable(feature = "sync_nonpoison", issue = "134645")]
+impl fmt::Display for WouldBlock {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "try_lock failed because the operation would block".fmt(f)
+ }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+pub use self::mutex::MappedMutexGuard;
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+pub use self::mutex::{Mutex, MutexGuard};
+
+mod mutex;
diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs
new file mode 100644
index 0000000..b6861c7
--- /dev/null
+++ b/library/std/src/sync/nonpoison/mutex.rs
@@ -0,0 +1,611 @@
+use crate::cell::UnsafeCell;
+use crate::fmt;
+use crate::marker::PhantomData;
+use crate::mem::{self, ManuallyDrop};
+use crate::ops::{Deref, DerefMut};
+use crate::ptr::NonNull;
+use crate::sync::nonpoison::{TryLockResult, WouldBlock};
+use crate::sys::sync as sys;
+
+/// A mutual exclusion primitive useful for protecting shared data that does not keep track of
+/// lock poisoning.
+///
+/// For more information about mutexes, check out the documentation for the poisoning variant of
+/// this lock at [`poison::Mutex`].
+///
+/// [`poison::Mutex`]: crate::sync::poison::Mutex
+///
+/// # Examples
+///
+/// Note that this `Mutex` does **not** propagate threads that panic while holding the lock via
+/// poisoning. If you need this functionality, see [`poison::Mutex`].
+///
+/// ```
+/// #![feature(nonpoison_mutex)]
+///
+/// use std::thread;
+/// use std::sync::{Arc, nonpoison::Mutex};
+///
+/// let mutex = Arc::new(Mutex::new(0u32));
+/// let mut handles = Vec::new();
+///
+/// for n in 0..10 {
+/// let m = Arc::clone(&mutex);
+/// let handle = thread::spawn(move || {
+/// let mut guard = m.lock();
+/// *guard += 1;
+/// panic!("panic from thread {n} {guard}")
+/// });
+/// handles.push(handle);
+/// }
+///
+/// for h in handles {
+/// let _ = h.join();
+/// }
+///
+/// println!("Finished, locked {} times", mutex.lock());
+/// ```
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "NonPoisonMutex")]
+pub struct Mutex<T: ?Sized> {
+ inner: sys::Mutex,
+ data: UnsafeCell<T>,
+}
+
+/// `T` must be `Send` for a [`Mutex`] to be `Send` because it is possible to acquire
+/// the owned `T` from the `Mutex` via [`into_inner`].
+///
+/// [`into_inner`]: Mutex::into_inner
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
+
+/// `T` must be `Send` for [`Mutex`] to be `Sync`.
+/// This ensures that the protected data can be accessed safely from multiple threads
+/// without causing data races or other unsafe behavior.
+///
+/// [`Mutex<T>`] provides mutable access to `T` to one thread at a time. However, it's essential
+/// for `T` to be `Send` because it's not safe for non-`Send` structures to be accessed in
+/// this manner. For instance, consider [`Rc`], a non-atomic reference counted smart pointer,
+/// which is not `Send`. With `Rc`, we can have multiple copies pointing to the same heap
+/// allocation with a non-atomic reference count. If we were to use `Mutex<Rc<_>>`, it would
+/// only protect one instance of `Rc` from shared access, leaving other copies vulnerable
+/// to potential data races.
+///
+/// Also note that it is not necessary for `T` to be `Sync` as `&T` is only made available
+/// to one thread at a time if `T` is not `Sync`.
+///
+/// [`Rc`]: crate::rc::Rc
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
+
+/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
+/// dropped (falls out of scope), the lock will be unlocked.
+///
+/// The data protected by the mutex can be accessed through this guard via its
+/// [`Deref`] and [`DerefMut`] implementations.
+///
+/// This structure is created by the [`lock`] and [`try_lock`] methods on
+/// [`Mutex`].
+///
+/// [`lock`]: Mutex::lock
+/// [`try_lock`]: Mutex::try_lock
+#[must_use = "if unused the Mutex will immediately unlock"]
+#[must_not_suspend = "holding a MutexGuard across suspend \
+ points can cause deadlocks, delays, \
+ and cause Futures to not implement `Send`"]
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+#[clippy::has_significant_drop]
+#[cfg_attr(not(test), rustc_diagnostic_item = "NonPoisonMutexGuard")]
+pub struct MutexGuard<'a, T: ?Sized + 'a> {
+ lock: &'a Mutex<T>,
+}
+
+/// A [`MutexGuard`] is not `Send` to maximize platform portablity.
+///
+/// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to
+/// release mutex locks on the same thread they were acquired.
+/// For this reason, [`MutexGuard`] must not implement `Send` to prevent it being dropped from
+/// another thread.
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
+
+/// `T` must be `Sync` for a [`MutexGuard<T>`] to be `Sync`
+/// because it is possible to get a `&T` from `&MutexGuard` (via `Deref`).
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}
+
+// FIXME(nonpoison_condvar): Use this link instead: [`Condvar`]: crate::sync::nonpoison::Condvar
+/// An RAII mutex guard returned by `MutexGuard::map`, which can point to a
+/// subfield of the protected data. When this structure is dropped (falls out
+/// of scope), the lock will be unlocked.
+///
+/// The main difference between `MappedMutexGuard` and [`MutexGuard`] is that the
+/// former cannot be used with [`Condvar`], since that could introduce soundness issues if the
+/// locked object is modified by another thread while the `Mutex` is unlocked.
+///
+/// The data protected by the mutex can be accessed through this guard via its
+/// [`Deref`] and [`DerefMut`] implementations.
+///
+/// This structure is created by the [`map`] and [`filter_map`] methods on
+/// [`MutexGuard`].
+///
+/// [`map`]: MutexGuard::map
+/// [`filter_map`]: MutexGuard::filter_map
+/// [`Condvar`]: crate::sync::Condvar
+#[must_use = "if unused the Mutex will immediately unlock"]
+#[must_not_suspend = "holding a MappedMutexGuard across suspend \
+ points can cause deadlocks, delays, \
+ and cause Futures to not implement `Send`"]
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+#[clippy::has_significant_drop]
+pub struct MappedMutexGuard<'a, T: ?Sized + 'a> {
+ // NB: we use a pointer instead of `&'a mut T` to avoid `noalias` violations, because a
+ // `MappedMutexGuard` argument doesn't hold uniqueness for its whole scope, only until it drops.
+ // `NonNull` is covariant over `T`, so we add a `PhantomData<&'a mut T>` field
+ // below for the correct variance over `T` (invariance).
+ data: NonNull<T>,
+ inner: &'a sys::Mutex,
+ _variance: PhantomData<&'a mut T>,
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized> !Send for MappedMutexGuard<'_, T> {}
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+unsafe impl<T: ?Sized + Sync> Sync for MappedMutexGuard<'_, T> {}
+
+impl<T> Mutex<T> {
+ /// Creates a new mutex in an unlocked state ready for use.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonpoison_mutex)]
+ ///
+ /// use std::sync::nonpoison::Mutex;
+ ///
+ /// let mutex = Mutex::new(0);
+ /// ```
+ #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+ #[inline]
+ pub const fn new(t: T) -> Mutex<T> {
+ Mutex { inner: sys::Mutex::new(), data: UnsafeCell::new(t) }
+ }
+
+ /// Returns the contained value by cloning it.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonpoison_mutex)]
+ /// #![feature(lock_value_accessors)]
+ ///
+ /// use std::sync::nonpoison::Mutex;
+ ///
+ /// let mut mutex = Mutex::new(7);
+ ///
+ /// assert_eq!(mutex.get_cloned(), 7);
+ /// ```
+ #[unstable(feature = "lock_value_accessors", issue = "133407")]
+ // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+ pub fn get_cloned(&self) -> T
+ where
+ T: Clone,
+ {
+ self.lock().clone()
+ }
+
+ /// Sets the contained value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonpoison_mutex)]
+ /// #![feature(lock_value_accessors)]
+ ///
+ /// use std::sync::nonpoison::Mutex;
+ ///
+ /// let mut mutex = Mutex::new(7);
+ ///
+ /// assert_eq!(mutex.get_cloned(), 7);
+ /// mutex.set(11);
+ /// assert_eq!(mutex.get_cloned(), 11);
+ /// ```
+ #[unstable(feature = "lock_value_accessors", issue = "133407")]
+ // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+ pub fn set(&self, value: T) {
+ if mem::needs_drop::<T>() {
+ // If the contained value has a non-trivial destructor, we
+ // call that destructor after the lock has been released.
+ drop(self.replace(value))
+ } else {
+ *self.lock() = value;
+ }
+ }
+
+ /// Replaces the contained value with `value`, and returns the old contained value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonpoison_mutex)]
+ /// #![feature(lock_value_accessors)]
+ ///
+ /// use std::sync::nonpoison::Mutex;
+ ///
+ /// let mut mutex = Mutex::new(7);
+ ///
+ /// assert_eq!(mutex.replace(11), 7);
+ /// assert_eq!(mutex.get_cloned(), 11);
+ /// ```
+ #[unstable(feature = "lock_value_accessors", issue = "133407")]
+ // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+ pub fn replace(&self, value: T) -> T {
+ let mut guard = self.lock();
+ mem::replace(&mut *guard, value)
+ }
+}
+
+impl<T: ?Sized> Mutex<T> {
+ /// Acquires a mutex, blocking the current thread until it is able to do so.
+ ///
+ /// This function will block the local thread until it is available to acquire
+ /// the mutex. Upon returning, the thread is the only thread with the lock
+ /// held. An RAII guard is returned to allow scoped unlock of the lock. When
+ /// the guard goes out of scope, the mutex will be unlocked.
+ ///
+ /// The exact behavior on locking a mutex in the thread which already holds
+ /// the lock is left unspecified. However, this function will not return on
+ /// the second call (it might panic or deadlock, for example).
+ ///
+ /// # Panics
+ ///
+ /// This function might panic when called if the lock is already held by
+ /// the current thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonpoison_mutex)]
+ ///
+ /// use std::sync::{Arc, nonpoison::Mutex};
+ /// use std::thread;
+ ///
+ /// let mutex = Arc::new(Mutex::new(0));
+ /// let c_mutex = Arc::clone(&mutex);
+ ///
+ /// thread::spawn(move || {
+ /// *c_mutex.lock() = 10;
+ /// }).join().expect("thread::spawn failed");
+ /// assert_eq!(*mutex.lock(), 10);
+ /// ```
+ #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+ pub fn lock(&self) -> MutexGuard<'_, T> {
+ unsafe {
+ self.inner.lock();
+ MutexGuard::new(self)
+ }
+ }
+
+ /// Attempts to acquire this lock.
+ ///
+ /// This function does not block. If the lock could not be acquired at this time, then
+ /// [`WouldBlock`] is returned. Otherwise, an RAII guard is returned.
+ ///
+ /// The lock will be unlocked when the guard is dropped.
+ ///
+ /// # Errors
+ ///
+ /// If the mutex could not be acquired because it is already locked, then this call will return
+ /// the [`WouldBlock`] error.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex};
+ /// use std::thread;
+ ///
+ /// let mutex = Arc::new(Mutex::new(0));
+ /// let c_mutex = Arc::clone(&mutex);
+ ///
+ /// thread::spawn(move || {
+ /// let mut lock = c_mutex.try_lock();
+ /// if let Ok(ref mut mutex) = lock {
+ /// **mutex = 10;
+ /// } else {
+ /// println!("try_lock failed");
+ /// }
+ /// }).join().expect("thread::spawn failed");
+ /// assert_eq!(*mutex.lock().unwrap(), 10);
+ /// ```
+ #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+ pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> {
+ unsafe { if self.inner.try_lock() { Ok(MutexGuard::new(self)) } else { Err(WouldBlock) } }
+ }
+
+ /// Consumes this mutex, returning the underlying data.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonpoison_mutex)]
+ ///
+ /// use std::sync::nonpoison::Mutex;
+ ///
+ /// let mutex = Mutex::new(0);
+ /// assert_eq!(mutex.into_inner(), 0);
+ /// ```
+ #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+ pub fn into_inner(self) -> T
+ where
+ T: Sized,
+ {
+ self.data.into_inner()
+ }
+
+ /// Returns a mutable reference to the underlying data.
+ ///
+ /// Since this call borrows the `Mutex` mutably, no actual locking needs to
+ /// take place -- the mutable borrow statically guarantees no locks exist.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonpoison_mutex)]
+ ///
+ /// use std::sync::nonpoison::Mutex;
+ ///
+ /// let mut mutex = Mutex::new(0);
+ /// *mutex.get_mut() = 10;
+ /// assert_eq!(*mutex.lock(), 10);
+ /// ```
+ #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+ pub fn get_mut(&mut self) -> &mut T {
+ self.data.get_mut()
+ }
+
+ /// Returns a raw pointer to the underlying data.
+ ///
+ /// The returned pointer is always non-null and properly aligned, but it is
+ /// the user's responsibility to ensure that any reads and writes through it
+ /// are properly synchronized to avoid data races, and that it is not read
+ /// or written through after the mutex is dropped.
+ #[unstable(feature = "mutex_data_ptr", issue = "140368")]
+ // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+ pub fn data_ptr(&self) -> *mut T {
+ self.data.get()
+ }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T> From<T> for Mutex<T> {
+ /// Creates a new mutex in an unlocked state ready for use.
+ /// This is equivalent to [`Mutex::new`].
+ fn from(t: T) -> Self {
+ Mutex::new(t)
+ }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized + Default> Default for Mutex<T> {
+ /// Creates a `Mutex<T>`, with the `Default` value for T.
+ fn default() -> Mutex<T> {
+ Mutex::new(Default::default())
+ }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut d = f.debug_struct("Mutex");
+ match self.try_lock() {
+ Ok(guard) => {
+ d.field("data", &&*guard);
+ }
+ Err(WouldBlock) => {
+ d.field("data", &"<locked>");
+ }
+ }
+ d.finish_non_exhaustive()
+ }
+}
+
+impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {
+ unsafe fn new(lock: &'mutex Mutex<T>) -> MutexGuard<'mutex, T> {
+ return MutexGuard { lock };
+ }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized> Deref for MutexGuard<'_, T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ unsafe { &*self.lock.data.get() }
+ }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
+ fn deref_mut(&mut self) -> &mut T {
+ unsafe { &mut *self.lock.data.get() }
+ }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized> Drop for MutexGuard<'_, T> {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ self.lock.inner.unlock();
+ }
+ }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&**self, f)
+ }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ (**self).fmt(f)
+ }
+}
+
+impl<'a, T: ?Sized> MutexGuard<'a, T> {
+ /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
+ /// an enum variant.
+ ///
+ /// The `Mutex` is already locked, so this cannot fail.
+ ///
+ /// This is an associated function that needs to be used as
+ /// `MutexGuard::map(...)`. A method would interfere with methods of the
+ /// same name on the contents of the `MutexGuard` used through `Deref`.
+ #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+ // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+ pub fn map<U, F>(orig: Self, f: F) -> MappedMutexGuard<'a, U>
+ where
+ F: FnOnce(&mut T) -> &mut U,
+ U: ?Sized,
+ {
+ // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+ // was created, and have been upheld throughout `map` and/or `filter_map`.
+ // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+ // passed to it. If the closure panics, the guard will be dropped.
+ let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() }));
+ let orig = ManuallyDrop::new(orig);
+ MappedMutexGuard { data, inner: &orig.lock.inner, _variance: PhantomData }
+ }
+
+ /// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
+ /// original guard is returned as an `Err(...)` if the closure returns
+ /// `None`.
+ ///
+ /// The `Mutex` is already locked, so this cannot fail.
+ ///
+ /// This is an associated function that needs to be used as
+ /// `MutexGuard::filter_map(...)`. A method would interfere with methods of the
+ /// same name on the contents of the `MutexGuard` used through `Deref`.
+ #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+ // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+ pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
+ where
+ F: FnOnce(&mut T) -> Option<&mut U>,
+ U: ?Sized,
+ {
+ // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+ // was created, and have been upheld throughout `map` and/or `filter_map`.
+ // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+ // passed to it. If the closure panics, the guard will be dropped.
+ match f(unsafe { &mut *orig.lock.data.get() }) {
+ Some(data) => {
+ let data = NonNull::from(data);
+ let orig = ManuallyDrop::new(orig);
+ Ok(MappedMutexGuard { data, inner: &orig.lock.inner, _variance: PhantomData })
+ }
+ None => Err(orig),
+ }
+ }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Deref for MappedMutexGuard<'_, T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ unsafe { self.data.as_ref() }
+ }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> DerefMut for MappedMutexGuard<'_, T> {
+ fn deref_mut(&mut self) -> &mut T {
+ unsafe { self.data.as_mut() }
+ }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Drop for MappedMutexGuard<'_, T> {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ self.inner.unlock();
+ }
+ }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedMutexGuard<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&**self, f)
+ }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Display> fmt::Display for MappedMutexGuard<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ (**self).fmt(f)
+ }
+}
+
+impl<'a, T: ?Sized> MappedMutexGuard<'a, T> {
+ /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
+ /// an enum variant.
+ ///
+ /// The `Mutex` is already locked, so this cannot fail.
+ ///
+ /// This is an associated function that needs to be used as
+ /// `MappedMutexGuard::map(...)`. A method would interfere with methods of the
+ /// same name on the contents of the `MutexGuard` used through `Deref`.
+ #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+ // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+ pub fn map<U, F>(mut orig: Self, f: F) -> MappedMutexGuard<'a, U>
+ where
+ F: FnOnce(&mut T) -> &mut U,
+ U: ?Sized,
+ {
+ // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+ // was created, and have been upheld throughout `map` and/or `filter_map`.
+ // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+ // passed to it. If the closure panics, the guard will be dropped.
+ let data = NonNull::from(f(unsafe { orig.data.as_mut() }));
+ let orig = ManuallyDrop::new(orig);
+ MappedMutexGuard { data, inner: orig.inner, _variance: PhantomData }
+ }
+
+ /// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
+ /// original guard is returned as an `Err(...)` if the closure returns
+ /// `None`.
+ ///
+ /// The `Mutex` is already locked, so this cannot fail.
+ ///
+ /// This is an associated function that needs to be used as
+ /// `MappedMutexGuard::filter_map(...)`. A method would interfere with methods of the
+ /// same name on the contents of the `MutexGuard` used through `Deref`.
+ #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+ // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+ pub fn filter_map<U, F>(mut orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
+ where
+ F: FnOnce(&mut T) -> Option<&mut U>,
+ U: ?Sized,
+ {
+ // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+ // was created, and have been upheld throughout `map` and/or `filter_map`.
+ // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+ // passed to it. If the closure panics, the guard will be dropped.
+ match f(unsafe { orig.data.as_mut() }) {
+ Some(data) => {
+ let data = NonNull::from(data);
+ let orig = ManuallyDrop::new(orig);
+ Ok(MappedMutexGuard { data, inner: orig.inner, _variance: PhantomData })
+ }
+ None => Err(orig),
+ }
+ }
+}
diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs
index 0c05f15..b901a57 100644
--- a/library/std/src/sync/poison.rs
+++ b/library/std/src/sync/poison.rs
@@ -13,7 +13,9 @@
//! depend on the primitive. See [#Overview] below.
//!
//! For the alternative implementations that do not employ poisoning,
-//! see `std::sync::nonpoisoning`.
+//! see [`std::sync::nonpoison`].
+//!
+//! [`std::sync::nonpoison`]: crate::sync::nonpoison
//!
//! # Overview
//!
@@ -56,8 +58,6 @@
//! while it is locked exclusively (write mode). If a panic occurs in any reader,
//! then the lock will not be poisoned.
-// FIXME(sync_nonpoison) add links to sync::nonpoison to the doc comment above.
-
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::condvar::{Condvar, WaitTimeoutResult};
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
diff --git a/library/std/src/sync/poison/condvar.rs b/library/std/src/sync/poison/condvar.rs
index 7f0f3f6..0e9d423 100644
--- a/library/std/src/sync/poison/condvar.rs
+++ b/library/std/src/sync/poison/condvar.rs
@@ -13,7 +13,7 @@
#[stable(feature = "wait_timeout", since = "1.5.0")]
pub struct WaitTimeoutResult(bool);
-// FIXME(sync_nonpoison): `WaitTimeoutResult` is actually poisoning-agnostic, it seems.
+// FIXME(nonpoison_condvar): `WaitTimeoutResult` is actually poisoning-agnostic, it seems.
// Should we take advantage of this fact?
impl WaitTimeoutResult {
/// Returns `true` if the wait was known to have timed out.
diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs
index 30325be..64744f1 100644
--- a/library/std/src/sync/poison/mutex.rs
+++ b/library/std/src/sync/poison/mutex.rs
@@ -650,7 +650,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
d.field("data", &&**err.get_ref());
}
Err(TryLockError::WouldBlock) => {
- d.field("data", &format_args!("<locked>"));
+ d.field("data", &"<locked>");
}
}
d.field("poisoned", &self.poison.get());
diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs
index 884cbd4..16e3487 100644
--- a/library/std/src/sys/net/connection/uefi/mod.rs
+++ b/library/std/src/sys/net/connection/uefi/mod.rs
@@ -86,11 +86,11 @@ pub fn is_write_vectored(&self) -> bool {
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
- unsupported()
+ self.inner.peer_addr()
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- unsupported()
+ self.inner.socket_addr()
}
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
@@ -114,7 +114,7 @@ pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
}
pub fn nodelay(&self) -> io::Result<bool> {
- unsupported()
+ self.inner.nodelay()
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
@@ -122,7 +122,7 @@ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
}
pub fn ttl(&self) -> io::Result<u32> {
- unsupported()
+ self.inner.ttl()
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
@@ -140,7 +140,9 @@ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
-pub struct TcpListener(!);
+pub struct TcpListener {
+ inner: tcp::Tcp,
+}
impl TcpListener {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
@@ -148,45 +150,45 @@ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- self.0
+ unsupported()
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
- self.0
+ unsupported()
}
pub fn duplicate(&self) -> io::Result<TcpListener> {
- self.0
+ unsupported()
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
- self.0
+ unsupported()
}
pub fn ttl(&self) -> io::Result<u32> {
- self.0
+ self.inner.ttl()
}
pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
- self.0
+ unsupported()
}
pub fn only_v6(&self) -> io::Result<bool> {
- self.0
+ unsupported()
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
- self.0
+ unsupported()
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
- self.0
+ unsupported()
}
}
impl fmt::Debug for TcpListener {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0
+ todo!()
}
}
diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs
index 1152f69..aac9700 100644
--- a/library/std/src/sys/net/connection/uefi/tcp.rs
+++ b/library/std/src/sys/net/connection/uefi/tcp.rs
@@ -1,6 +1,8 @@
use super::tcp4;
use crate::io;
use crate::net::SocketAddr;
+use crate::ptr::NonNull;
+use crate::sys::{helpers, unsupported};
use crate::time::Duration;
pub(crate) enum Tcp {
@@ -31,4 +33,44 @@ pub(crate) fn read(&self, buf: &mut [u8], timeout: Option<Duration>) -> io::Resu
Self::V4(client) => client.read(buf, timeout),
}
}
+
+ pub(crate) fn ttl(&self) -> io::Result<u32> {
+ match self {
+ Self::V4(client) => client.get_mode_data().map(|x| x.time_to_live.into()),
+ }
+ }
+
+ pub(crate) fn nodelay(&self) -> io::Result<bool> {
+ match self {
+ Self::V4(client) => {
+ let temp = client.get_mode_data()?;
+ match NonNull::new(temp.control_option) {
+ Some(x) => unsafe { Ok(x.as_ref().enable_nagle.into()) },
+ None => unsupported(),
+ }
+ }
+ }
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ match self {
+ Self::V4(client) => client.get_mode_data().map(|x| {
+ SocketAddr::new(
+ helpers::ipv4_from_r_efi(x.access_point.remote_address).into(),
+ x.access_point.remote_port,
+ )
+ }),
+ }
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self {
+ Self::V4(client) => client.get_mode_data().map(|x| {
+ SocketAddr::new(
+ helpers::ipv4_from_r_efi(x.access_point.station_address).into(),
+ x.access_point.station_port,
+ )
+ }),
+ }
+ }
}
diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs
index 6342718..75862ff 100644
--- a/library/std/src/sys/net/connection/uefi/tcp4.rs
+++ b/library/std/src/sys/net/connection/uefi/tcp4.rs
@@ -67,6 +67,24 @@ pub(crate) fn configure(
if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
}
+ pub(crate) fn get_mode_data(&self) -> io::Result<tcp4::ConfigData> {
+ let mut config_data = tcp4::ConfigData::default();
+ let protocol = self.protocol.as_ptr();
+
+ let r = unsafe {
+ ((*protocol).get_mode_data)(
+ protocol,
+ crate::ptr::null_mut(),
+ &mut config_data,
+ crate::ptr::null_mut(),
+ crate::ptr::null_mut(),
+ crate::ptr::null_mut(),
+ )
+ };
+
+ if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(config_data) }
+ }
+
pub(crate) fn connect(&self, timeout: Option<Duration>) -> io::Result<()> {
let evt = unsafe { self.create_evt() }?;
let completion_token =
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs
index 9bc5a16..95fe4f9 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/pal/hermit/thread.rs
@@ -58,7 +58,11 @@ extern "C" fn thread_start(main: usize) {
}
}
- pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+ pub unsafe fn new(
+ stack: usize,
+ _name: Option<&str>,
+ p: Box<dyn FnOnce()>,
+ ) -> io::Result<Thread> {
unsafe {
Thread::new_with_coreid(stack, p, -1 /* = no specific core */)
}
diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs
index 813e1cb..0d28051 100644
--- a/library/std/src/sys/pal/itron/thread.rs
+++ b/library/std/src/sys/pal/itron/thread.rs
@@ -86,7 +86,11 @@ impl Thread {
/// # Safety
///
/// See `thread::Builder::spawn_unchecked` for safety requirements.
- pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+ pub unsafe fn new(
+ stack: usize,
+ _name: Option<&str>,
+ p: Box<dyn FnOnce()>,
+ ) -> io::Result<Thread> {
let inner = Box::new(ThreadInner {
start: UnsafeCell::new(ManuallyDrop::new(p)),
lifecycle: AtomicUsize::new(LIFECYCLE_INIT),
diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
index dea4412..5041770 100644
--- a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
@@ -267,7 +267,7 @@ pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> {
/// Usercall `insecure_time`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn insecure_time() -> Duration {
- let t = unsafe { raw::insecure_time() };
+ let t = unsafe { raw::insecure_time().0 };
Duration::new(t / 1_000_000_000, (t % 1_000_000_000) as _)
}
diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs
index 85f6dcd..a236c362 100644
--- a/library/std/src/sys/pal/sgx/thread.rs
+++ b/library/std/src/sys/pal/sgx/thread.rs
@@ -96,7 +96,11 @@ pub fn new() -> (Notifier, Waiter) {
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
- pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce() + Send>) -> io::Result<Thread> {
+ pub unsafe fn new(
+ _stack: usize,
+ _name: Option<&str>,
+ p: Box<dyn FnOnce() + Send>,
+ ) -> io::Result<Thread> {
let mut queue_lock = task_queue::lock();
unsafe { usercalls::launch_thread()? };
let (task, handle) = task_queue::Task::new(p);
diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs
index b9cdc7a..a91d956 100644
--- a/library/std/src/sys/pal/teeos/thread.rs
+++ b/library/std/src/sys/pal/teeos/thread.rs
@@ -22,7 +22,11 @@ unsafe impl Sync for Thread {}
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
- pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+ pub unsafe fn new(
+ stack: usize,
+ _name: Option<&str>,
+ p: Box<dyn FnOnce()>,
+ ) -> io::Result<Thread> {
let p = Box::into_raw(Box::new(p));
let mut native: libc::pthread_t = unsafe { mem::zeroed() };
let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() };
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index 4204816..271dc4d 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -761,3 +761,7 @@ fn drop(&mut self) {
pub(crate) const fn ipv4_to_r_efi(addr: crate::net::Ipv4Addr) -> efi::Ipv4Address {
efi::Ipv4Address { addr: addr.octets() }
}
+
+pub(crate) const fn ipv4_from_r_efi(ip: efi::Ipv4Address) -> crate::net::Ipv4Addr {
+ crate::net::Ipv4Addr::new(ip.addr[0], ip.addr[1], ip.addr[2], ip.addr[3])
+}
diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs
index e4776ec..75c3643 100644
--- a/library/std/src/sys/pal/uefi/thread.rs
+++ b/library/std/src/sys/pal/uefi/thread.rs
@@ -11,7 +11,11 @@
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
- pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+ pub unsafe fn new(
+ _stack: usize,
+ _name: Option<&str>,
+ _p: Box<dyn FnOnce()>,
+ ) -> io::Result<Thread> {
unsupported()
}
diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs
index 850bdfd..0e68313 100644
--- a/library/std/src/sys/pal/unix/os.rs
+++ b/library/std/src/sys/pal/unix/os.rs
@@ -633,7 +633,10 @@ pub fn temp_dir() -> PathBuf {
}
pub fn home_dir() -> Option<PathBuf> {
- return crate::env::var_os("HOME").or_else(|| unsafe { fallback() }).map(PathBuf::from);
+ return crate::env::var_os("HOME")
+ .filter(|s| !s.is_empty())
+ .or_else(|| unsafe { fallback() })
+ .map(PathBuf::from);
#[cfg(any(
target_os = "android",
diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs
index a3be2cd..d89100e 100644
--- a/library/std/src/sys/pal/unix/stack_overflow.rs
+++ b/library/std/src/sys/pal/unix/stack_overflow.rs
@@ -8,8 +8,8 @@ pub struct Handler {
}
impl Handler {
- pub unsafe fn new() -> Handler {
- make_handler(false)
+ pub unsafe fn new(thread_name: Option<Box<str>>) -> Handler {
+ make_handler(false, thread_name)
}
fn null() -> Handler {
@@ -72,7 +72,6 @@ mod imp {
use crate::sync::OnceLock;
use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr, AtomicUsize, Ordering};
use crate::sys::pal::unix::os;
- use crate::thread::with_current_name;
use crate::{io, mem, panic, ptr};
// Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
@@ -158,13 +157,12 @@ pub unsafe fn init() {
if !NEED_ALTSTACK.load(Ordering::Relaxed) {
// haven't set up our sigaltstack yet
NEED_ALTSTACK.store(true, Ordering::Release);
- let handler = unsafe { make_handler(true) };
+ let handler = unsafe { make_handler(true, None) };
MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);
mem::forget(handler);
if let Some(guard_page_range) = guard_page_range.take() {
- let thread_name = with_current_name(|name| name.map(Box::from));
- set_current_info(guard_page_range, thread_name);
+ set_current_info(guard_page_range, Some(Box::from("main")));
}
}
@@ -230,14 +228,13 @@ unsafe fn get_stack() -> libc::stack_t {
/// # Safety
/// Mutates the alternate signal stack
#[forbid(unsafe_op_in_unsafe_fn)]
- pub unsafe fn make_handler(main_thread: bool) -> Handler {
+ pub unsafe fn make_handler(main_thread: bool, thread_name: Option<Box<str>>) -> Handler {
if !NEED_ALTSTACK.load(Ordering::Acquire) {
return Handler::null();
}
if !main_thread {
if let Some(guard_page_range) = unsafe { current_guard() } {
- let thread_name = with_current_name(|name| name.map(Box::from));
set_current_info(guard_page_range, thread_name);
}
}
@@ -634,7 +631,10 @@ pub unsafe fn init() {}
pub unsafe fn cleanup() {}
- pub unsafe fn make_handler(_main_thread: bool) -> super::Handler {
+ pub unsafe fn make_handler(
+ _main_thread: bool,
+ _thread_name: Option<Box<str>>,
+ ) -> super::Handler {
super::Handler::null()
}
@@ -717,7 +717,10 @@ pub unsafe fn init() {
pub unsafe fn cleanup() {}
- pub unsafe fn make_handler(main_thread: bool) -> super::Handler {
+ pub unsafe fn make_handler(
+ main_thread: bool,
+ _thread_name: Option<Box<str>>,
+ ) -> super::Handler {
if !main_thread {
reserve_stack();
}
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index e4f5520..7f64401 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -22,6 +22,11 @@
#[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
+struct ThreadData {
+ name: Option<Box<str>>,
+ f: Box<dyn FnOnce()>,
+}
+
pub struct Thread {
id: libc::pthread_t,
}
@@ -34,8 +39,12 @@ unsafe impl Sync for Thread {}
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
- pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
- let p = Box::into_raw(Box::new(p));
+ pub unsafe fn new(
+ stack: usize,
+ name: Option<&str>,
+ f: Box<dyn FnOnce()>,
+ ) -> io::Result<Thread> {
+ let data = Box::into_raw(Box::new(ThreadData { name: name.map(Box::from), f }));
let mut native: libc::pthread_t = mem::zeroed();
let mut attr: mem::MaybeUninit<libc::pthread_attr_t> = mem::MaybeUninit::uninit();
assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0);
@@ -73,7 +82,7 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
};
}
- let ret = libc::pthread_create(&mut native, attr.as_ptr(), thread_start, p as *mut _);
+ let ret = libc::pthread_create(&mut native, attr.as_ptr(), thread_start, data as *mut _);
// Note: if the thread creation fails and this assert fails, then p will
// be leaked. However, an alternative design could cause double-free
// which is clearly worse.
@@ -82,19 +91,20 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
return if ret != 0 {
// The thread failed to start and as a result p was not consumed. Therefore, it is
// safe to reconstruct the box so that it gets deallocated.
- drop(Box::from_raw(p));
+ drop(Box::from_raw(data));
Err(io::Error::from_raw_os_error(ret))
} else {
Ok(Thread { id: native })
};
- extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
+ extern "C" fn thread_start(data: *mut libc::c_void) -> *mut libc::c_void {
unsafe {
+ let data = Box::from_raw(data as *mut ThreadData);
// Next, set up our stack overflow handler which may get triggered if we run
// out of stack.
- let _handler = stack_overflow::Handler::new();
+ let _handler = stack_overflow::Handler::new(data.name);
// Finally, let's run some code.
- Box::from_raw(main as *mut Box<dyn FnOnce()>)();
+ (data.f)();
}
ptr::null_mut()
}
diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/pal/unsupported/thread.rs
index 8a3119f..5a1e3fd 100644
--- a/library/std/src/sys/pal/unsupported/thread.rs
+++ b/library/std/src/sys/pal/unsupported/thread.rs
@@ -10,7 +10,11 @@
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
- pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+ pub unsafe fn new(
+ _stack: usize,
+ _name: Option<&str>,
+ _p: Box<dyn FnOnce()>,
+ ) -> io::Result<Thread> {
unsupported()
}
diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs
index 5f21a55..a46c746 100644
--- a/library/std/src/sys/pal/wasi/thread.rs
+++ b/library/std/src/sys/pal/wasi/thread.rs
@@ -73,7 +73,7 @@ impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
cfg_if::cfg_if! {
if #[cfg(target_feature = "atomics")] {
- pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+ pub unsafe fn new(stack: usize, _name: Option<&str>, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
let p = Box::into_raw(Box::new(p));
let mut native: libc::pthread_t = unsafe { mem::zeroed() };
let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() };
@@ -120,7 +120,7 @@ extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
}
}
} else {
- pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+ pub unsafe fn new(_stack: usize, _name: Option<&str>, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
crate::sys::unsupported()
}
}
diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs
index 44ce3ea..ebfabaa 100644
--- a/library/std/src/sys/pal/wasm/atomics/thread.rs
+++ b/library/std/src/sys/pal/wasm/atomics/thread.rs
@@ -10,7 +10,11 @@
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
- pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+ pub unsafe fn new(
+ _stack: usize,
+ _name: Option<&str>,
+ _p: Box<dyn FnOnce()>,
+ ) -> io::Result<Thread> {
unsupported()
}
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs
index 1478517..b45f76f 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/pal/windows/thread.rs
@@ -20,7 +20,11 @@ pub struct Thread {
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
- pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+ pub unsafe fn new(
+ stack: usize,
+ _name: Option<&str>,
+ p: Box<dyn FnOnce()>,
+ ) -> io::Result<Thread> {
let p = Box::into_raw(Box::new(p));
// CreateThread rounds up values for the stack size to the nearest page size (at least 4kb).
diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs
index 1b344e9..f2404a6 100644
--- a/library/std/src/sys/pal/xous/thread.rs
+++ b/library/std/src/sys/pal/xous/thread.rs
@@ -20,7 +20,11 @@ pub struct Thread {
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
- pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+ pub unsafe fn new(
+ stack: usize,
+ _name: Option<&str>,
+ p: Box<dyn FnOnce()>,
+ ) -> io::Result<Thread> {
let p = Box::into_raw(Box::new(p));
let mut stack_size = crate::cmp::max(stack, MIN_STACK_SIZE);
diff --git a/library/std/src/sys/random/sgx.rs b/library/std/src/sys/random/sgx.rs
index c3647a8..462b190 100644
--- a/library/std/src/sys/random/sgx.rs
+++ b/library/std/src/sys/random/sgx.rs
@@ -46,22 +46,22 @@ fn rdrand16() -> u16 {
}
pub fn fill_bytes(bytes: &mut [u8]) {
- let mut chunks = bytes.array_chunks_mut();
- for chunk in &mut chunks {
+ let (chunks, remainder) = bytes.as_chunks_mut();
+ for chunk in chunks {
*chunk = rdrand64().to_ne_bytes();
}
- let mut chunks = chunks.into_remainder().array_chunks_mut();
- for chunk in &mut chunks {
+ let (chunks, remainder) = remainder.as_chunks_mut();
+ for chunk in chunks {
*chunk = rdrand32().to_ne_bytes();
}
- let mut chunks = chunks.into_remainder().array_chunks_mut();
- for chunk in &mut chunks {
+ let (chunks, remainder) = remainder.as_chunks_mut();
+ for chunk in chunks {
*chunk = rdrand16().to_ne_bytes();
}
- if let [byte] = chunks.into_remainder() {
+ if let [byte] = remainder {
*byte = rdrand16() as u8;
}
}
diff --git a/library/std/src/sys/random/uefi.rs b/library/std/src/sys/random/uefi.rs
index 5f001f0..4a71d32 100644
--- a/library/std/src/sys/random/uefi.rs
+++ b/library/std/src/sys/random/uefi.rs
@@ -138,12 +138,11 @@ fn is_rdrand_good() -> bool {
}
unsafe fn rdrand_exact(dest: &mut [u8]) -> Option<()> {
- let mut chunks = dest.array_chunks_mut();
- for chunk in &mut chunks {
+ let (chunks, tail) = dest.as_chunks_mut();
+ for chunk in chunks {
*chunk = unsafe { rdrand() }?.to_ne_bytes();
}
- let tail = chunks.into_remainder();
let n = tail.len();
if n > 0 {
let src = unsafe { rdrand() }?.to_ne_bytes();
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 6075173..dff981c 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -595,7 +595,7 @@ fn drop(&mut self) {
// Similarly, the `sys` implementation must guarantee that no references to the closure
// exist after the thread has terminated, which is signaled by `Thread::join`
// returning.
- native: unsafe { imp::Thread::new(stack_size, main)? },
+ native: unsafe { imp::Thread::new(stack_size, my_thread.name(), main)? },
thread: my_thread,
packet: my_packet,
})
@@ -1399,6 +1399,11 @@ pub(crate) fn with_current_name<F, R>(f: F) -> R
}
/// The internal representation of a `Thread` handle
+///
+/// We explicitly set the alignment for our guarantee in Thread::into_raw. This
+/// allows applications to stuff extra metadata bits into the alignment, which
+/// can be rather useful when working with atomics.
+#[repr(align(8))]
struct Inner {
name: Option<ThreadNameString>,
id: ThreadId,
@@ -1582,7 +1587,8 @@ pub fn name(&self) -> Option<&str> {
/// Consumes the `Thread`, returning a raw pointer.
///
/// To avoid a memory leak the pointer must be converted
- /// back into a `Thread` using [`Thread::from_raw`].
+ /// back into a `Thread` using [`Thread::from_raw`]. The pointer is
+ /// guaranteed to be aligned to at least 8 bytes.
///
/// # Examples
///
diff --git a/library/std/tests/sync/lib.rs b/library/std/tests/sync/lib.rs
index 51190f0..94f1fe9 100644
--- a/library/std/tests/sync/lib.rs
+++ b/library/std/tests/sync/lib.rs
@@ -6,7 +6,10 @@
#![feature(reentrant_lock)]
#![feature(rwlock_downgrade)]
#![feature(std_internals)]
+#![feature(sync_nonpoison)]
+#![feature(nonpoison_mutex)]
#![allow(internal_features)]
+#![feature(macro_metavar_expr_concat)] // For concatenating identifiers in macros.
mod barrier;
mod condvar;
@@ -29,3 +32,55 @@
#[path = "../common/mod.rs"]
mod common;
+
+#[track_caller]
+fn result_unwrap<T, E: std::fmt::Debug>(x: Result<T, E>) -> T {
+ x.unwrap()
+}
+
+/// A macro that generates two test cases for both the poison and nonpoison locks.
+///
+/// To write a test that tests both `poison` and `nonpoison` locks, import any of the types
+/// under both `poison` and `nonpoison` using the module name `locks` instead. For example, write
+/// `use locks::Mutex;` instead of `use std::sync::poiosn::Mutex`. This will import the correct type
+/// for each test variant.
+///
+/// Write a test as normal in the `test_body`, but instead of calling `unwrap` on `poison` methods
+/// that return a `LockResult` or similar, call the function `maybe_unwrap(...)` on the result.
+///
+/// For example, call `maybe_unwrap(mutex.lock())` instead of `mutex.lock().unwrap()` or
+/// `maybe_unwrap(rwlock.read())` instead of `rwlock.read().unwrap()`.
+///
+/// For the `poison` types, `maybe_unwrap` will simply unwrap the `Result` (usually this is a form
+/// of `LockResult`, but it could also be other kinds of results). For the `nonpoison` types, it is
+/// a no-op (the identity function).
+///
+/// The test names will be prefiex with `poison_` or `nonpoison_`.
+macro_rules! nonpoison_and_poison_unwrap_test {
+ (
+ name: $name:ident,
+ test_body: {$($test_body:tt)*}
+ ) => {
+ // Creates the nonpoison test.
+ #[test]
+ fn ${concat(nonpoison_, $name)}() {
+ #[allow(unused_imports)]
+ use ::std::convert::identity as maybe_unwrap;
+ use ::std::sync::nonpoison as locks;
+
+ $($test_body)*
+ }
+
+ // Creates the poison test with the suffix `_unwrap_poisoned`.
+ #[test]
+ fn ${concat(poison_, $name)}() {
+ #[allow(unused_imports)]
+ use super::result_unwrap as maybe_unwrap;
+ use ::std::sync::poison as locks;
+
+ $($test_body)*
+ }
+ }
+}
+
+use nonpoison_and_poison_unwrap_test;
diff --git a/library/std/tests/sync/mutex.rs b/library/std/tests/sync/mutex.rs
index ac82914..90cefc0 100644
--- a/library/std/tests/sync/mutex.rs
+++ b/library/std/tests/sync/mutex.rs
@@ -6,7 +6,71 @@
use std::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError};
use std::{hint, mem, thread};
-struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Nonpoison & Poison Tests
+////////////////////////////////////////////////////////////////////////////////////////////////////
+use super::nonpoison_and_poison_unwrap_test;
+
+nonpoison_and_poison_unwrap_test!(
+ name: smoke,
+ test_body: {
+ use locks::Mutex;
+
+ let m = Mutex::new(());
+ drop(maybe_unwrap(m.lock()));
+ drop(maybe_unwrap(m.lock()));
+ }
+);
+
+nonpoison_and_poison_unwrap_test!(
+ name: lots_and_lots,
+ test_body: {
+ use locks::Mutex;
+
+ const J: u32 = 1000;
+ const K: u32 = 3;
+
+ let m = Arc::new(Mutex::new(0));
+
+ fn inc(m: &Mutex<u32>) {
+ for _ in 0..J {
+ *maybe_unwrap(m.lock()) += 1;
+ }
+ }
+
+ let (tx, rx) = channel();
+ for _ in 0..K {
+ let tx2 = tx.clone();
+ let m2 = m.clone();
+ thread::spawn(move || {
+ inc(&m2);
+ tx2.send(()).unwrap();
+ });
+ let tx2 = tx.clone();
+ let m2 = m.clone();
+ thread::spawn(move || {
+ inc(&m2);
+ tx2.send(()).unwrap();
+ });
+ }
+
+ drop(tx);
+ for _ in 0..2 * K {
+ rx.recv().unwrap();
+ }
+ assert_eq!(*maybe_unwrap(m.lock()), J * K * 2);
+ }
+);
+
+nonpoison_and_poison_unwrap_test!(
+ name: try_lock,
+ test_body: {
+ use locks::Mutex;
+
+ let m = Mutex::new(());
+ *m.try_lock().unwrap() = ();
+ }
+);
#[derive(Eq, PartialEq, Debug)]
struct NonCopy(i32);
@@ -26,58 +90,278 @@ fn test_needs_drop() {
assert!(mem::needs_drop::<NonCopyNeedsDrop>());
}
-#[derive(Clone, Eq, PartialEq, Debug)]
-struct Cloneable(i32);
+nonpoison_and_poison_unwrap_test!(
+ name: test_into_inner,
+ test_body: {
+ use locks::Mutex;
-#[test]
-fn smoke() {
- let m = Mutex::new(());
- drop(m.lock().unwrap());
- drop(m.lock().unwrap());
-}
-
-#[test]
-fn lots_and_lots() {
- const J: u32 = 1000;
- const K: u32 = 3;
-
- let m = Arc::new(Mutex::new(0));
-
- fn inc(m: &Mutex<u32>) {
- for _ in 0..J {
- *m.lock().unwrap() += 1;
- }
+ let m = Mutex::new(NonCopy(10));
+ assert_eq!(maybe_unwrap(m.into_inner()), NonCopy(10));
}
+);
+
+nonpoison_and_poison_unwrap_test!(
+ name: test_into_inner_drop,
+ test_body: {
+ use locks::Mutex;
+
+ struct Foo(Arc<AtomicUsize>);
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ self.0.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+
+ let num_drops = Arc::new(AtomicUsize::new(0));
+ let m = Mutex::new(Foo(num_drops.clone()));
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ {
+ let _inner = maybe_unwrap(m.into_inner());
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ }
+ assert_eq!(num_drops.load(Ordering::SeqCst), 1);
+ }
+);
+
+nonpoison_and_poison_unwrap_test!(
+ name: test_get_mut,
+ test_body: {
+ use locks::Mutex;
+
+ let mut m = Mutex::new(NonCopy(10));
+ *maybe_unwrap(m.get_mut()) = NonCopy(20);
+ assert_eq!(maybe_unwrap(m.into_inner()), NonCopy(20));
+ }
+);
+
+nonpoison_and_poison_unwrap_test!(
+ name: test_get_cloned,
+ test_body: {
+ use locks::Mutex;
+
+ #[derive(Clone, Eq, PartialEq, Debug)]
+ struct Cloneable(i32);
+
+ let m = Mutex::new(Cloneable(10));
+
+ assert_eq!(maybe_unwrap(m.get_cloned()), Cloneable(10));
+ }
+);
+
+nonpoison_and_poison_unwrap_test!(
+ name: test_set,
+ test_body: {
+ use locks::Mutex;
+
+ fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+ where
+ T: Debug + Eq,
+ {
+ let m = Mutex::new(init());
+
+ assert_eq!(*maybe_unwrap(m.lock()), init());
+ maybe_unwrap(m.set(value()));
+ assert_eq!(*maybe_unwrap(m.lock()), value());
+ }
+
+ inner(|| NonCopy(10), || NonCopy(20));
+ inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+ }
+);
+
+// Ensure that old values that are replaced by `set` are correctly dropped.
+nonpoison_and_poison_unwrap_test!(
+ name: test_set_drop,
+ test_body: {
+ use locks::Mutex;
+
+ struct Foo(Arc<AtomicUsize>);
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ self.0.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+
+ let num_drops = Arc::new(AtomicUsize::new(0));
+ let m = Mutex::new(Foo(num_drops.clone()));
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+
+ let different = Foo(Arc::new(AtomicUsize::new(42)));
+ maybe_unwrap(m.set(different));
+ assert_eq!(num_drops.load(Ordering::SeqCst), 1);
+ }
+);
+
+nonpoison_and_poison_unwrap_test!(
+ name: test_replace,
+ test_body: {
+ use locks::Mutex;
+
+ fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+ where
+ T: Debug + Eq,
+ {
+ let m = Mutex::new(init());
+
+ assert_eq!(*maybe_unwrap(m.lock()), init());
+ assert_eq!(maybe_unwrap(m.replace(value())), init());
+ assert_eq!(*maybe_unwrap(m.lock()), value());
+ }
+
+ inner(|| NonCopy(10), || NonCopy(20));
+ inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+ }
+);
+
+// FIXME(nonpoison_condvar): Move this to the `condvar.rs` test file once `nonpoison::condvar` gets
+// implemented.
+#[test]
+fn test_mutex_arc_condvar() {
+ struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
+
+ let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
+ let packet2 = Packet(packet.0.clone());
let (tx, rx) = channel();
- for _ in 0..K {
- let tx2 = tx.clone();
- let m2 = m.clone();
- thread::spawn(move || {
- inc(&m2);
- tx2.send(()).unwrap();
- });
- let tx2 = tx.clone();
- let m2 = m.clone();
- thread::spawn(move || {
- inc(&m2);
- tx2.send(()).unwrap();
- });
- }
- drop(tx);
- for _ in 0..2 * K {
+ let _t = thread::spawn(move || {
+ // Wait until our parent has taken the lock.
+ rx.recv().unwrap();
+ let &(ref lock, ref cvar) = &*packet2.0;
+
+ // Set the data to `true` and wake up our parent.
+ let mut guard = lock.lock().unwrap();
+ *guard = true;
+ cvar.notify_one();
+ });
+
+ let &(ref lock, ref cvar) = &*packet.0;
+ let mut guard = lock.lock().unwrap();
+ // Wake up our child.
+ tx.send(()).unwrap();
+
+ // Wait until our child has set the data to `true`.
+ assert!(!*guard);
+ while !*guard {
+ guard = cvar.wait(guard).unwrap();
+ }
+}
+
+nonpoison_and_poison_unwrap_test!(
+ name: test_mutex_arc_nested,
+ test_body: {
+ use locks::Mutex;
+
+ // Tests nested mutexes and access
+ // to underlying data.
+ let arc = Arc::new(Mutex::new(1));
+ let arc2 = Arc::new(Mutex::new(arc));
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move || {
+ let lock = maybe_unwrap(arc2.lock());
+ let lock2 = maybe_unwrap(lock.lock());
+ assert_eq!(*lock2, 1);
+ tx.send(()).unwrap();
+ });
rx.recv().unwrap();
}
- assert_eq!(*m.lock().unwrap(), J * K * 2);
-}
+);
-#[test]
-fn try_lock() {
- let m = Mutex::new(());
- *m.try_lock().unwrap() = ();
-}
+nonpoison_and_poison_unwrap_test!(
+ name: test_mutex_unsized,
+ test_body: {
+ use locks::Mutex;
+ let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
+ {
+ let b = &mut *maybe_unwrap(mutex.lock());
+ b[0] = 4;
+ b[2] = 5;
+ }
+ let comp: &[i32] = &[4, 2, 5];
+ assert_eq!(&*maybe_unwrap(mutex.lock()), comp);
+ }
+);
+
+nonpoison_and_poison_unwrap_test!(
+ name: test_mapping_mapped_guard,
+ test_body: {
+ use locks::{Mutex, MutexGuard, MappedMutexGuard};
+
+ let arr = [0; 4];
+ let lock = Mutex::new(arr);
+ let guard = maybe_unwrap(lock.lock());
+ let guard = MutexGuard::map(guard, |arr| &mut arr[..2]);
+ let mut guard = MappedMutexGuard::map(guard, |slice| &mut slice[1..]);
+ assert_eq!(guard.len(), 1);
+ guard[0] = 42;
+ drop(guard);
+ assert_eq!(*maybe_unwrap(lock.lock()), [0, 42, 0, 0]);
+ }
+);
+
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+nonpoison_and_poison_unwrap_test!(
+ name: test_panics,
+ test_body: {
+ use locks::Mutex;
+
+ let mutex = Mutex::new(42);
+
+ let catch_unwind_result1 = panic::catch_unwind(AssertUnwindSafe(|| {
+ let _guard1 = maybe_unwrap(mutex.lock());
+
+ panic!("test panic with mutex once");
+ }));
+ assert!(catch_unwind_result1.is_err());
+
+ let catch_unwind_result2 = panic::catch_unwind(AssertUnwindSafe(|| {
+ let _guard2 = maybe_unwrap(mutex.lock());
+
+ panic!("test panic with mutex twice");
+ }));
+ assert!(catch_unwind_result2.is_err());
+
+ let catch_unwind_result3 = panic::catch_unwind(AssertUnwindSafe(|| {
+ let _guard3 = maybe_unwrap(mutex.lock());
+
+ panic!("test panic with mutex thrice");
+ }));
+ assert!(catch_unwind_result3.is_err());
+ }
+);
+
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+nonpoison_and_poison_unwrap_test!(
+ name: test_mutex_arc_access_in_unwind,
+ test_body: {
+ use locks::Mutex;
+
+ let arc = Arc::new(Mutex::new(1));
+ let arc2 = arc.clone();
+ let _ = thread::spawn(move || -> () {
+ struct Unwinder {
+ i: Arc<Mutex<i32>>,
+ }
+ impl Drop for Unwinder {
+ fn drop(&mut self) {
+ *maybe_unwrap(self.i.lock()) += 1;
+ }
+ }
+ let _u = Unwinder { i: arc2 };
+ panic!();
+ })
+ .join();
+ let lock = maybe_unwrap(arc.lock());
+ assert_eq!(*lock, 2);
+ }
+);
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Poison Tests
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// Creates a mutex that is immediately poisoned.
fn new_poisoned_mutex<T>(value: T) -> Mutex<T> {
let mutex = Mutex::new(value);
@@ -94,30 +378,6 @@ fn new_poisoned_mutex<T>(value: T) -> Mutex<T> {
}
#[test]
-fn test_into_inner() {
- let m = Mutex::new(NonCopy(10));
- assert_eq!(m.into_inner().unwrap(), NonCopy(10));
-}
-
-#[test]
-fn test_into_inner_drop() {
- struct Foo(Arc<AtomicUsize>);
- impl Drop for Foo {
- fn drop(&mut self) {
- self.0.fetch_add(1, Ordering::SeqCst);
- }
- }
- let num_drops = Arc::new(AtomicUsize::new(0));
- let m = Mutex::new(Foo(num_drops.clone()));
- assert_eq!(num_drops.load(Ordering::SeqCst), 0);
- {
- let _inner = m.into_inner().unwrap();
- assert_eq!(num_drops.load(Ordering::SeqCst), 0);
- }
- assert_eq!(num_drops.load(Ordering::SeqCst), 1);
-}
-
-#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_into_inner_poison() {
let m = new_poisoned_mutex(NonCopy(10));
@@ -129,15 +389,11 @@ fn test_into_inner_poison() {
}
#[test]
-fn test_get_cloned() {
- let m = Mutex::new(Cloneable(10));
-
- assert_eq!(m.get_cloned().unwrap(), Cloneable(10));
-}
-
-#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_get_cloned_poison() {
+ #[derive(Clone, Eq, PartialEq, Debug)]
+ struct Cloneable(i32);
+
let m = new_poisoned_mutex(Cloneable(10));
match m.get_cloned() {
@@ -147,13 +403,6 @@ fn test_get_cloned_poison() {
}
#[test]
-fn test_get_mut() {
- let mut m = Mutex::new(NonCopy(10));
- *m.get_mut().unwrap() = NonCopy(20);
- assert_eq!(m.into_inner().unwrap(), NonCopy(20));
-}
-
-#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_get_mut_poison() {
let mut m = new_poisoned_mutex(NonCopy(10));
@@ -165,23 +414,6 @@ fn test_get_mut_poison() {
}
#[test]
-fn test_set() {
- fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
- where
- T: Debug + Eq,
- {
- let m = Mutex::new(init());
-
- assert_eq!(*m.lock().unwrap(), init());
- m.set(value()).unwrap();
- assert_eq!(*m.lock().unwrap(), value());
- }
-
- inner(|| NonCopy(10), || NonCopy(20));
- inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
-}
-
-#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_set_poison() {
fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
@@ -204,23 +436,6 @@ fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
}
#[test]
-fn test_replace() {
- fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
- where
- T: Debug + Eq,
- {
- let m = Mutex::new(init());
-
- assert_eq!(*m.lock().unwrap(), init());
- assert_eq!(m.replace(value()).unwrap(), init());
- assert_eq!(*m.lock().unwrap(), value());
- }
-
- inner(|| NonCopy(10), || NonCopy(20));
- inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
-}
-
-#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_replace_poison() {
fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
@@ -243,31 +458,10 @@ fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
}
#[test]
-fn test_mutex_arc_condvar() {
- let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
- let packet2 = Packet(packet.0.clone());
- let (tx, rx) = channel();
- let _t = thread::spawn(move || {
- // wait until parent gets in
- rx.recv().unwrap();
- let &(ref lock, ref cvar) = &*packet2.0;
- let mut lock = lock.lock().unwrap();
- *lock = true;
- cvar.notify_one();
- });
-
- let &(ref lock, ref cvar) = &*packet.0;
- let mut lock = lock.lock().unwrap();
- tx.send(()).unwrap();
- assert!(!*lock);
- while !*lock {
- lock = cvar.wait(lock).unwrap();
- }
-}
-
-#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_arc_condvar_poison() {
+ struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
+
let packet = Packet(Arc::new((Mutex::new(1), Condvar::new())));
let packet2 = Packet(packet.0.clone());
let (tx, rx) = channel();
@@ -327,69 +521,6 @@ fn test_mutex_arc_poison_mapped() {
}
#[test]
-fn test_mutex_arc_nested() {
- // Tests nested mutexes and access
- // to underlying data.
- let arc = Arc::new(Mutex::new(1));
- let arc2 = Arc::new(Mutex::new(arc));
- let (tx, rx) = channel();
- let _t = thread::spawn(move || {
- let lock = arc2.lock().unwrap();
- let lock2 = lock.lock().unwrap();
- assert_eq!(*lock2, 1);
- tx.send(()).unwrap();
- });
- rx.recv().unwrap();
-}
-
-#[test]
-#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
-fn test_mutex_arc_access_in_unwind() {
- let arc = Arc::new(Mutex::new(1));
- let arc2 = arc.clone();
- let _ = thread::spawn(move || -> () {
- struct Unwinder {
- i: Arc<Mutex<i32>>,
- }
- impl Drop for Unwinder {
- fn drop(&mut self) {
- *self.i.lock().unwrap() += 1;
- }
- }
- let _u = Unwinder { i: arc2 };
- panic!();
- })
- .join();
- let lock = arc.lock().unwrap();
- assert_eq!(*lock, 2);
-}
-
-#[test]
-fn test_mutex_unsized() {
- let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
- {
- let b = &mut *mutex.lock().unwrap();
- b[0] = 4;
- b[2] = 5;
- }
- let comp: &[i32] = &[4, 2, 5];
- assert_eq!(&*mutex.lock().unwrap(), comp);
-}
-
-#[test]
-fn test_mapping_mapped_guard() {
- let arr = [0; 4];
- let mut lock = Mutex::new(arr);
- let guard = lock.lock().unwrap();
- let guard = MutexGuard::map(guard, |arr| &mut arr[..2]);
- let mut guard = MappedMutexGuard::map(guard, |slice| &mut slice[1..]);
- assert_eq!(guard.len(), 1);
- guard[0] = 42;
- drop(guard);
- assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]);
-}
-
-#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn panic_while_mapping_unlocked_poison() {
let lock = Mutex::new(());
diff --git a/library/std_detect/src/detect/macros.rs b/library/std_detect/src/detect/macros.rs
index c2a006d..17140e1 100644
--- a/library/std_detect/src/detect/macros.rs
+++ b/library/std_detect/src/detect/macros.rs
@@ -131,14 +131,13 @@ macro_rules! $macro_name {
};
}
- #[test] //tidy:skip
#[deny(unexpected_cfgs)]
#[deny(unfulfilled_lint_expectations)]
- fn unexpected_cfgs() {
+ const _: () = {
$(
check_cfg_feature!($feature, $feature_lit $(, without cfg check: $feature_cfg_check)? $(: $($target_feature_lit),*)?);
)*
- }
+ };
/// Each variant denotes a position in a bitset for a particular feature.
///
diff --git a/library/std_detect/src/detect/os/riscv.rs b/library/std_detect/src/detect/os/riscv.rs
index 46b7dd7..dc9a403 100644
--- a/library/std_detect/src/detect/os/riscv.rs
+++ b/library/std_detect/src/detect/os/riscv.rs
@@ -135,4 +135,5 @@ macro_rules! group {
}
#[cfg(test)]
+#[path = "riscv/tests.rs"]
mod tests;
diff --git a/library/stdarch/crates/core_arch/src/wasm32/mod.rs b/library/stdarch/crates/core_arch/src/wasm32/mod.rs
index 2c4361f..60049c7 100644
--- a/library/stdarch/crates/core_arch/src/wasm32/mod.rs
+++ b/library/stdarch/crates/core_arch/src/wasm32/mod.rs
@@ -191,6 +191,16 @@ pub fn f64_sqrt(a: f64) -> f64 {
// #[cfg_attr(test, assert_instr(throw, TAG = 0, ptr = core::ptr::null_mut()))]
#[inline]
#[unstable(feature = "wasm_exception_handling_intrinsics", issue = "122465")]
+// FIXME: Since this instruction unwinds, `core` built with `-C panic=unwind`
+// cannot be linked with `-C panic=abort` programs. But that's not
+// entirely supported anyway, because runtimes without EH support won't
+// be able to handle `try` blocks in `-C panic=unwind` crates either.
+// We ship `-C panic=abort` `core`, so this doesn't affect users
+// directly. Resolving this will likely require patching out both `try`
+// and `throw` instructions, at which point we can look into whitelisting
+// this function in the compiler to allow linking.
+// See https://github.com/rust-lang/rust/issues/118168.
+#[allow(ffi_unwind_calls)]
pub unsafe fn throw<const TAG: i32>(ptr: *mut u8) -> ! {
static_assert!(TAG == 0); // LLVM only supports tag 0 == C++ right now.
wasm_throw(TAG, ptr)
diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml
index 032f527..7b4aeed 100644
--- a/library/sysroot/Cargo.toml
+++ b/library/sysroot/Cargo.toml
@@ -6,6 +6,8 @@
edition = "2024"
[lib]
+test = false
+bench = false
# make sure this crate isn't included in public standard library docs
doc = false
@@ -23,9 +25,7 @@
backtrace-trace-only = ["std/backtrace-trace-only"]
compiler-builtins-c = ["std/compiler-builtins-c"]
compiler-builtins-mem = ["std/compiler-builtins-mem"]
-compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"]
compiler-builtins-no-f16-f128 = ["std/compiler-builtins-no-f16-f128"]
-compiler-builtins-mangled-names = ["std/compiler-builtins-mangled-names"]
debug_refcell = ["std/debug_refcell"]
llvm-libunwind = ["std/llvm-libunwind"]
system-llvm-libunwind = ["std/system-llvm-libunwind"]
diff --git a/library/windows_targets/Cargo.toml b/library/windows_targets/Cargo.toml
index 705c9e0..1c804a0 100644
--- a/library/windows_targets/Cargo.toml
+++ b/library/windows_targets/Cargo.toml
@@ -4,6 +4,11 @@
version = "0.0.0"
edition = "2024"
+[lib]
+test = false
+bench = false
+doc = false
+
[features]
# Enable using raw-dylib for Windows imports.
# This will eventually be the default.
diff --git a/library/windows_targets/src/lib.rs b/library/windows_targets/src/lib.rs
index 9e82e6a..3446e21 100644
--- a/library/windows_targets/src/lib.rs
+++ b/library/windows_targets/src/lib.rs
@@ -34,22 +34,12 @@
#[cfg(feature = "windows_raw_dylib")]
pub macro link($($tt:tt)*) {
- $crate::link_raw_dylib!($($tt)*)
+ $crate::link_raw_dylib!($($tt)*);
}
#[cfg(not(feature = "windows_raw_dylib"))]
-pub macro link {
- ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => (
- // Note: the windows-targets crate uses a pre-built Windows.lib import library which we don't
- // have in this repo. So instead we always link kernel32.lib and add the rest of the import
- // libraries below by using an empty extern block. This works because extern blocks are not
- // connected to the library given in the #[link] attribute.
- #[link(name = "kernel32")]
- unsafe extern $abi {
- $(#[link_name=$link_name])?
- pub fn $($function)*;
- }
- )
+pub macro link($($tt:tt)*) {
+ $crate::link_dylib!($($tt)*);
}
#[cfg(not(feature = "windows_raw_dylib"))]
diff --git a/src/bootstrap/defaults/bootstrap.tools.toml b/src/bootstrap/defaults/bootstrap.tools.toml
index 57c2706..5abe636 100644
--- a/src/bootstrap/defaults/bootstrap.tools.toml
+++ b/src/bootstrap/defaults/bootstrap.tools.toml
@@ -14,6 +14,8 @@
doc-stage = 2
# Contributors working on tools will probably expect compiler docs to be generated, so they can figure out how to use the API.
compiler-docs = true
+# Contributors working on tools are the most likely to change non-rust programs.
+tidy-extra-checks = "auto:js,auto:py,auto:cpp,auto:spellcheck"
[llvm]
# Will download LLVM from CI if available on your platform.
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index cfe090b..b423240 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -556,3 +556,9 @@ fn run_tool_check_step(
allow_features: COMPILETEST_ALLOW_FEATURES,
default: false,
});
+
+tool_check_step!(Linkchecker {
+ path: "src/tools/linkchecker",
+ mode: |_builder| Mode::ToolBootstrap,
+ default: false
+});
diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs
index a0371eb..b119f2d 100644
--- a/src/bootstrap/src/core/build_steps/clippy.rs
+++ b/src/bootstrap/src/core/build_steps/clippy.rs
@@ -19,6 +19,7 @@
"too_many_arguments",
"needless_lifetimes", // people want to keep the lifetimes
"wrong_self_convention",
+ "approx_constant", // libcore is what defines those
];
fn lint_args(builder: &Builder<'_>, config: &LintConfig, ignored_rules: &[&str]) -> Vec<String> {
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index c7e7b01..4abfe18 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -597,11 +597,6 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
let mut features = String::new();
- if stage != 0 && builder.config.default_codegen_backend(target).as_deref() == Some("cranelift")
- {
- features += "compiler-builtins-no-f16-f128 ";
- }
-
if builder.no_std(target) == Some(true) {
features += " compiler-builtins-mem";
if !target.starts_with("bpf") {
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index d346062..0f92680 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1113,6 +1113,12 @@ fn run(self, builder: &Builder<'_>) {
8 * std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32
});
cmd.arg(jobs.to_string());
+ // pass the path to the npm command used for installing js deps.
+ if let Some(npm) = &builder.config.npm {
+ cmd.arg(npm);
+ } else {
+ cmd.arg("npm");
+ }
if builder.is_verbose() {
cmd.arg("--verbose");
}
@@ -3126,7 +3132,11 @@ fn run(self, builder: &Builder<'_>) {
}
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/bootstrap")
+ // Bootstrap tests might not be perfectly self-contained and can depend on the external
+ // environment, submodules that are checked out, etc.
+ // Therefore we only run them by default on CI.
+ let runs_on_ci = run.builder.config.is_running_on_ci;
+ run.path("src/bootstrap").default_condition(runs_on_ci)
}
fn make_run(run: RunConfig<'_>) {
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 923c3a9..020622d 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -1033,6 +1033,7 @@ macro_rules! describe {
check::Compiletest,
check::FeaturesStatusDump,
check::CoverageDump,
+ check::Linkchecker,
// This has special staging logic, it may run on stage 1 while others run on stage 0.
// It takes quite some time to build stage 1, so put this at the end.
//
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 6e04f11..9644ade 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -45,7 +45,9 @@
DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, RustcLto, SplitDebuginfo,
StringOrBool, set, threads_from_config,
};
-use crate::core::download::is_download_ci_available;
+use crate::core::download::{
+ DownloadContext, download_beta_toolchain, is_download_ci_available, maybe_download_rustfmt,
+};
use crate::utils::channel;
use crate::utils::exec::{ExecutionContext, command};
use crate::utils::helpers::{exe, get_host_target};
@@ -795,13 +797,19 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
);
}
+ config.patch_binaries_for_nix = patch_binaries_for_nix;
+ config.bootstrap_cache_path = bootstrap_cache_path;
+ config.llvm_assertions =
+ toml.llvm.as_ref().is_some_and(|llvm| llvm.assertions.unwrap_or(false));
+
config.initial_rustc = if let Some(rustc) = rustc {
if !flags_skip_stage0_validation {
config.check_stage0_version(&rustc, "rustc");
}
rustc
} else {
- config.download_beta_toolchain();
+ let dwn_ctx = DownloadContext::from(&config);
+ download_beta_toolchain(dwn_ctx);
config
.out
.join(config.host_target)
@@ -827,7 +835,8 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
}
cargo
} else {
- config.download_beta_toolchain();
+ let dwn_ctx = DownloadContext::from(&config);
+ download_beta_toolchain(dwn_ctx);
config.initial_sysroot.join("bin").join(exe("cargo", config.host_target))
};
@@ -863,7 +872,6 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
config.reuse = reuse.map(PathBuf::from);
config.submodules = submodules;
config.android_ndk = android_ndk;
- config.bootstrap_cache_path = bootstrap_cache_path;
set(&mut config.low_priority, low_priority);
set(&mut config.compiler_docs, compiler_docs);
set(&mut config.library_docs_private_items, library_docs_private_items);
@@ -882,7 +890,6 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
set(&mut config.local_rebuild, local_rebuild);
set(&mut config.print_step_timings, print_step_timings);
set(&mut config.print_step_rusage, print_step_rusage);
- config.patch_binaries_for_nix = patch_binaries_for_nix;
config.verbose = cmp::max(config.verbose, flags_verbose as usize);
@@ -891,9 +898,6 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
config.apply_install_config(toml.install);
- config.llvm_assertions =
- toml.llvm.as_ref().is_some_and(|llvm| llvm.assertions.unwrap_or(false));
-
let file_content = t!(fs::read_to_string(config.src.join("src/ci/channel")));
let ci_channel = file_content.trim_end();
@@ -994,8 +998,12 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
config.apply_dist_config(toml.dist);
- config.initial_rustfmt =
- if let Some(r) = rustfmt { Some(r) } else { config.maybe_download_rustfmt() };
+ config.initial_rustfmt = if let Some(r) = rustfmt {
+ Some(r)
+ } else {
+ let dwn_ctx = DownloadContext::from(&config);
+ maybe_download_rustfmt(dwn_ctx)
+ };
if matches!(config.lld_mode, LldMode::SelfContained)
&& !config.lld_enabled
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 373fcd5..7ec6c62 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -7,9 +7,9 @@
use xz2::bufread::XzDecoder;
-use crate::core::config::BUILDER_CONFIG_FILENAME;
+use crate::core::config::{BUILDER_CONFIG_FILENAME, TargetSelection};
use crate::utils::build_stamp::BuildStamp;
-use crate::utils::exec::command;
+use crate::utils::exec::{ExecutionContext, command};
use crate::utils::helpers::{exe, hex_encode, move_file};
use crate::{Config, t};
@@ -24,17 +24,6 @@ fn extract_curl_version(out: String) -> semver::Version {
.unwrap_or(semver::Version::new(1, 0, 0))
}
-fn curl_version(config: &Config) -> semver::Version {
- let mut curl = command("curl");
- curl.arg("-V");
- let curl = curl.run_capture_stdout(config);
- if curl.is_failure() {
- return semver::Version::new(1, 0, 0);
- }
- let output = curl.stdout();
- extract_curl_version(output)
-}
-
/// Generic helpers that are useful anywhere in bootstrap.
impl Config {
pub fn is_verbose(&self) -> bool {
@@ -49,10 +38,7 @@ pub(crate) fn create<P: AsRef<Path>>(&self, path: P, s: &str) {
}
pub(crate) fn remove(&self, f: &Path) {
- if self.dry_run() {
- return;
- }
- fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {f:?}"));
+ remove(&self.exec_ctx, f);
}
/// Create a temporary directory in `out` and return its path.
@@ -68,49 +54,7 @@ pub(crate) fn tempdir(&self) -> PathBuf {
/// Whether or not `fix_bin_or_dylib` needs to be run; can only be true
/// on NixOS
fn should_fix_bins_and_dylibs(&self) -> bool {
- let val = *SHOULD_FIX_BINS_AND_DYLIBS.get_or_init(|| {
- let uname = command("uname").allow_failure().arg("-s").run_capture_stdout(self);
- if uname.is_failure() {
- return false;
- }
- let output = uname.stdout();
- if !output.starts_with("Linux") {
- return false;
- }
- // If the user has asked binaries to be patched for Nix, then
- // don't check for NixOS or `/lib`.
- // NOTE: this intentionally comes after the Linux check:
- // - patchelf only works with ELF files, so no need to run it on Mac or Windows
- // - On other Unix systems, there is no stable syscall interface, so Nix doesn't manage the global libc.
- if let Some(explicit_value) = self.patch_binaries_for_nix {
- return explicit_value;
- }
-
- // Use `/etc/os-release` instead of `/etc/NIXOS`.
- // The latter one does not exist on NixOS when using tmpfs as root.
- let is_nixos = match File::open("/etc/os-release") {
- Err(e) if e.kind() == ErrorKind::NotFound => false,
- Err(e) => panic!("failed to access /etc/os-release: {e}"),
- Ok(os_release) => BufReader::new(os_release).lines().any(|l| {
- let l = l.expect("reading /etc/os-release");
- matches!(l.trim(), "ID=nixos" | "ID='nixos'" | "ID=\"nixos\"")
- }),
- };
- if !is_nixos {
- let in_nix_shell = env::var("IN_NIX_SHELL");
- if let Ok(in_nix_shell) = in_nix_shell {
- eprintln!(
- "The IN_NIX_SHELL environment variable is `{in_nix_shell}`; \
- you may need to set `patch-binaries-for-nix=true` in bootstrap.toml"
- );
- }
- }
- is_nixos
- });
- if val {
- eprintln!("INFO: You seem to be using Nix.");
- }
- val
+ should_fix_bins_and_dylibs(self.patch_binaries_for_nix, &self.exec_ctx)
}
/// Modifies the interpreter section of 'fname' to fix the dynamic linker,
@@ -121,259 +65,22 @@ fn should_fix_bins_and_dylibs(&self) -> bool {
///
/// Please see <https://nixos.org/patchelf.html> for more information
fn fix_bin_or_dylib(&self, fname: &Path) {
- assert_eq!(SHOULD_FIX_BINS_AND_DYLIBS.get(), Some(&true));
- println!("attempting to patch {}", fname.display());
-
- // Only build `.nix-deps` once.
- static NIX_DEPS_DIR: OnceLock<PathBuf> = OnceLock::new();
- let mut nix_build_succeeded = true;
- let nix_deps_dir = NIX_DEPS_DIR.get_or_init(|| {
- // Run `nix-build` to "build" each dependency (which will likely reuse
- // the existing `/nix/store` copy, or at most download a pre-built copy).
- //
- // Importantly, we create a gc-root called `.nix-deps` in the `build/`
- // directory, but still reference the actual `/nix/store` path in the rpath
- // as it makes it significantly more robust against changes to the location of
- // the `.nix-deps` location.
- //
- // bintools: Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
- // zlib: Needed as a system dependency of `libLLVM-*.so`.
- // patchelf: Needed for patching ELF binaries (see doc comment above).
- let nix_deps_dir = self.out.join(".nix-deps");
- const NIX_EXPR: &str = "
- with (import <nixpkgs> {});
- symlinkJoin {
- name = \"rust-stage0-dependencies\";
- paths = [
- zlib
- patchelf
- stdenv.cc.bintools
- ];
- }
- ";
- nix_build_succeeded = command("nix-build")
- .allow_failure()
- .args([Path::new("-E"), Path::new(NIX_EXPR), Path::new("-o"), &nix_deps_dir])
- .run_capture_stdout(self)
- .is_success();
- nix_deps_dir
- });
- if !nix_build_succeeded {
- return;
- }
-
- let mut patchelf = command(nix_deps_dir.join("bin/patchelf"));
- patchelf.args(&[
- OsString::from("--add-rpath"),
- OsString::from(t!(fs::canonicalize(nix_deps_dir)).join("lib")),
- ]);
- if !path_is_dylib(fname) {
- // Finally, set the correct .interp for binaries
- let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker");
- let dynamic_linker = t!(fs::read_to_string(dynamic_linker_path));
- patchelf.args(["--set-interpreter", dynamic_linker.trim_end()]);
- }
- patchelf.arg(fname);
- let _ = patchelf.allow_failure().run_capture_stdout(self);
+ fix_bin_or_dylib(&self.out, fname, &self.exec_ctx);
}
fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) {
- self.verbose(|| println!("download {url}"));
- // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
- let tempfile = self.tempdir().join(dest_path.file_name().unwrap());
- // While bootstrap itself only supports http and https downloads, downstream forks might
- // need to download components from other protocols. The match allows them adding more
- // protocols without worrying about merge conflicts if we change the HTTP implementation.
- match url.split_once("://").map(|(proto, _)| proto) {
- Some("http") | Some("https") => {
- self.download_http_with_retries(&tempfile, url, help_on_error)
- }
- Some(other) => panic!("unsupported protocol {other} in {url}"),
- None => panic!("no protocol in {url}"),
- }
- t!(
- move_file(&tempfile, dest_path),
- format!("failed to rename {tempfile:?} to {dest_path:?}")
- );
- }
-
- fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) {
- println!("downloading {url}");
- // Try curl. If that fails and we are on windows, fallback to PowerShell.
- // options should be kept in sync with
- // src/bootstrap/src/core/download.rs
- // for consistency
- let mut curl = command("curl").allow_failure();
- curl.args([
- // follow redirect
- "--location",
- // timeout if speed is < 10 bytes/sec for > 30 seconds
- "--speed-time",
- "30",
- "--speed-limit",
- "10",
- // timeout if cannot connect within 30 seconds
- "--connect-timeout",
- "30",
- // output file
- "--output",
- tempfile.to_str().unwrap(),
- // if there is an error, don't restart the download,
- // instead continue where it left off.
- "--continue-at",
- "-",
- // retry up to 3 times. note that this means a maximum of 4
- // attempts will be made, since the first attempt isn't a *re*try.
- "--retry",
- "3",
- // show errors, even if --silent is specified
- "--show-error",
- // set timestamp of downloaded file to that of the server
- "--remote-time",
- // fail on non-ok http status
- "--fail",
- ]);
- // Don't print progress in CI; the \r wrapping looks bad and downloads don't take long enough for progress to be useful.
- if self.is_running_on_ci {
- curl.arg("--silent");
- } else {
- curl.arg("--progress-bar");
- }
- // --retry-all-errors was added in 7.71.0, don't use it if curl is old.
- if curl_version(self) >= semver::Version::new(7, 71, 0) {
- curl.arg("--retry-all-errors");
- }
- curl.arg(url);
- if !curl.run(self) {
- if self.host_target.contains("windows-msvc") {
- eprintln!("Fallback to PowerShell");
- for _ in 0..3 {
- let powershell = command("PowerShell.exe").allow_failure().args([
- "/nologo",
- "-Command",
- "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
- &format!(
- "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')",
- url, tempfile.to_str().expect("invalid UTF-8 not supported with powershell downloads"),
- ),
- ]).run_capture_stdout(self);
-
- if powershell.is_failure() {
- return;
- }
-
- eprintln!("\nspurious failure, trying again");
- }
- }
- if !help_on_error.is_empty() {
- eprintln!("{help_on_error}");
- }
- crate::exit!(1);
- }
+ let dwn_ctx: DownloadContext<'_> = self.into();
+ download_file(dwn_ctx, url, dest_path, help_on_error);
}
fn unpack(&self, tarball: &Path, dst: &Path, pattern: &str) {
- eprintln!("extracting {} to {}", tarball.display(), dst.display());
- if !dst.exists() {
- t!(fs::create_dir_all(dst));
- }
-
- // `tarball` ends with `.tar.xz`; strip that suffix
- // example: `rust-dev-nightly-x86_64-unknown-linux-gnu`
- let uncompressed_filename =
- Path::new(tarball.file_name().expect("missing tarball filename")).file_stem().unwrap();
- let directory_prefix = Path::new(Path::new(uncompressed_filename).file_stem().unwrap());
-
- // decompress the file
- let data = t!(File::open(tarball), format!("file {} not found", tarball.display()));
- let decompressor = XzDecoder::new(BufReader::new(data));
-
- let mut tar = tar::Archive::new(decompressor);
-
- let is_ci_rustc = dst.ends_with("ci-rustc");
- let is_ci_llvm = dst.ends_with("ci-llvm");
-
- // `compile::Sysroot` needs to know the contents of the `rustc-dev` tarball to avoid adding
- // it to the sysroot unless it was explicitly requested. But parsing the 100 MB tarball is slow.
- // Cache the entries when we extract it so we only have to read it once.
- let mut recorded_entries = if is_ci_rustc { recorded_entries(dst, pattern) } else { None };
-
- for member in t!(tar.entries()) {
- let mut member = t!(member);
- let original_path = t!(member.path()).into_owned();
- // skip the top-level directory
- if original_path == directory_prefix {
- continue;
- }
- let mut short_path = t!(original_path.strip_prefix(directory_prefix));
- let is_builder_config = short_path.to_str() == Some(BUILDER_CONFIG_FILENAME);
-
- if !(short_path.starts_with(pattern)
- || ((is_ci_rustc || is_ci_llvm) && is_builder_config))
- {
- continue;
- }
- short_path = short_path.strip_prefix(pattern).unwrap_or(short_path);
- let dst_path = dst.join(short_path);
- self.verbose(|| {
- println!("extracting {} to {}", original_path.display(), dst.display())
- });
- if !t!(member.unpack_in(dst)) {
- panic!("path traversal attack ??");
- }
- if let Some(record) = &mut recorded_entries {
- t!(writeln!(record, "{}", short_path.to_str().unwrap()));
- }
- let src_path = dst.join(original_path);
- if src_path.is_dir() && dst_path.exists() {
- continue;
- }
- t!(move_file(src_path, dst_path));
- }
- let dst_dir = dst.join(directory_prefix);
- if dst_dir.exists() {
- t!(fs::remove_dir_all(&dst_dir), format!("failed to remove {}", dst_dir.display()));
- }
+ unpack(&self.exec_ctx, tarball, dst, pattern);
}
/// Returns whether the SHA256 checksum of `path` matches `expected`.
+ #[cfg(test)]
pub(crate) fn verify(&self, path: &Path, expected: &str) -> bool {
- use sha2::Digest;
-
- self.verbose(|| println!("verifying {}", path.display()));
-
- if self.dry_run() {
- return false;
- }
-
- let mut hasher = sha2::Sha256::new();
-
- let file = t!(File::open(path));
- let mut reader = BufReader::new(file);
-
- loop {
- let buffer = t!(reader.fill_buf());
- let l = buffer.len();
- // break if EOF
- if l == 0 {
- break;
- }
- hasher.update(buffer);
- reader.consume(l);
- }
-
- let checksum = hex_encode(hasher.finalize().as_slice());
- let verified = checksum == expected;
-
- if !verified {
- println!(
- "invalid checksum: \n\
- found: {checksum}\n\
- expected: {expected}",
- );
- }
-
- verified
+ verify(&self.exec_ctx, path, expected)
}
}
@@ -388,6 +95,7 @@ fn recorded_entries(dst: &Path, pattern: &str) -> Option<BufWriter<File>> {
Some(BufWriter::new(t!(File::create(dst.join(name)))))
}
+#[derive(Clone)]
enum DownloadSource {
CI,
Dist,
@@ -420,63 +128,6 @@ pub(crate) fn download_clippy(&self) -> PathBuf {
cargo_clippy
}
- #[cfg(test)]
- pub(crate) fn maybe_download_rustfmt(&self) -> Option<PathBuf> {
- Some(PathBuf::new())
- }
-
- /// NOTE: rustfmt is a completely different toolchain than the bootstrap compiler, so it can't
- /// reuse target directories or artifacts
- #[cfg(not(test))]
- pub(crate) fn maybe_download_rustfmt(&self) -> Option<PathBuf> {
- use build_helper::stage0_parser::VersionMetadata;
-
- if self.dry_run() {
- return Some(PathBuf::new());
- }
-
- let VersionMetadata { date, version } = self.stage0_metadata.rustfmt.as_ref()?;
- let channel = format!("{version}-{date}");
-
- let host = self.host_target;
- let bin_root = self.out.join(host).join("rustfmt");
- let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host));
- let rustfmt_stamp = BuildStamp::new(&bin_root).with_prefix("rustfmt").add_stamp(channel);
- if rustfmt_path.exists() && rustfmt_stamp.is_up_to_date() {
- return Some(rustfmt_path);
- }
-
- self.download_component(
- DownloadSource::Dist,
- format!("rustfmt-{version}-{build}.tar.xz", build = host.triple),
- "rustfmt-preview",
- date,
- "rustfmt",
- );
- self.download_component(
- DownloadSource::Dist,
- format!("rustc-{version}-{build}.tar.xz", build = host.triple),
- "rustc",
- date,
- "rustfmt",
- );
-
- if self.should_fix_bins_and_dylibs() {
- self.fix_bin_or_dylib(&bin_root.join("bin").join("rustfmt"));
- self.fix_bin_or_dylib(&bin_root.join("bin").join("cargo-fmt"));
- let lib_dir = bin_root.join("lib");
- for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
- let lib = t!(lib);
- if path_is_dylib(&lib.path()) {
- self.fix_bin_or_dylib(&lib.path());
- }
- }
- }
-
- t!(rustfmt_stamp.write());
- Some(rustfmt_path)
- }
-
pub(crate) fn ci_rust_std_contents(&self) -> Vec<String> {
self.ci_component_contents(".rust-std-contents")
}
@@ -514,30 +165,6 @@ pub(crate) fn download_ci_rustc(&self, commit: &str) {
);
}
- #[cfg(test)]
- pub(crate) fn download_beta_toolchain(&self) {}
-
- #[cfg(not(test))]
- pub(crate) fn download_beta_toolchain(&self) {
- self.verbose(|| println!("downloading stage0 beta artifacts"));
-
- let date = &self.stage0_metadata.compiler.date;
- let version = &self.stage0_metadata.compiler.version;
- let extra_components = ["cargo"];
-
- let download_beta_component = |config: &Config, filename, prefix: &_, date: &_| {
- config.download_component(DownloadSource::Dist, filename, prefix, date, "stage0")
- };
-
- self.download_toolchain(
- version,
- "stage0",
- date,
- &extra_components,
- download_beta_component,
- );
- }
-
fn download_toolchain(
&self,
version: &str,
@@ -607,91 +234,8 @@ fn download_component(
key: &str,
destination: &str,
) {
- if self.dry_run() {
- return;
- }
-
- let cache_dst =
- self.bootstrap_cache_path.as_ref().cloned().unwrap_or_else(|| self.out.join("cache"));
-
- let cache_dir = cache_dst.join(key);
- if !cache_dir.exists() {
- t!(fs::create_dir_all(&cache_dir));
- }
-
- let bin_root = self.out.join(self.host_target).join(destination);
- let tarball = cache_dir.join(&filename);
- let (base_url, url, should_verify) = match mode {
- DownloadSource::CI => {
- let dist_server = if self.llvm_assertions {
- self.stage0_metadata.config.artifacts_with_llvm_assertions_server.clone()
- } else {
- self.stage0_metadata.config.artifacts_server.clone()
- };
- let url = format!(
- "{}/{filename}",
- key.strip_suffix(&format!("-{}", self.llvm_assertions)).unwrap()
- );
- (dist_server, url, false)
- }
- DownloadSource::Dist => {
- let dist_server = env::var("RUSTUP_DIST_SERVER")
- .unwrap_or(self.stage0_metadata.config.dist_server.to_string());
- // NOTE: make `dist` part of the URL because that's how it's stored in src/stage0
- (dist_server, format!("dist/{key}/{filename}"), true)
- }
- };
-
- // For the stage0 compiler, put special effort into ensuring the checksums are valid.
- let checksum = if should_verify {
- let error = format!(
- "src/stage0 doesn't contain a checksum for {url}. \
- Pre-built artifacts might not be available for this \
- target at this time, see https://doc.rust-lang.org/nightly\
- /rustc/platform-support.html for more information."
- );
- let sha256 = self.stage0_metadata.checksums_sha256.get(&url).expect(&error);
- if tarball.exists() {
- if self.verify(&tarball, sha256) {
- self.unpack(&tarball, &bin_root, prefix);
- return;
- } else {
- self.verbose(|| {
- println!(
- "ignoring cached file {} due to failed verification",
- tarball.display()
- )
- });
- self.remove(&tarball);
- }
- }
- Some(sha256)
- } else if tarball.exists() {
- self.unpack(&tarball, &bin_root, prefix);
- return;
- } else {
- None
- };
-
- let mut help_on_error = "";
- if destination == "ci-rustc" {
- help_on_error = "ERROR: failed to download pre-built rustc from CI
-
-NOTE: old builds get deleted after a certain time
-HELP: if trying to compile an old commit of rustc, disable `download-rustc` in bootstrap.toml:
-
-[rust]
-download-rustc = false
-";
- }
- self.download_file(&format!("{base_url}/{url}"), &tarball, help_on_error);
- if let Some(sha256) = checksum
- && !self.verify(&tarball, sha256)
- {
- panic!("failed to verify {}", tarball.display());
- }
-
- self.unpack(&tarball, &bin_root, prefix);
+ let dwn_ctx: DownloadContext<'_> = self.into();
+ download_component(dwn_ctx, mode, filename, prefix, key, destination);
}
#[cfg(test)]
@@ -852,6 +396,39 @@ pub fn download_ci_gcc(&self, gcc_sha: &str, root_dir: &Path) {
}
}
+/// Only should be used for pre config initialization downloads.
+pub(crate) struct DownloadContext<'a> {
+ host_target: TargetSelection,
+ out: &'a Path,
+ patch_binaries_for_nix: Option<bool>,
+ exec_ctx: &'a ExecutionContext,
+ stage0_metadata: &'a build_helper::stage0_parser::Stage0,
+ llvm_assertions: bool,
+ bootstrap_cache_path: &'a Option<PathBuf>,
+ is_running_on_ci: bool,
+}
+
+impl<'a> AsRef<DownloadContext<'a>> for DownloadContext<'a> {
+ fn as_ref(&self) -> &DownloadContext<'a> {
+ self
+ }
+}
+
+impl<'a> From<&'a Config> for DownloadContext<'a> {
+ fn from(value: &'a Config) -> Self {
+ DownloadContext {
+ host_target: value.host_target,
+ out: &value.out,
+ patch_binaries_for_nix: value.patch_binaries_for_nix,
+ exec_ctx: &value.exec_ctx,
+ stage0_metadata: &value.stage0_metadata,
+ llvm_assertions: value.llvm_assertions,
+ bootstrap_cache_path: &value.bootstrap_cache_path,
+ is_running_on_ci: value.is_running_on_ci,
+ }
+ }
+}
+
fn path_is_dylib(path: &Path) -> bool {
// The .so is not necessarily the extension, it might be libLLVM.so.18.1
path.to_str().is_some_and(|path| path.contains(".so"))
@@ -897,3 +474,596 @@ pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: boo
SUPPORTED_PLATFORMS.contains(&target_triple)
}
}
+
+#[cfg(test)]
+pub(crate) fn maybe_download_rustfmt<'a>(
+ dwn_ctx: impl AsRef<DownloadContext<'a>>,
+) -> Option<PathBuf> {
+ Some(PathBuf::new())
+}
+
+/// NOTE: rustfmt is a completely different toolchain than the bootstrap compiler, so it can't
+/// reuse target directories or artifacts
+#[cfg(not(test))]
+pub(crate) fn maybe_download_rustfmt<'a>(
+ dwn_ctx: impl AsRef<DownloadContext<'a>>,
+) -> Option<PathBuf> {
+ use build_helper::stage0_parser::VersionMetadata;
+
+ let dwn_ctx = dwn_ctx.as_ref();
+
+ if dwn_ctx.exec_ctx.dry_run() {
+ return Some(PathBuf::new());
+ }
+
+ let VersionMetadata { date, version } = dwn_ctx.stage0_metadata.rustfmt.as_ref()?;
+ let channel = format!("{version}-{date}");
+
+ let host = dwn_ctx.host_target;
+ let bin_root = dwn_ctx.out.join(host).join("rustfmt");
+ let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host));
+ let rustfmt_stamp = BuildStamp::new(&bin_root).with_prefix("rustfmt").add_stamp(channel);
+ if rustfmt_path.exists() && rustfmt_stamp.is_up_to_date() {
+ return Some(rustfmt_path);
+ }
+
+ download_component(
+ dwn_ctx,
+ DownloadSource::Dist,
+ format!("rustfmt-{version}-{build}.tar.xz", build = host.triple),
+ "rustfmt-preview",
+ date,
+ "rustfmt",
+ );
+
+ download_component(
+ dwn_ctx,
+ DownloadSource::Dist,
+ format!("rustc-{version}-{build}.tar.xz", build = host.triple),
+ "rustc",
+ date,
+ "rustfmt",
+ );
+
+ if should_fix_bins_and_dylibs(dwn_ctx.patch_binaries_for_nix, dwn_ctx.exec_ctx) {
+ fix_bin_or_dylib(dwn_ctx.out, &bin_root.join("bin").join("rustfmt"), dwn_ctx.exec_ctx);
+ fix_bin_or_dylib(dwn_ctx.out, &bin_root.join("bin").join("cargo-fmt"), dwn_ctx.exec_ctx);
+ let lib_dir = bin_root.join("lib");
+ for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
+ let lib = t!(lib);
+ if path_is_dylib(&lib.path()) {
+ fix_bin_or_dylib(dwn_ctx.out, &lib.path(), dwn_ctx.exec_ctx);
+ }
+ }
+ }
+
+ t!(rustfmt_stamp.write());
+ Some(rustfmt_path)
+}
+
+#[cfg(test)]
+pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>) {}
+
+#[cfg(not(test))]
+pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>) {
+ let dwn_ctx = dwn_ctx.as_ref();
+ dwn_ctx.exec_ctx.verbose(|| {
+ println!("downloading stage0 beta artifacts");
+ });
+
+ let date = dwn_ctx.stage0_metadata.compiler.date.clone();
+ let version = dwn_ctx.stage0_metadata.compiler.version.clone();
+ let extra_components = ["cargo"];
+ let sysroot = "stage0";
+ download_toolchain(
+ dwn_ctx,
+ &version,
+ sysroot,
+ &date,
+ &extra_components,
+ "stage0",
+ DownloadSource::Dist,
+ );
+}
+
+fn download_toolchain<'a>(
+ dwn_ctx: impl AsRef<DownloadContext<'a>>,
+ version: &str,
+ sysroot: &str,
+ stamp_key: &str,
+ extra_components: &[&str],
+ destination: &str,
+ mode: DownloadSource,
+) {
+ let dwn_ctx = dwn_ctx.as_ref();
+ let host = dwn_ctx.host_target.triple;
+ let bin_root = dwn_ctx.out.join(host).join(sysroot);
+ let rustc_stamp = BuildStamp::new(&bin_root).with_prefix("rustc").add_stamp(stamp_key);
+
+ if !bin_root.join("bin").join(exe("rustc", dwn_ctx.host_target)).exists()
+ || !rustc_stamp.is_up_to_date()
+ {
+ if bin_root.exists() {
+ t!(fs::remove_dir_all(&bin_root));
+ }
+ let filename = format!("rust-std-{version}-{host}.tar.xz");
+ let pattern = format!("rust-std-{host}");
+ download_component(dwn_ctx, mode.clone(), filename, &pattern, stamp_key, destination);
+ let filename = format!("rustc-{version}-{host}.tar.xz");
+ download_component(dwn_ctx, mode.clone(), filename, "rustc", stamp_key, destination);
+
+ for component in extra_components {
+ let filename = format!("{component}-{version}-{host}.tar.xz");
+ download_component(dwn_ctx, mode.clone(), filename, component, stamp_key, destination);
+ }
+
+ if should_fix_bins_and_dylibs(dwn_ctx.patch_binaries_for_nix, dwn_ctx.exec_ctx) {
+ fix_bin_or_dylib(dwn_ctx.out, &bin_root.join("bin").join("rustc"), dwn_ctx.exec_ctx);
+ fix_bin_or_dylib(dwn_ctx.out, &bin_root.join("bin").join("rustdoc"), dwn_ctx.exec_ctx);
+ fix_bin_or_dylib(
+ dwn_ctx.out,
+ &bin_root.join("libexec").join("rust-analyzer-proc-macro-srv"),
+ dwn_ctx.exec_ctx,
+ );
+ let lib_dir = bin_root.join("lib");
+ for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
+ let lib = t!(lib);
+ if path_is_dylib(&lib.path()) {
+ fix_bin_or_dylib(dwn_ctx.out, &lib.path(), dwn_ctx.exec_ctx);
+ }
+ }
+ }
+
+ t!(rustc_stamp.write());
+ }
+}
+
+pub(crate) fn remove(exec_ctx: &ExecutionContext, f: &Path) {
+ if exec_ctx.dry_run() {
+ return;
+ }
+ fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {f:?}"));
+}
+
+fn fix_bin_or_dylib(out: &Path, fname: &Path, exec_ctx: &ExecutionContext) {
+ assert_eq!(SHOULD_FIX_BINS_AND_DYLIBS.get(), Some(&true));
+ println!("attempting to patch {}", fname.display());
+
+ // Only build `.nix-deps` once.
+ static NIX_DEPS_DIR: OnceLock<PathBuf> = OnceLock::new();
+ let mut nix_build_succeeded = true;
+ let nix_deps_dir = NIX_DEPS_DIR.get_or_init(|| {
+ // Run `nix-build` to "build" each dependency (which will likely reuse
+ // the existing `/nix/store` copy, or at most download a pre-built copy).
+ //
+ // Importantly, we create a gc-root called `.nix-deps` in the `build/`
+ // directory, but still reference the actual `/nix/store` path in the rpath
+ // as it makes it significantly more robust against changes to the location of
+ // the `.nix-deps` location.
+ //
+ // bintools: Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
+ // zlib: Needed as a system dependency of `libLLVM-*.so`.
+ // patchelf: Needed for patching ELF binaries (see doc comment above).
+ let nix_deps_dir = out.join(".nix-deps");
+ const NIX_EXPR: &str = "
+ with (import <nixpkgs> {});
+ symlinkJoin {
+ name = \"rust-stage0-dependencies\";
+ paths = [
+ zlib
+ patchelf
+ stdenv.cc.bintools
+ ];
+ }
+ ";
+ nix_build_succeeded = command("nix-build")
+ .allow_failure()
+ .args([Path::new("-E"), Path::new(NIX_EXPR), Path::new("-o"), &nix_deps_dir])
+ .run_capture_stdout(exec_ctx)
+ .is_success();
+ nix_deps_dir
+ });
+ if !nix_build_succeeded {
+ return;
+ }
+
+ let mut patchelf = command(nix_deps_dir.join("bin/patchelf"));
+ patchelf.args(&[
+ OsString::from("--add-rpath"),
+ OsString::from(t!(fs::canonicalize(nix_deps_dir)).join("lib")),
+ ]);
+ if !path_is_dylib(fname) {
+ // Finally, set the correct .interp for binaries
+ let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker");
+ let dynamic_linker = t!(fs::read_to_string(dynamic_linker_path));
+ patchelf.args(["--set-interpreter", dynamic_linker.trim_end()]);
+ }
+ patchelf.arg(fname);
+ let _ = patchelf.allow_failure().run_capture_stdout(exec_ctx);
+}
+
+fn should_fix_bins_and_dylibs(
+ patch_binaries_for_nix: Option<bool>,
+ exec_ctx: &ExecutionContext,
+) -> bool {
+ let val = *SHOULD_FIX_BINS_AND_DYLIBS.get_or_init(|| {
+ let uname = command("uname").allow_failure().arg("-s").run_capture_stdout(exec_ctx);
+ if uname.is_failure() {
+ return false;
+ }
+ let output = uname.stdout();
+ if !output.starts_with("Linux") {
+ return false;
+ }
+ // If the user has asked binaries to be patched for Nix, then
+ // don't check for NixOS or `/lib`.
+ // NOTE: this intentionally comes after the Linux check:
+ // - patchelf only works with ELF files, so no need to run it on Mac or Windows
+ // - On other Unix systems, there is no stable syscall interface, so Nix doesn't manage the global libc.
+ if let Some(explicit_value) = patch_binaries_for_nix {
+ return explicit_value;
+ }
+
+ // Use `/etc/os-release` instead of `/etc/NIXOS`.
+ // The latter one does not exist on NixOS when using tmpfs as root.
+ let is_nixos = match File::open("/etc/os-release") {
+ Err(e) if e.kind() == ErrorKind::NotFound => false,
+ Err(e) => panic!("failed to access /etc/os-release: {e}"),
+ Ok(os_release) => BufReader::new(os_release).lines().any(|l| {
+ let l = l.expect("reading /etc/os-release");
+ matches!(l.trim(), "ID=nixos" | "ID='nixos'" | "ID=\"nixos\"")
+ }),
+ };
+ if !is_nixos {
+ let in_nix_shell = env::var("IN_NIX_SHELL");
+ if let Ok(in_nix_shell) = in_nix_shell {
+ eprintln!(
+ "The IN_NIX_SHELL environment variable is `{in_nix_shell}`; \
+ you may need to set `patch-binaries-for-nix=true` in bootstrap.toml"
+ );
+ }
+ }
+ is_nixos
+ });
+ if val {
+ eprintln!("INFO: You seem to be using Nix.");
+ }
+ val
+}
+
+fn download_component<'a>(
+ dwn_ctx: impl AsRef<DownloadContext<'a>>,
+ mode: DownloadSource,
+ filename: String,
+ prefix: &str,
+ key: &str,
+ destination: &str,
+) {
+ let dwn_ctx = dwn_ctx.as_ref();
+
+ if dwn_ctx.exec_ctx.dry_run() {
+ return;
+ }
+
+ let cache_dst =
+ dwn_ctx.bootstrap_cache_path.as_ref().cloned().unwrap_or_else(|| dwn_ctx.out.join("cache"));
+
+ let cache_dir = cache_dst.join(key);
+ if !cache_dir.exists() {
+ t!(fs::create_dir_all(&cache_dir));
+ }
+
+ let bin_root = dwn_ctx.out.join(dwn_ctx.host_target).join(destination);
+ let tarball = cache_dir.join(&filename);
+ let (base_url, url, should_verify) = match mode {
+ DownloadSource::CI => {
+ let dist_server = if dwn_ctx.llvm_assertions {
+ dwn_ctx.stage0_metadata.config.artifacts_with_llvm_assertions_server.clone()
+ } else {
+ dwn_ctx.stage0_metadata.config.artifacts_server.clone()
+ };
+ let url = format!(
+ "{}/{filename}",
+ key.strip_suffix(&format!("-{}", dwn_ctx.llvm_assertions)).unwrap()
+ );
+ (dist_server, url, false)
+ }
+ DownloadSource::Dist => {
+ let dist_server = env::var("RUSTUP_DIST_SERVER")
+ .unwrap_or(dwn_ctx.stage0_metadata.config.dist_server.to_string());
+ // NOTE: make `dist` part of the URL because that's how it's stored in src/stage0
+ (dist_server, format!("dist/{key}/{filename}"), true)
+ }
+ };
+
+ // For the stage0 compiler, put special effort into ensuring the checksums are valid.
+ let checksum = if should_verify {
+ let error = format!(
+ "src/stage0 doesn't contain a checksum for {url}. \
+ Pre-built artifacts might not be available for this \
+ target at this time, see https://doc.rust-lang.org/nightly\
+ /rustc/platform-support.html for more information."
+ );
+ let sha256 = dwn_ctx.stage0_metadata.checksums_sha256.get(&url).expect(&error);
+ if tarball.exists() {
+ if verify(dwn_ctx.exec_ctx, &tarball, sha256) {
+ unpack(dwn_ctx.exec_ctx, &tarball, &bin_root, prefix);
+ return;
+ } else {
+ dwn_ctx.exec_ctx.verbose(|| {
+ println!(
+ "ignoring cached file {} due to failed verification",
+ tarball.display()
+ )
+ });
+ remove(dwn_ctx.exec_ctx, &tarball);
+ }
+ }
+ Some(sha256)
+ } else if tarball.exists() {
+ unpack(dwn_ctx.exec_ctx, &tarball, &bin_root, prefix);
+ return;
+ } else {
+ None
+ };
+
+ let mut help_on_error = "";
+ if destination == "ci-rustc" {
+ help_on_error = "ERROR: failed to download pre-built rustc from CI
+
+NOTE: old builds get deleted after a certain time
+HELP: if trying to compile an old commit of rustc, disable `download-rustc` in bootstrap.toml:
+
+[rust]
+download-rustc = false
+";
+ }
+ download_file(dwn_ctx, &format!("{base_url}/{url}"), &tarball, help_on_error);
+ if let Some(sha256) = checksum
+ && !verify(dwn_ctx.exec_ctx, &tarball, sha256)
+ {
+ panic!("failed to verify {}", tarball.display());
+ }
+
+ unpack(dwn_ctx.exec_ctx, &tarball, &bin_root, prefix);
+}
+
+pub(crate) fn verify(exec_ctx: &ExecutionContext, path: &Path, expected: &str) -> bool {
+ use sha2::Digest;
+
+ exec_ctx.verbose(|| {
+ println!("verifying {}", path.display());
+ });
+
+ if exec_ctx.dry_run() {
+ return false;
+ }
+
+ let mut hasher = sha2::Sha256::new();
+
+ let file = t!(File::open(path));
+ let mut reader = BufReader::new(file);
+
+ loop {
+ let buffer = t!(reader.fill_buf());
+ let l = buffer.len();
+ // break if EOF
+ if l == 0 {
+ break;
+ }
+ hasher.update(buffer);
+ reader.consume(l);
+ }
+
+ let checksum = hex_encode(hasher.finalize().as_slice());
+ let verified = checksum == expected;
+
+ if !verified {
+ println!(
+ "invalid checksum: \n\
+ found: {checksum}\n\
+ expected: {expected}",
+ );
+ }
+
+ verified
+}
+
+fn unpack(exec_ctx: &ExecutionContext, tarball: &Path, dst: &Path, pattern: &str) {
+ eprintln!("extracting {} to {}", tarball.display(), dst.display());
+ if !dst.exists() {
+ t!(fs::create_dir_all(dst));
+ }
+
+ // `tarball` ends with `.tar.xz`; strip that suffix
+ // example: `rust-dev-nightly-x86_64-unknown-linux-gnu`
+ let uncompressed_filename =
+ Path::new(tarball.file_name().expect("missing tarball filename")).file_stem().unwrap();
+ let directory_prefix = Path::new(Path::new(uncompressed_filename).file_stem().unwrap());
+
+ // decompress the file
+ let data = t!(File::open(tarball), format!("file {} not found", tarball.display()));
+ let decompressor = XzDecoder::new(BufReader::new(data));
+
+ let mut tar = tar::Archive::new(decompressor);
+
+ let is_ci_rustc = dst.ends_with("ci-rustc");
+ let is_ci_llvm = dst.ends_with("ci-llvm");
+
+ // `compile::Sysroot` needs to know the contents of the `rustc-dev` tarball to avoid adding
+ // it to the sysroot unless it was explicitly requested. But parsing the 100 MB tarball is slow.
+ // Cache the entries when we extract it so we only have to read it once.
+ let mut recorded_entries = if is_ci_rustc { recorded_entries(dst, pattern) } else { None };
+
+ for member in t!(tar.entries()) {
+ let mut member = t!(member);
+ let original_path = t!(member.path()).into_owned();
+ // skip the top-level directory
+ if original_path == directory_prefix {
+ continue;
+ }
+ let mut short_path = t!(original_path.strip_prefix(directory_prefix));
+ let is_builder_config = short_path.to_str() == Some(BUILDER_CONFIG_FILENAME);
+
+ if !(short_path.starts_with(pattern) || ((is_ci_rustc || is_ci_llvm) && is_builder_config))
+ {
+ continue;
+ }
+ short_path = short_path.strip_prefix(pattern).unwrap_or(short_path);
+ let dst_path = dst.join(short_path);
+
+ exec_ctx.verbose(|| {
+ println!("extracting {} to {}", original_path.display(), dst.display());
+ });
+
+ if !t!(member.unpack_in(dst)) {
+ panic!("path traversal attack ??");
+ }
+ if let Some(record) = &mut recorded_entries {
+ t!(writeln!(record, "{}", short_path.to_str().unwrap()));
+ }
+ let src_path = dst.join(original_path);
+ if src_path.is_dir() && dst_path.exists() {
+ continue;
+ }
+ t!(move_file(src_path, dst_path));
+ }
+ let dst_dir = dst.join(directory_prefix);
+ if dst_dir.exists() {
+ t!(fs::remove_dir_all(&dst_dir), format!("failed to remove {}", dst_dir.display()));
+ }
+}
+
+fn download_file<'a>(
+ dwn_ctx: impl AsRef<DownloadContext<'a>>,
+ url: &str,
+ dest_path: &Path,
+ help_on_error: &str,
+) {
+ let dwn_ctx = dwn_ctx.as_ref();
+
+ dwn_ctx.exec_ctx.verbose(|| {
+ println!("download {url}");
+ });
+ // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
+ let tempfile = tempdir(dwn_ctx.out).join(dest_path.file_name().unwrap());
+ // While bootstrap itself only supports http and https downloads, downstream forks might
+ // need to download components from other protocols. The match allows them adding more
+ // protocols without worrying about merge conflicts if we change the HTTP implementation.
+ match url.split_once("://").map(|(proto, _)| proto) {
+ Some("http") | Some("https") => download_http_with_retries(
+ dwn_ctx.host_target,
+ dwn_ctx.is_running_on_ci,
+ dwn_ctx.exec_ctx,
+ &tempfile,
+ url,
+ help_on_error,
+ ),
+ Some(other) => panic!("unsupported protocol {other} in {url}"),
+ None => panic!("no protocol in {url}"),
+ }
+ t!(move_file(&tempfile, dest_path), format!("failed to rename {tempfile:?} to {dest_path:?}"));
+}
+
+/// Create a temporary directory in `out` and return its path.
+///
+/// NOTE: this temporary directory is shared between all steps;
+/// if you need an empty directory, create a new subdirectory inside it.
+pub(crate) fn tempdir(out: &Path) -> PathBuf {
+ let tmp = out.join("tmp");
+ t!(fs::create_dir_all(&tmp));
+ tmp
+}
+
+fn download_http_with_retries(
+ host_target: TargetSelection,
+ is_running_on_ci: bool,
+ exec_ctx: &ExecutionContext,
+ tempfile: &Path,
+ url: &str,
+ help_on_error: &str,
+) {
+ println!("downloading {url}");
+ // Try curl. If that fails and we are on windows, fallback to PowerShell.
+ // options should be kept in sync with
+ // src/bootstrap/src/core/download.rs
+ // for consistency
+ let mut curl = command("curl").allow_failure();
+ curl.args([
+ // follow redirect
+ "--location",
+ // timeout if speed is < 10 bytes/sec for > 30 seconds
+ "--speed-time",
+ "30",
+ "--speed-limit",
+ "10",
+ // timeout if cannot connect within 30 seconds
+ "--connect-timeout",
+ "30",
+ // output file
+ "--output",
+ tempfile.to_str().unwrap(),
+ // if there is an error, don't restart the download,
+ // instead continue where it left off.
+ "--continue-at",
+ "-",
+ // retry up to 3 times. note that this means a maximum of 4
+ // attempts will be made, since the first attempt isn't a *re*try.
+ "--retry",
+ "3",
+ // show errors, even if --silent is specified
+ "--show-error",
+ // set timestamp of downloaded file to that of the server
+ "--remote-time",
+ // fail on non-ok http status
+ "--fail",
+ ]);
+ // Don't print progress in CI; the \r wrapping looks bad and downloads don't take long enough for progress to be useful.
+ if is_running_on_ci {
+ curl.arg("--silent");
+ } else {
+ curl.arg("--progress-bar");
+ }
+ // --retry-all-errors was added in 7.71.0, don't use it if curl is old.
+ if curl_version(exec_ctx) >= semver::Version::new(7, 71, 0) {
+ curl.arg("--retry-all-errors");
+ }
+ curl.arg(url);
+ if !curl.run(exec_ctx) {
+ if host_target.contains("windows-msvc") {
+ eprintln!("Fallback to PowerShell");
+ for _ in 0..3 {
+ let powershell = command("PowerShell.exe").allow_failure().args([
+ "/nologo",
+ "-Command",
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
+ &format!(
+ "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')",
+ url, tempfile.to_str().expect("invalid UTF-8 not supported with powershell downloads"),
+ ),
+ ]).run_capture_stdout(exec_ctx);
+
+ if powershell.is_failure() {
+ return;
+ }
+
+ eprintln!("\nspurious failure, trying again");
+ }
+ }
+ if !help_on_error.is_empty() {
+ eprintln!("{help_on_error}");
+ }
+ crate::exit!(1);
+ }
+}
+
+fn curl_version(exec_ctx: &ExecutionContext) -> semver::Version {
+ let mut curl = command("curl");
+ curl.arg("-V");
+ let curl = curl.run_capture_stdout(exec_ctx);
+ if curl.is_failure() {
+ return semver::Version::new(1, 0, 0);
+ }
+ let output = curl.stdout();
+ extract_curl_version(output)
+}
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index b39d464..15e04f5 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -338,12 +338,6 @@ pub fn check(build: &mut Build) {
// Make sure musl-root is valid.
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.config.is_host_target(*target) {
- let target = build.config.target_config.entry(*target).or_default();
- target.musl_root = Some("/usr".into());
- }
match build.musl_libdir(*target) {
Some(libdir) => {
if fs::metadata(libdir.join("libc.a")).is_err() {
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 63aab4d..51a84ad 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -1329,23 +1329,33 @@ fn crt_static(&self, target: TargetSelection) -> Option<bool> {
}
}
- /// Returns the "musl root" for this `target`, if defined
+ /// Returns the "musl root" for this `target`, if defined.
+ ///
+ /// If this is a native target (host is also musl) and no musl-root is given,
+ /// it falls back to the system toolchain in /usr.
fn musl_root(&self, target: TargetSelection) -> Option<&Path> {
- self.config
+ let configured_root = self
+ .config
.target_config
.get(&target)
.and_then(|t| t.musl_root.as_ref())
.or(self.config.musl_root.as_ref())
- .map(|p| &**p)
+ .map(|p| &**p);
+
+ if self.config.is_host_target(target) && configured_root.is_none() {
+ Some(Path::new("/usr"))
+ } else {
+ configured_root
+ }
}
/// Returns the "musl libdir" for this `target`.
fn musl_libdir(&self, target: TargetSelection) -> Option<PathBuf> {
- let t = self.config.target_config.get(&target)?;
- if let libdir @ Some(_) = &t.musl_libdir {
- return libdir.clone();
- }
- self.musl_root(target).map(|root| root.join("lib"))
+ self.config
+ .target_config
+ .get(&target)
+ .and_then(|t| t.musl_libdir.clone())
+ .or_else(|| self.musl_root(target).map(|root| root.join("lib")))
}
/// Returns the `lib` directory for the WASI target specified, if
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index f802640..4b0c482 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -439,7 +439,7 @@ pub fn human_readable_changes(changes: &[ChangeInfo]) -> String {
ChangeInfo {
change_id: 143255,
severity: ChangeSeverity::Warning,
- summary: "`llvm.lld` is no longer enabled by default for the dist profile.",
+ summary: "`rust.lld` is no longer enabled by default for the dist profile.",
},
ChangeInfo {
change_id: 143251,
diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs
index 21c7fc8..777c860 100644
--- a/src/bootstrap/src/utils/proc_macro_deps.rs
+++ b/src/bootstrap/src/utils/proc_macro_deps.rs
@@ -3,6 +3,7 @@
/// See <https://github.com/rust-lang/rust/issues/134863>
pub static CRATES: &[&str] = &[
// tidy-alphabetical-start
+ "allocator-api2",
"annotate-snippets",
"anstyle",
"askama_parser",
@@ -16,13 +17,17 @@
"darling_core",
"derive_builder_core",
"digest",
+ "equivalent",
"fluent-bundle",
"fluent-langneg",
"fluent-syntax",
"fnv",
+ "foldhash",
"generic-array",
+ "hashbrown",
"heck",
"ident_case",
+ "indexmap",
"intl-memoizer",
"intl_pluralrules",
"libc",
diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs
index 9c6b4a7..9428e22 100644
--- a/src/bootstrap/src/utils/shared_helpers.rs
+++ b/src/bootstrap/src/utils/shared_helpers.rs
@@ -1,14 +1,18 @@
//! This module serves two purposes:
-//! 1. It is part of the `utils` module and used in other parts of bootstrap.
-//! 2. It is embedded inside bootstrap shims to avoid a dependency on the bootstrap library.
-//! Therefore, this module should never use any other bootstrap module. This reduces binary
-//! size and improves compilation time by minimizing linking time.
+//!
+//! 1. It is part of the `utils` module and used in other parts of bootstrap.
+//! 2. It is embedded inside bootstrap shims to avoid a dependency on the bootstrap library.
+//! Therefore, this module should never use any other bootstrap module. This reduces binary size
+//! and improves compilation time by minimizing linking time.
+
+// # Note on tests
+//
+// If we were to declare a tests submodule here, the shim binaries that include this module via
+// `#[path]` would fail to find it, which breaks `./x check bootstrap`. So instead the unit tests
+// for this module are in `super::tests::shared_helpers_tests`.
#![allow(dead_code)]
-#[cfg(test)]
-mod tests;
-
use std::env;
use std::ffi::OsString;
use std::fs::OpenOptions;
@@ -16,10 +20,6 @@
use std::process::Command;
use std::str::FromStr;
-// If we were to declare a tests submodule here, the shim binaries that include this
-// module via `#[path]` would fail to find it, which breaks `./x check bootstrap`.
-// So instead the unit tests for this module are in `super::tests::shared_helpers_tests`.
-
/// Returns the environment variable which the dynamic library lookup path
/// resides in for this platform.
pub fn dylib_path_var() -> &'static str {
diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs
index ec87e71..983680b 100644
--- a/src/bootstrap/src/utils/tests/mod.rs
+++ b/src/bootstrap/src/utils/tests/mod.rs
@@ -12,6 +12,10 @@
pub mod git;
+// Note: tests for `shared_helpers` is separate here, as otherwise shim binaries that include the
+// `shared_helpers` via `#[path]` would fail to find it, breaking `./x check bootstrap`.
+mod shared_helpers_tests;
+
/// Holds temporary state of a bootstrap test.
/// Right now it is only used to redirect the build directory of the bootstrap
/// invocation, in the future it would be great if we could actually execute
diff --git a/src/bootstrap/src/utils/shared_helpers/tests.rs b/src/bootstrap/src/utils/tests/shared_helpers_tests.rs
similarity index 73%
rename from src/bootstrap/src/utils/shared_helpers/tests.rs
rename to src/bootstrap/src/utils/tests/shared_helpers_tests.rs
index 559e9f7..c486e65 100644
--- a/src/bootstrap/src/utils/shared_helpers/tests.rs
+++ b/src/bootstrap/src/utils/tests/shared_helpers_tests.rs
@@ -1,3 +1,10 @@
+//! The `shared_helpers` module can't have its own tests submodule, because that would cause
+//! problems for the shim binaries that include it via `#[path]`, so instead those unit tests live
+//! here.
+//!
+//! To prevent tidy from complaining about this file not being named `tests.rs`, it lives inside a
+//! submodule directory named `tests`.
+
use crate::utils::shared_helpers::parse_value_from_args;
#[test]
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index e1d83d3..0855ea2 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -81,9 +81,9 @@
COPY host-x86_64/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh
-RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz | \
+RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-27/wasi-sdk-27.0-x86_64-linux.tar.gz | \
tar -xz
-ENV WASI_SDK_PATH=/tmp/wasi-sdk-25.0-x86_64-linux
+ENV WASI_SDK_PATH=/tmp/wasi-sdk-27.0-x86_64-linux
COPY scripts/freebsd-toolchain.sh /tmp/
RUN /tmp/freebsd-toolchain.sh i686
diff --git a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile
index d3c3cd1..f7d51fb 100644
--- a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile
+++ b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile
@@ -40,6 +40,7 @@
# We disable optimized compiler built-ins because that requires a C toolchain for the target.
# We also skip the x86_64-unknown-linux-gnu target as it is well-tested by other jobs.
ENV SCRIPT \
+ python3 ../x.py check bootstrap && \
/scripts/check-default-config-profiles.sh && \
python3 ../x.py build src/tools/build-manifest && \
python3 ../x.py test --stage 0 src/tools/compiletest && \
diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile
index 4d09bea..82a820c 100644
--- a/src/ci/docker/host-x86_64/test-various/Dockerfile
+++ b/src/ci/docker/host-x86_64/test-various/Dockerfile
@@ -40,9 +40,9 @@
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz | \
+RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-27/wasi-sdk-27.0-x86_64-linux.tar.gz | \
tar -xz
-ENV WASI_SDK_PATH=/wasi-sdk-25.0-x86_64-linux
+ENV WASI_SDK_PATH=/wasi-sdk-27.0-x86_64-linux
ENV RUST_CONFIGURE_ARGS \
--musl-root-x86_64=/usr/local/x86_64-linux-musl \
@@ -79,7 +79,6 @@
CXX_x86_64_unknown_linux_musl=x86_64-linux-musl-g++
ENV MUSL_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $MUSL_TARGETS
-COPY host-x86_64/test-various/uefi_qemu_test /uefi_qemu_test
ENV UEFI_TARGETS=aarch64-unknown-uefi,i686-unknown-uefi,x86_64-unknown-uefi \
CC_aarch64_unknown_uefi=clang-11 \
CXX_aarch64_unknown_uefi=clang++-11 \
@@ -88,6 +87,8 @@
CC_x86_64_unknown_uefi=clang-11 \
CXX_x86_64_unknown_uefi=clang++-11
ENV UEFI_SCRIPT python3 /checkout/x.py --stage 2 build --host='' --target $UEFI_TARGETS && \
- python3 -u /uefi_qemu_test/run.py
+ python3 /checkout/x.py --stage 2 test tests/run-make/uefi-qemu/rmake.rs --target aarch64-unknown-uefi && \
+ python3 /checkout/x.py --stage 2 test tests/run-make/uefi-qemu/rmake.rs --target i686-unknown-uefi && \
+ python3 /checkout/x.py --stage 2 test tests/run-make/uefi-qemu/rmake.rs --target x86_64-unknown-uefi
ENV SCRIPT $WASM_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT && $UEFI_SCRIPT
diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py
deleted file mode 100755
index 4f87738..0000000
--- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py
+++ /dev/null
@@ -1,140 +0,0 @@
-#!/usr/bin/env python3
-
-import os
-import shutil
-import subprocess
-import sys
-import tempfile
-
-from pathlib import Path
-
-TARGET_AARCH64 = "aarch64-unknown-uefi"
-TARGET_I686 = "i686-unknown-uefi"
-TARGET_X86_64 = "x86_64-unknown-uefi"
-
-
-def run(*cmd, capture=False, check=True, env=None, timeout=None):
- """Print and run a command, optionally capturing the output."""
- cmd = [str(p) for p in cmd]
- print(" ".join(cmd))
- return subprocess.run(
- cmd, capture_output=capture, check=check, env=env, text=True, timeout=timeout
- )
-
-
-def build_and_run(tmp_dir, target):
- if target == TARGET_AARCH64:
- boot_file_name = "bootaa64.efi"
- ovmf_dir = Path("/usr/share/AAVMF")
- ovmf_code = "AAVMF_CODE.fd"
- ovmf_vars = "AAVMF_VARS.fd"
- qemu = "qemu-system-aarch64"
- machine = "virt"
- cpu = "cortex-a72"
- elif target == TARGET_I686:
- boot_file_name = "bootia32.efi"
- ovmf_dir = Path("/usr/share/OVMF")
- ovmf_code = "OVMF32_CODE_4M.secboot.fd"
- ovmf_vars = "OVMF32_VARS_4M.fd"
- # The i686 target intentionally uses 64-bit qemu; the important
- # difference is that the OVMF code provides a 32-bit environment.
- qemu = "qemu-system-x86_64"
- machine = "q35"
- cpu = "qemu64"
- elif target == TARGET_X86_64:
- boot_file_name = "bootx64.efi"
- ovmf_dir = Path("/usr/share/OVMF")
- ovmf_code = "OVMF_CODE.fd"
- ovmf_vars = "OVMF_VARS.fd"
- qemu = "qemu-system-x86_64"
- machine = "q35"
- cpu = "qemu64"
- else:
- raise KeyError("invalid target")
-
- host_artifacts = Path("/checkout/obj/build/x86_64-unknown-linux-gnu")
- stage0 = host_artifacts / "stage0/bin"
- stage2 = host_artifacts / "stage2/bin"
-
- env = dict(os.environ)
- env["PATH"] = "{}:{}:{}".format(stage2, stage0, env["PATH"])
-
- # Copy the test create into `tmp_dir`.
- test_crate = Path(tmp_dir) / "uefi_qemu_test"
- shutil.copytree("/uefi_qemu_test", test_crate)
-
- # Build the UEFI executable.
- run(
- "cargo",
- "build",
- "--manifest-path",
- test_crate / "Cargo.toml",
- "--target",
- target,
- env=env,
- )
-
- # Create a mock EFI System Partition in a subdirectory.
- esp = test_crate / "esp"
- boot = esp / "efi/boot"
- os.makedirs(boot, exist_ok=True)
-
- # Copy the executable into the ESP.
- src_exe_path = test_crate / "target" / target / "debug/uefi_qemu_test.efi"
- shutil.copy(src_exe_path, boot / boot_file_name)
- print(src_exe_path, boot / boot_file_name)
-
- # Select the appropriate EDK2 build.
- ovmf_code = ovmf_dir / ovmf_code
- ovmf_vars = ovmf_dir / ovmf_vars
-
- # Make a writable copy of the vars file. aarch64 doesn't boot
- # correctly with read-only vars.
- ovmf_rw_vars = Path(tmp_dir) / "vars.fd"
- shutil.copy(ovmf_vars, ovmf_rw_vars)
-
- # Run the executable in QEMU and capture the output.
- output = run(
- qemu,
- "-machine",
- machine,
- "-cpu",
- cpu,
- "-display",
- "none",
- "-serial",
- "stdio",
- "-drive",
- f"if=pflash,format=raw,readonly=on,file={ovmf_code}",
- "-drive",
- f"if=pflash,format=raw,readonly=off,file={ovmf_rw_vars}",
- "-drive",
- f"format=raw,file=fat:rw:{esp}",
- capture=True,
- check=True,
- # Set a timeout to kill the VM in case something goes wrong.
- timeout=60,
- ).stdout
-
- if "Hello World!" in output:
- print("VM produced expected output")
- else:
- print("unexpected VM output:")
- print("---start---")
- print(output)
- print("---end---")
- sys.exit(1)
-
-
-def main():
- targets = [TARGET_AARCH64, TARGET_I686, TARGET_X86_64]
-
- for target in targets:
- # Create a temporary directory so that we have a writeable
- # workspace.
- with tempfile.TemporaryDirectory() as tmp_dir:
- build_and_run(tmp_dir, target)
-
-
-if __name__ == "__main__":
- main()
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 0116884..0e1edfe 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -491,7 +491,7 @@
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
NO_OVERFLOW_CHECKS: 1
- <<: *job-macos
+ <<: *job-macos-m1
- name: x86_64-apple-1
env:
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index f6b7efe..b631041 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-460259d14de0274b97b8801e08cb2fe5f16fdac5
+2b5e239c6b86cde974b0ef0f8e23754fb08ff3c5
diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md
index 651e292..e3c0d50 100644
--- a/src/doc/rustc-dev-guide/src/SUMMARY.md
+++ b/src/doc/rustc-dev-guide/src/SUMMARY.md
@@ -53,7 +53,8 @@
- [Walkthrough: a typical contribution](./walkthrough.md)
- [Implementing new language features](./implementing_new_features.md)
- [Stability attributes](./stability.md)
-- [Stabilizing Features](./stabilization_guide.md)
+- [Stabilizing language features](./stabilization_guide.md)
+ - [Stabilization report template](./stabilization_report_template.md)
- [Feature Gates](./feature-gates.md)
- [Coding conventions](./conventions.md)
- [Procedures for breaking changes](./bug-fix-procedure.md)
diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md
index ecc65b2..5fb7eee 100644
--- a/src/doc/rustc-dev-guide/src/external-repos.md
+++ b/src/doc/rustc-dev-guide/src/external-repos.md
@@ -40,27 +40,24 @@
* `portable-simd` ([sync script](https://github.com/rust-lang/portable-simd/blob/master/subtree-sync.sh))
* `rustfmt`
* `rustc_codegen_cranelift` ([sync script](https://github.com/rust-lang/rustc_codegen_cranelift/blob/113af154d459e41b3dc2c5d7d878e3d3a8f33c69/scripts/rustup.sh#L7))
-* Using the [josh] tool
- * `miri` ([sync guide](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#advanced-topic-syncing-with-the-rustc-repo))
- * `rust-analyzer` ([sync script](https://github.com/rust-lang/rust-analyzer/blob/2e13684be123eca7181aa48e043e185d8044a84a/xtask/src/release.rs#L147))
- * `rustc-dev-guide` ([josh sync](#synchronizing-a-josh-subtree))
- * `compiler-builtins` ([josh sync](#synchronizing-a-josh-subtree))
- * `stdarch` ([josh sync](#synchronizing-a-josh-subtree))
+* Using the [josh](#synchronizing-a-josh-subtree) tool
+ * `miri`
+ * `rust-analyzer`
+ * `rustc-dev-guide`
+ * `compiler-builtins`
+ * `stdarch`
### Josh subtrees
-The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. Specific tooling is required to work with josh; you can check out the `miri` or `rust-analyzer` scripts linked above for inspiration. We provide a helper [`rustc-josh-sync`][josh-sync] tool to help with the synchronization, described [below](#synchronizing-a-josh-subtree).
+The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. Specific tooling is required to work with josh. We provide a helper [`rustc-josh-sync`][josh-sync] tool to help with the synchronization, described [below](#synchronizing-a-josh-subtree).
### Synchronizing a Josh subtree
We use a dedicated tool called [`rustc-josh-sync`][josh-sync] for performing Josh subtree updates.
-Currently, we are migrating Josh repositories to it. So far, it is used in:
+The commands below can be used for all our Josh subtrees, although note that `miri`
+requires you to perform some [additional steps](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#advanced-topic-syncing-with-the-rustc-repo) during pulls.
-- compiler-builtins
-- rustc-dev-guide
-- stdarch
-
-To install the tool:
+You can install the tool using the following command:
```
cargo install --locked --git https://github.com/rust-lang/josh-sync
```
@@ -80,6 +77,9 @@
#### Performing push
+> NOTE:
+> Before you proceed, look at some guidance related to Git [on josh-sync README].
+
1) Run the push command to create a branch named `<branch-name>` in a `rustc` fork under the `<gh-username>` account
```
rustc-josh-sync push <branch-name> <gh-username>
@@ -173,3 +173,4 @@
[Toolstate chapter]: https://forge.rust-lang.org/infra/toolstate.html
[josh]: https://josh-project.github.io/josh/intro.html
[josh-sync]: https://github.com/rust-lang/josh-sync
+[on josh-sync README]: https://github.com/rust-lang/josh-sync#git-peculiarities
diff --git a/src/doc/rustc-dev-guide/src/implementing_new_features.md b/src/doc/rustc-dev-guide/src/implementing_new_features.md
index 5d0e875..76cf238 100644
--- a/src/doc/rustc-dev-guide/src/implementing_new_features.md
+++ b/src/doc/rustc-dev-guide/src/implementing_new_features.md
@@ -2,145 +2,91 @@
<!-- toc -->
-When you want to implement a new significant feature in the compiler,
-you need to go through this process to make sure everything goes
-smoothly.
+When you want to implement a new significant feature in the compiler, you need to go through this process to make sure everything goes smoothly.
-**NOTE: this section is for *language* features, not *library* features,
-which use [a different process].**
+**NOTE: This section is for *language* features, not *library* features, which use [a different process].**
-See also [the Rust Language Design Team's procedures][lang-propose] for
-proposing changes to the language.
+See also [the Rust Language Design Team's procedures][lang-propose] for proposing changes to the language.
[a different process]: ./stability.md
[lang-propose]: https://lang-team.rust-lang.org/how_to/propose.html
## The @rfcbot FCP process
-When the change is small and uncontroversial, then it can be done
-with just writing a PR and getting an r+ from someone who knows that
-part of the code. However, if the change is potentially controversial,
-it would be a bad idea to push it without consensus from the rest
-of the team (both in the "distributed system" sense to make sure
-you don't break anything you don't know about, and in the social
-sense to avoid PR fights).
+When the change is small, uncontroversial, non-breaking, and does not affect the stable language in any user-observable ways or add any new unstable features, then it can be done with just writing a PR and getting an r+ from someone who knows that part of the code. However, if not, more must be done. Even for compiler-internal work, it would be a bad idea to push a controversial change without consensus from the rest of the team (both in the "distributed system" sense to make sure you don't break anything you don't know about, and in the social sense to avoid PR fights).
-If such a change seems to be too small to require a full formal RFC process
-(e.g., a small standard library addition, a big refactoring of the code, a
-"technically-breaking" change, or a "big bugfix" that basically amounts to a
-small feature) but is still too controversial or big to get by with a single r+,
-you can propose a final comment period (FCP). Or, if you're not on the relevant
-team (and thus don't have @rfcbot permissions), ask someone who is to start one;
-unless they have a concern themselves, they should.
+For changes that need the consensus of a team, we us the process of proposing a final comment period (FCP). If you're not on the relevant team (and thus don't have @rfcbot permissions), ask someone who is to start one; unless they have a concern themselves, they should.
-Again, the FCP process is only needed if you need consensus – if you
-don't think anyone would have a problem with your change, it's OK to
-get by with only an r+. For example, it is OK to add or modify
-unstable command-line flags or attributes without an FCP for
-compiler development or standard library use, as long as you don't
-expect them to be in wide use in the nightly ecosystem.
-Some teams have lighter weight processes that they use in scenarios
-like this; for example, the compiler team recommends
-filing a Major Change Proposal ([MCP][mcp]) as a lightweight way to
-garner support and feedback without requiring full consensus.
+The FCP process is only needed if you need consensus – if no processes require consensus for your change and you don't think anyone would have a problem with it, it's OK to rely on only an r+. For example, it is OK to add or modify unstable command-line flags or attributes in the reserved compiler-internal `rustc_` namespace without an FCP for compiler development or standard library use, as long as you don't expect them to be in wide use in the nightly ecosystem. Some teams have lighter weight processes that they use in scenarios like this; for example, the compiler team recommends filing a Major Change Proposal ([MCP][mcp]) as a lightweight way to garner support and feedback without requiring full consensus.
[mcp]: https://forge.rust-lang.org/compiler/proposals-and-stabilization.html#how-do-i-submit-an-mcp
-You don't need to have the implementation fully ready for r+ to propose an FCP,
-but it is generally a good idea to have at least a proof
-of concept so that people can see what you are talking about.
+You don't need to have the implementation fully ready for r+ to propose an FCP, but it is generally a good idea to have at least a proof of concept so that people can see what you are talking about.
-When an FCP is proposed, it requires all members of the team to sign off the
-FCP. After they all do so, there's a 10-day-long "final comment period" (hence
-the name) where everybody can comment, and if no concerns are raised, the
-PR/issue gets FCP approval.
+When an FCP is proposed, it requires all members of the team to sign off on the FCP. After they all do so, there's a 10-day-long "final comment period" (hence the name) where everybody can comment, and if no concerns are raised, the PR/issue gets FCP approval.
## The logistics of writing features
-There are a few "logistic" hoops you might need to go through in
-order to implement a feature in a working way.
+There are a few "logistical" hoops you might need to go through in order to implement a feature in a working way.
### Warning Cycles
-In some cases, a feature or bugfix might break some existing programs
-in some edge cases. In that case, you might want to do a crater run
-to assess the impact and possibly add a future-compatibility lint,
-similar to those used for
-[edition-gated lints](diagnostics.md#edition-gated-lints).
+In some cases, a feature or bugfix might break some existing programs in some edge cases. In that case, you'll want to do a crater run to assess the impact and possibly add a future-compatibility lint, similar to those used for [edition-gated lints](diagnostics.md#edition-gated-lints).
### Stability
-We [value the stability of Rust]. Code that works and runs on stable
-should (mostly) not break. Because of that, we don't want to release
-a feature to the world with only team consensus and code review -
-we want to gain real-world experience on using that feature on nightly,
-and we might want to change the feature based on that experience.
+We [value the stability of Rust]. Code that works and runs on stable should (mostly) not break. Because of that, we don't want to release a feature to the world with only team consensus and code review - we want to gain real-world experience on using that feature on nightly, and we might want to change the feature based on that experience.
-To allow for that, we must make sure users don't accidentally depend
-on that new feature - otherwise, especially if experimentation takes
-time or is delayed and the feature takes the trains to stable,
-it would end up de facto stable and we'll not be able to make changes
-in it without breaking people's code.
+To allow for that, we must make sure users don't accidentally depend on that new feature - otherwise, especially if experimentation takes time or is delayed and the feature takes the trains to stable, it would end up de facto stable and we'll not be able to make changes in it without breaking people's code.
-The way we do that is that we make sure all new features are feature
-gated - they can't be used without enabling a feature gate
-(`#[feature(foo)]`), which can't be done in a stable/beta compiler.
-See the [stability in code] section for the technical details.
+The way we do that is that we make sure all new features are feature gated - they can't be used without enabling a feature gate (`#[feature(foo)]`), which can't be done in a stable/beta compiler. See the [stability in code] section for the technical details.
-Eventually, after we gain enough experience using the feature,
-make the necessary changes, and are satisfied, we expose it to
-the world using the stabilization process described [here].
-Until then, the feature is not set in stone: every part of the
-feature can be changed, or the feature might be completely
-rewritten or removed. Features are not supposed to gain tenure
-by being unstable and unchanged for a year.
+Eventually, after we gain enough experience using the feature, make the necessary changes, and are satisfied, we expose it to the world using the stabilization process described [here]. Until then, the feature is not set in stone: every part of the feature can be changed, or the feature might be completely rewritten or removed. Features do not gain tenure by being unstable and unchanged for long periods of time.
### Tracking Issues
-To keep track of the status of an unstable feature, the
-experience we get while using it on nightly, and of the
-concerns that block its stabilization, every feature-gate
-needs a tracking issue. General discussions about the feature should be done on the tracking issue.
+To keep track of the status of an unstable feature, the experience we get while using it on
+nightly, and of the concerns that block its stabilization, every feature-gate needs a tracking
+issue. When creating issues and PRs related to the feature, reference this tracking issue, and when there are updates about the feature's progress, post those to the tracking issue.
-For features that have an RFC, you should use the RFC's
-tracking issue for the feature.
+For features that are part of an accept RFC or approved lang experiment, use the tracking issue for that.
-For other features, you'll have to make a tracking issue
-for that feature. The issue title should be "Tracking issue
-for YOUR FEATURE". Use the ["Tracking Issue" issue template][template].
+For other features, create a tracking issue for that feature. The issue title should be "Tracking issue for YOUR FEATURE". Use the ["Tracking Issue" issue template][template].
[template]: https://github.com/rust-lang/rust/issues/new?template=tracking_issue.md
+### Lang experiments
+
+To land in the compiler, features that have user-visible effects on the language (even unstable ones) must either be part of an accepted RFC or an approved [lang experiment].
+
+To propose a new lang experiment, open an issue in `rust-lang/rust` that describes the motivation and the intended solution. If it's accepted, this issue will become the tracking issue for the experiment, so use the tracking issue [template] while also including these other details. Nominate the issue for the lang team and CC `@rust-lang/lang` and `@rust-lang/lang-advisors`. When the experiment is approved, the tracking issue will be marked as `B-experimental`.
+
+Feature flags related to a lang experiment must be marked as `incomplete` until an RFC is accepted for the feature.
+
+[lang experiment]: https://lang-team.rust-lang.org/how_to/experiment.html
+
## Stability in code
-The below steps needs to be followed in order to implement
-a new unstable feature:
+The below steps needs to be followed in order to implement a new unstable feature:
-1. Open a [tracking issue] -
- if you have an RFC, you can use the tracking issue for the RFC.
+1. Open or identify the [tracking issue]. For features that are part of an accept RFC or approved lang experiment, use the tracking issue for that.
- The tracking issue should be labeled with at least `C-tracking-issue`.
- For a language feature, a label `F-feature_name` should be added as well.
+ Label the tracking issue with `C-tracking-issue` and the relevant `F-feature_name` label (adding that label if needed).
-1. Pick a name for the feature gate (for RFCs, use the name
- in the RFC).
+1. Pick a name for the feature gate (for RFCs, use the name in the RFC).
1. Add the feature name to `rustc_span/src/symbol.rs` in the `Symbols {...}` block.
Note that this block must be in alphabetical order.
-1. Add a feature gate declaration to `rustc_feature/src/unstable.rs` in the unstable
- `declare_features` block.
+1. Add a feature gate declaration to `rustc_feature/src/unstable.rs` in the unstable `declare_features` block.
```rust ignore
/// description of feature
(unstable, $feature_name, "CURRENT_RUSTC_VERSION", Some($tracking_issue_number))
```
- If you haven't yet
- opened a tracking issue (e.g. because you want initial feedback on whether the feature is likely
- to be accepted), you can temporarily use `None` - but make sure to update it before the PR is
- merged!
+ If you haven't yet opened a tracking issue (e.g. because you want initial feedback on whether the feature is likely to be accepted), you can temporarily use `None` - but make sure to update it before the PR is merged!
For example:
@@ -149,9 +95,7 @@
(unstable, non_ascii_idents, "CURRENT_RUSTC_VERSION", Some(55467), None),
```
- Features can be marked as incomplete, and trigger the warn-by-default [`incomplete_features`
- lint]
- by setting their type to `incomplete`:
+ Features can be marked as incomplete, and trigger the warn-by-default [`incomplete_features` lint] by setting their type to `incomplete`:
[`incomplete_features` lint]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#incomplete-features
@@ -160,42 +104,27 @@
(incomplete, deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121), None),
```
- To avoid [semantic merge conflicts], please use `CURRENT_RUSTC_VERSION` instead of `1.70` or
- another explicit version number.
+ Feature flags related to a lang experiment must be marked as `incomplete` until an RFC is accepted for the feature.
+
+ To avoid [semantic merge conflicts], use `CURRENT_RUSTC_VERSION` instead of `1.70` or another explicit version number.
[semantic merge conflicts]: https://bors.tech/essay/2017/02/02/pitch/
-1. Prevent usage of the new feature unless the feature gate is set.
- You can check it in most places in the compiler using the
- expression `tcx.features().$feature_name()`
+1. Prevent usage of the new feature unless the feature gate is set. You can check it in most places in the compiler using the expression `tcx.features().$feature_name()`.
- If the feature gate is not set, you should either maintain
- the pre-feature behavior or raise an error, depending on
- what makes sense. Errors should generally use [`rustc_session::parse::feature_err`].
- For an example of adding an error, see [#81015].
+ If the feature gate is not set, you should either maintain the pre-feature behavior or raise an error, depending on what makes sense. Errors should generally use [`rustc_session::parse::feature_err`]. For an example of adding an error, see [#81015].
- For features introducing new syntax, pre-expansion gating should be used instead.
- During parsing, when the new syntax is parsed, the symbol must be inserted to the
- current crate's [`GatedSpans`] via `self.sess.gated_span.gate(sym::my_feature, span)`.
-
- After being inserted to the gated spans, the span must be checked in the
- [`rustc_ast_passes::feature_gate::check_crate`] function, which actually denies
- features. Exactly how it is gated depends on the exact type of feature, but most
- likely will use the `gate_all!()` macro.
+ For features introducing new syntax, pre-expansion gating should be used instead. During parsing, when the new syntax is parsed, the symbol must be inserted to the current crate's [`GatedSpans`] via `self.sess.gated_span.gate(sym::my_feature, span)`.
-1. Add a test to ensure the feature cannot be used without
- a feature gate, by creating `tests/ui/feature-gates/feature-gate-$feature_name.rs`.
- You can generate the corresponding `.stderr` file by running `./x test
-tests/ui/feature-gates/ --bless`.
+ After being inserted to the gated spans, the span must be checked in the [`rustc_ast_passes::feature_gate::check_crate`] function, which actually denies features. Exactly how it is gated depends on the exact type of feature, but most likely will use the `gate_all!()` macro.
-1. Add a section to the unstable book, in
- `src/doc/unstable-book/src/language-features/$feature_name.md`.
+1. Add a test to ensure the feature cannot be used without a feature gate, by creating `tests/ui/feature-gates/feature-gate-$feature_name.rs`. You can generate the corresponding `.stderr` file by running `./x test tests/ui/feature-gates/ --bless`.
-1. Write a lot of tests for the new feature, preferably in `tests/ui/$feature_name/`.
- PRs without tests will not be accepted!
+1. Add a section to the unstable book, in `src/doc/unstable-book/src/language-features/$feature_name.md`.
-1. Get your PR reviewed and land it. You have now successfully
- implemented a feature in Rust!
+1. Write a lot of tests for the new feature, preferably in `tests/ui/$feature_name/`. PRs without tests will not be accepted!
+
+1. Get your PR reviewed and land it. You have now successfully implemented a feature in Rust!
[`GatedSpans`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/struct.GatedSpans.html
[#81015]: https://github.com/rust-lang/rust/pull/81015
@@ -206,3 +135,42 @@
[here]: ./stabilization_guide.md
[tracking issue]: #tracking-issues
[add-feature-gate]: ./feature-gates.md#adding-a-feature-gate
+
+## Call for testing
+
+Once the implementation is complete, the feature will be available to nightly users but not yet part of stable Rust. This is a good time to write a blog post on [the main Rust blog][rust-blog] and issue a "call for testing".
+
+Some earlier such blog posts include:
+
+1. [The push for GATs stabilization](https://blog.rust-lang.org/2021/08/03/GATs-stabilization-push/)
+2. [Changes to `impl Trait` in Rust 2024](https://blog.rust-lang.org/2024/09/05/impl-trait-capture-rules.html)
+3. [Async Closures MVP: Call for Testing!](https://blog.rust-lang.org/inside-rust/2024/08/09/async-closures-call-for-testing/)
+
+Alternatively, [*This Week in Rust*][twir] has a [section][twir-cft] for this. One example of this having been used is:
+
+- [Call for testing on boolean literals as cfg predicates](https://github.com/rust-lang/rust/issues/131204#issuecomment-2569314526)
+
+Which option to choose might depend on how significant the language change is, though note that the [*This Week in Rust*][twir] section might be less visible than a dedicated post on the main Rust blog.
+
+## Polishing
+
+Giving users a polished experience means more than just implementing the feature in rustc. We need to think about all of the tools and resources that we ship. This work includes:
+
+- Documenting the language feature in the [Rust Reference][reference].
+- Extending [`rustfmt`] to format any new syntax (if applicable).
+- Extending [`rust-analyzer`] (if applicable). The extent of this work can depend on the nature of the language feature, as some features don't need to be blocked on *full* support.
+ - When a language feature degrades the user experience simply by existing before support is implemented in [`rust-analyzer`], that may lead the lang team to raise a blocking concern.
+ - Examples of such might include new syntax that [`rust-analyzer`] can't parse or type inference changes it doesn't understand when those lead to bogus diagnostics.
+
+## Stabilization
+
+The final step in the feature lifecycle is [stabilization][stab], which is when the feature becomes available to all Rust users. At this point, backward incompatible changes are generally no longer permitted (see the lang team's [defined semver policies](https://rust-lang.github.io/rfcs/1122-language-semver.html) for details). To learn more about stabilization, see the [stabilization guide][stab].
+
+
+[stab]: ./stabilization_guide.md
+[rust-blog]: https://github.com/rust-lang/blog.rust-lang.org/
+[twir]: https://github.com/rust-lang/this-week-in-rust
+[twir-cft]: https://this-week-in-rust.org/blog/2025/01/22/this-week-in-rust-583/#calls-for-testing
+[`rustfmt`]: https://github.com/rust-lang/rustfmt
+[`rust-analyzer`]: https://github.com/rust-lang/rust-analyzer
+[reference]: https://github.com/rust-lang/reference
diff --git a/src/doc/rustc-dev-guide/src/stabilization_guide.md b/src/doc/rustc-dev-guide/src/stabilization_guide.md
index f875c68..f155272 100644
--- a/src/doc/rustc-dev-guide/src/stabilization_guide.md
+++ b/src/doc/rustc-dev-guide/src/stabilization_guide.md
@@ -1,120 +1,66 @@
# Request for stabilization
-**NOTE**: this page is about stabilizing *language* features.
-For stabilizing *library* features, see [Stabilizing a library feature].
+**NOTE**: This page is about stabilizing *language* features. For stabilizing *library* features, see [Stabilizing a library feature].
[Stabilizing a library feature]: ./stability.md#stabilizing-a-library-feature
-Once an unstable feature has been well-tested with no outstanding
-concern, anyone may push for its stabilization. It involves the
-following steps:
+Once an unstable feature has been well-tested with no outstanding concerns, anyone may push for its stabilization, though involving the people who have worked on it is prudent. Follow these steps:
<!-- toc -->
+## Write an RFC, if needed
+
+If the feature was part of a [lang experiment], the lang team generally will want to first accept an RFC before stabilization.
+
+[lang experiment]: https://lang-team.rust-lang.org/how_to/experiment.html
+
## Documentation PRs
<a id="updating-documentation"></a>
-If any documentation for this feature exists, it should be
-in the [`Unstable Book`], located at [`src/doc/unstable-book`].
-If it exists, the page for the feature gate should be removed.
+The feature might be documented in the [`Unstable Book`], located at [`src/doc/unstable-book`]. Remove the page for the feature gate if it exists. Integrate any useful parts of that documentation in other places.
-If there was documentation there, integrating it into the
-existing documentation is needed.
+Places that may need updated documentation include:
-If there wasn't documentation there, it needs to be added.
+- [The Reference]: This must be updated, in full detail, and a member of the lang-docs team must review and approve the PR before the stabilization can be merged.
+- [The Book]: This is updated as needed. If you're not sure, please open an issue on this repository and it can be discussed.
+- Standard library documentation: This is updated as needed. Language features often don't need this, but if it's a feature that changes how idiomatic examples are written, such as when `?` was added to the language, updating these in the library documentation is important. Review also the keyword documentation and ABI documentation in the standard library, as these sometimes needs updates for language changes.
+- [Rust by Example]: This is updated as needed.
-Places that may need updated documentation:
-
-- [The Reference]: This must be updated, in full detail.
-- [The Book]: This may or may not need updating, depends.
- If you're not sure, please open an issue on this repository
- and it can be discussed.
-- standard library documentation: As needed. Language features
- often don't need this, but if it's a feature that changes
- how good examples are written, such as when `?` was added
- to the language, updating examples is important.
-- [Rust by Example]: As needed.
-
-Prepare PRs to update documentation involving this new feature
-for repositories mentioned above. Maintainers of these repositories
-will keep these PRs open until the whole stabilization process
-has completed. Meanwhile, we can proceed to the next step.
+Prepare PRs to update documentation involving this new feature for the repositories mentioned above. Maintainers of these repositories will keep these PRs open until the whole stabilization process has completed. Meanwhile, we can proceed to the next step.
## Write a stabilization report
-Find the tracking issue of the feature, and create a short
-stabilization report. Essentially this would be a brief summary
-of the feature plus some links to test cases showing it works
-as expected, along with a list of edge cases that came up
-and were considered. This is a minimal "due diligence" that
-we do before stabilizing.
+Author a stabilization report using the [template found in this repository][srt].
-The report should contain:
+The stabilization reports summarizes:
-- A summary, showing examples (e.g. code snippets) what is
- enabled by this feature.
-- Links to test cases in our test suite regarding this feature
- and describe the feature's behavior on encountering edge cases.
-- Links to the documentations (the PRs we have made in the
- previous steps).
-- Any other relevant information.
-- The resolutions of any unresolved questions if the stabilization
- is for an RFC.
+- The main design decisions and deviations since the RFC was accepted, including both decisions that were FCP'd or otherwise accepted by the language team as well as those being presented to the lang team for the first time.
+ - Often, the final stabilized language feature has significant design deviations from the original RFC. That's OK, but these deviations must be highlighted and explained carefully.
+- The work that has been done since the RFC was accepted, acknowledging the main contributors that helped drive the language feature forward.
-Examples of stabilization reports can be found in
-[rust-lang/rust#44494][report1] and [rust-lang/rust#28237][report2] (these links
-will bring you directly to the comment containing the stabilization report).
+The [*Stabilization Template*][srt] includes a series of questions that aim to surface connections between this feature and lang's subteams (e.g. types, opsem, lang-docs, etc.) and to identify items that are commonly overlooked.
-[report1]: https://github.com/rust-lang/rust/issues/44494#issuecomment-360191474
-[report2]: https://github.com/rust-lang/rust/issues/28237#issuecomment-363374130
+[srt]: ./stabilization_report_template.md
-## FCP
-
-If any member of the team responsible for tracking this
-feature agrees with stabilizing this feature, they will
-start the FCP (final-comment-period) process by commenting
-
-```text
-@rfcbot fcp merge
-```
-
-The rest of the team members will review the proposal. If the final
-decision is to stabilize, we proceed to do the actual code modification.
+The stabilization report is typically posted as the main comment on the stabilization PR (see the next section).
## Stabilization PR
-*This is for stabilizing language features. If you are stabilizing a library
-feature, see [the stabilization chapter of the std dev guide][std-guide-stabilization] instead.*
+Every feature is different, and some may require steps beyond what this guide discusses.
-Once we have decided to stabilize a feature, we need to have
-a PR that actually makes that stabilization happen. These kinds
-of PRs are a great way to get involved in Rust, as they take
-you on a little tour through the source code.
-
-Here is a general guide to how to stabilize a feature --
-every feature is different, of course, so some features may
-require steps beyond what this guide talks about.
-
-Note: Before we stabilize any feature, it's the rule that it
-should appear in the documentation.
+Before the stabilization will be considered by the lang team, there must be a complete PR to the Reference describing the feature, and before the stabilization PR will be merged, this PR must have been reviewed and approved by the lang-docs team.
### Updating the feature-gate listing
-There is a central listing of unstable feature-gates in
-[`compiler/rustc_feature/src/unstable.rs`]. Search for the `declare_features!`
-macro. There should be an entry for the feature you are aiming
-to stabilize, something like (this example is taken from
-[rust-lang/rust#32409]:
+There is a central listing of unstable feature-gates in [`compiler/rustc_feature/src/unstable.rs`]. Search for the `declare_features!` macro. There should be an entry for the feature you are aiming to stabilize, something like (this example is taken from [rust-lang/rust#32409]:
```rust,ignore
// pub(restricted) visibilities (RFC 1422)
(unstable, pub_restricted, "CURRENT_RUSTC_VERSION", Some(32409)),
```
-The above line should be moved to [`compiler/rustc_feature/src/accepted.rs`].
-Entries in the `declare_features!` call are sorted, so find the correct place.
-When it is done, it should look like:
+The above line should be moved to [`compiler/rustc_feature/src/accepted.rs`]. Entries in the `declare_features!` call are sorted, so find the correct place. When it is done, it should look like:
```rust,ignore
// pub(restricted) visibilities (RFC 1422)
@@ -122,54 +68,31 @@
// note that we changed this
```
-(Even though you will encounter version numbers in the file of past changes,
-you should not put the rustc version you expect your stabilization to happen in,
-but instead `CURRENT_RUSTC_VERSION`)
+(Even though you will encounter version numbers in the file of past changes, you should not put the rustc version you expect your stabilization to happen in, but instead use `CURRENT_RUSTC_VERSION`.)
### Removing existing uses of the feature-gate
-Next search for the feature string (in this case, `pub_restricted`)
-in the codebase to find where it appears. Change uses of
-`#![feature(XXX)]` from the `std` and any rustc crates (this includes test folders
-under `library/` and `compiler/` but not the toplevel `tests/` one) to be
-`#![cfg_attr(bootstrap, feature(XXX))]`. This includes the feature-gate
-only for stage0, which is built using the current beta (this is
-needed because the feature is still unstable in the current beta).
+Next, search for the feature string (in this case, `pub_restricted`) in the codebase to find where it appears. Change uses of `#![feature(XXX)]` from the `std` and any rustc crates (this includes test folders under `library/` and `compiler/` but not the toplevel `tests/` one) to be `#![cfg_attr(bootstrap, feature(XXX))]`. This includes the feature-gate only for stage0, which is built using the current beta (this is needed because the feature is still unstable in the current beta).
-Also, remove those strings from any tests (e.g. under `tests/`). If there are tests
-specifically targeting the feature-gate (i.e., testing that the
-feature-gate is required to use the feature, but nothing else),
-simply remove the test.
+Also, remove those strings from any tests (e.g. under `tests/`). If there are tests specifically targeting the feature-gate (i.e., testing that the feature-gate is required to use the feature, but nothing else), simply remove the test.
### Do not require the feature-gate to use the feature
-Most importantly, remove the code which flags an error if the
-feature-gate is not present (since the feature is now considered
-stable). If the feature can be detected because it employs some
-new syntax, then a common place for that code to be is in the
-same `compiler/rustc_ast_passes/src/feature_gate.rs`.
-For example, you might see code like this:
+Most importantly, remove the code which flags an error if the feature-gate is not present (since the feature is now considered stable). If the feature can be detected because it employs some new syntax, then a common place for that code to be is in `compiler/rustc_ast_passes/src/feature_gate.rs`. For example, you might see code like this:
```rust,ignore
-gate_feature_post!(&self, pub_restricted, span,
- "`pub(restricted)` syntax is experimental");
+gate_all!(pub_restricted, "`pub(restricted)` syntax is experimental");
```
-This `gate_feature_post!` macro prints an error if the
-`pub_restricted` feature is not enabled. It is not needed
-now that `#[pub_restricted]` is stable.
+This `gate_feature_post!` macro prints an error if the `pub_restricted` feature is not enabled. It is not needed now that `#[pub_restricted]` is stable.
For more subtle features, you may find code like this:
```rust,ignore
-if self.tcx.sess.features.borrow().pub_restricted { /* XXX */ }
+if self.tcx.features().async_fn_in_dyn_trait() { /* XXX */ }
```
-This `pub_restricted` field (obviously named after the feature)
-would ordinarily be false if the feature flag is not present
-and true if it is. So transform the code to assume that the field
-is true. In this case, that would mean removing the `if` and
-leaving just the `/* XXX */`.
+This `pub_restricted` field (named after the feature) would ordinarily be false if the feature flag is not present and true if it is. So transform the code to assume that the field is true. In this case, that would mean removing the `if` and leaving just the `/* XXX */`.
```rust,ignore
if self.tcx.sess.features.borrow().pub_restricted { /* XXX */ }
@@ -194,3 +117,40 @@
[Rust by Example]: https://github.com/rust-lang/rust-by-example
[`Unstable Book`]: https://doc.rust-lang.org/unstable-book/index.html
[`src/doc/unstable-book`]: https://github.com/rust-lang/rust/tree/master/src/doc/unstable-book
+
+## Team nominations
+
+When opening the stabilization PR, CC the lang team and its advisors (`@rust-lang/lang @rust-lang/lang-advisors`) and any other teams to whom the feature is relevant, e.g.:
+
+- `@rust-lang/types`, for type system interactions.
+- `@rust-lang/opsem`, for interactions with unsafe code.
+- `@rust-lang/compiler`, for implementation robustness.
+- `@rust-lang/libs-api`, for changes to the standard library API or its guarantees.
+- `@rust-lang/lang-docs`, for questions about how this should be documented in the Reference.
+
+After the stabilization PR is opened with the stabilization report, wait a bit for any immediate comments. When such comments "simmer down" and you feel the PR is ready for consideration by the lang team, [nominate the PR](https://lang-team.rust-lang.org/how_to/nominate.html) to get it on the agenda for consideration in an upcoming lang meeting.
+
+If you are not a `rust-lang` organization member, you can ask your assigned reviewer to CC the relevant teams on your behalf.
+
+## Propose FCP on the PR
+
+After the lang team and other relevant teams review the stabilization, and after you have answered any questions they may have had, a member of one of the teams may propose to accept the stabilization by commenting:
+
+```text
+@rfcbot fcp merge
+```
+
+Once enough team members have reviewed, the PR will move into a "final comment period" (FCP). If no new concerns are raised, this period will complete and the PR can be merged after implementation review in the usual way.
+
+## Reviewing and merging stabilizations
+
+On a stabilization, before giving it the `r+`, ensure that the PR:
+
+- Matches what the team proposed for stabilization and what is documented in the Reference PR.
+- Includes any changes the team decided to request along the way in order to resolve or avoid concerns.
+- Is otherwise exactly what is described in the stabilization report and in any relevant RFCs or prior lang FCPs.
+- Does not expose on stable behaviors other than those specified, accepted for stabilization, and documented in the Reference.
+- Has sufficient tests to convincingly demonstrate these things.
+- Is accompanied by a PR to the Reference than has been reviewed and approved by a member of lang-docs.
+
+In particular, when reviewing the PR, keep an eye out for any user-visible details that the lang team failed to consider and specify. If you find one, describe it and nominate the PR for the lang team.
diff --git a/src/doc/rustc-dev-guide/src/stabilization_report_template.md b/src/doc/rustc-dev-guide/src/stabilization_report_template.md
new file mode 100644
index 0000000..793f7d7
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/stabilization_report_template.md
@@ -0,0 +1,277 @@
+# Stabilization report template
+
+## What is this?
+
+This is a template for [stabilization reports](./stabilization_guide.md) of **language features**. The questions aim to solicit the details most often needed. These details help reviewers to identify potential problems upfront. Not all parts of the template will apply to every stabilization. If a question doesn't apply, explain briefly why.
+
+Copy everything after the separator and edit it as Markdown. Replace each *TODO* with your answer.
+
+---
+
+# Stabilization report
+
+## Summary
+
+> Remind us what this feature is and what value it provides. Tell the story of what led up to this stabilization.
+>
+> E.g., see:
+>
+> - [Stabilize AFIT/RPITIT](https://web.archive.org/web/20250329190642/https://github.com/rust-lang/rust/pull/115822)
+> - [Stabilize RTN](https://web.archive.org/web/20250321214601/https://github.com/rust-lang/rust/pull/138424)
+> - [Stabilize ATPIT](https://web.archive.org/web/20250124214256/https://github.com/rust-lang/rust/pull/120700)
+> - [Stabilize opaque type precise capturing](https://web.archive.org/web/20250312173538/https://github.com/rust-lang/rust/pull/127672)
+
+*TODO*
+
+Tracking:
+
+- *TODO* (Link to tracking issue.)
+
+Reference PRs:
+
+- *TODO* (Link to Reference PRs.)
+
+cc @rust-lang/lang @rust-lang/lang-advisors
+
+### What is stabilized
+
+> Describe each behavior being stabilized and give a short example of code that will now be accepted.
+
+```rust
+todo!()
+```
+
+### What isn't stabilized
+
+> Describe any parts of the feature not being stabilized. Talk about what we might want to do later and what doors are being left open for that. If what we're not stabilizing might lead to surprises for users, talk about that in particular.
+
+## Design
+
+### Reference
+
+> What updates are needed to the Reference? Link to each PR. If the Reference is missing content needed for describing this feature, discuss that.
+
+- *TODO*
+
+### RFC history
+
+> What RFCs have been accepted for this feature?
+
+- *TODO*
+
+### Answers to unresolved questions
+
+> What questions were left unresolved by the RFC? How have they been answered? Link to any relevant lang decisions.
+
+*TODO*
+
+### Post-RFC changes
+
+> What other user-visible changes have occurred since the RFC was accepted? Describe both changes that the lang team accepted (and link to those decisions) as well as changes that are being presented to the team for the first time in this stabilization report.
+
+*TODO*
+
+### Key points
+
+> What decisions have been most difficult and what behaviors to be stabilized have proved most contentious? Summarize the major arguments on all sides and link to earlier documents and discussions.
+
+*TODO*
+
+### Nightly extensions
+
+> Are there extensions to this feature that remain unstable? How do we know that we are not accidentally committing to those?
+
+*TODO*
+
+### Doors closed
+
+> What doors does this stabilization close for later changes to the language? E.g., does this stabilization make any other RFCs, lang experiments, or known in-flight proposals more difficult or impossible to do later?
+
+## Feedback
+
+### Call for testing
+
+> Has a "call for testing" been done? If so, what feedback was received?
+
+*TODO*
+
+### Nightly use
+
+> Do any known nightly users use this feature? Counting instances of `#![feature(FEATURE_NAME)]` on GitHub with grep might be informative.
+
+*TODO*
+
+## Implementation
+
+### Major parts
+
+> Summarize the major parts of the implementation and provide links into the code and to relevant PRs.
+>
+> See, e.g., this breakdown of the major parts of async closures:
+>
+> - <https://rustc-dev-guide.rust-lang.org/coroutine-closures.html>
+
+*TODO*
+
+### Coverage
+
+> Summarize the test coverage of this feature.
+>
+> Consider what the "edges" of this feature are. We're particularly interested in seeing tests that assure us about exactly what nearby things we're not stabilizing. Tests should of course comprehensively demonstrate that the feature works. Think too about demonstrating the diagnostics seen when common mistakes are made and the feature is used incorrectly.
+>
+> Within each test, include a comment at the top describing the purpose of the test and what set of invariants it intends to demonstrate. This is a great help to our review.
+>
+> Describe any known or intentional gaps in test coverage.
+>
+> Contextualize and link to test folders and individual tests.
+
+*TODO*
+
+### Outstanding bugs
+
+> What outstanding bugs involve this feature? List them. Should any block the stabilization? Discuss why or why not.
+
+*TODO*
+
+- *TODO*
+- *TODO*
+- *TODO*
+
+### Outstanding FIXMEs
+
+> What FIXMEs are still in the code for that feature and why is it OK to leave them there?
+
+*TODO*
+
+### Tool changes
+
+> What changes must be made to our other tools to support this feature. Has this work been done? Link to any relevant PRs and issues.
+
+- [ ] rustfmt
+ - *TODO*
+- [ ] rust-analyzer
+ - *TODO*
+- [ ] rustdoc (both JSON and HTML)
+ - *TODO*
+- [ ] cargo
+ - *TODO*
+- [ ] clippy
+ - *TODO*
+- [ ] rustup
+ - *TODO*
+- [ ] docs.rs
+ - *TODO*
+
+*TODO*
+
+### Breaking changes
+
+> If this stabilization represents a known breaking change, link to the crater report, the analysis of the crater report, and to all PRs we've made to ecosystem projects affected by this breakage. Discuss any limitations of what we're able to know about or to fix.
+
+*TODO*
+
+Crater report:
+
+- *TODO*
+
+Crater analysis:
+
+- *TODO*
+
+PRs to affected crates:
+
+- *TODO*
+- *TODO*
+- *TODO*
+
+## Type system, opsem
+
+### Compile-time checks
+
+> What compilation-time checks are done that are needed to prevent undefined behavior?
+>
+> Link to tests demonstrating that these checks are being done.
+
+*TODO*
+
+- *TODO*
+- *TODO*
+- *TODO*
+
+### Type system rules
+
+> What type system rules are enforced for this feature and what is the purpose of each?
+
+*TODO*
+
+### Sound by default?
+
+> Does the feature's implementation need specific checks to prevent UB, or is it sound by default and need specific opt-in to perform the dangerous/unsafe operations? If it is not sound by default, what is the rationale?
+
+*TODO*
+
+### Breaks the AM?
+
+> Can users use this feature to introduce undefined behavior, or use this feature to break the abstraction of Rust and expose the underlying assembly-level implementation? Describe this if so.
+
+*TODO*
+
+## Common interactions
+
+### Temporaries
+
+> Does this feature introduce new expressions that can produce temporaries? What are the scopes of those temporaries?
+
+*TODO*
+
+### Drop order
+
+> Does this feature raise questions about the order in which we should drop values? Talk about the decisions made here and how they're consistent with our earlier decisions.
+
+*TODO*
+
+### Pre-expansion / post-expansion
+
+> Does this feature raise questions about what should be accepted pre-expansion (e.g. in code covered by `#[cfg(false)]`) versus what should be accepted post-expansion? What decisions were made about this?
+
+*TODO*
+
+### Edition hygiene
+
+> If this feature is gated on an edition, how do we decide, in the context of the edition hygiene of tokens, whether to accept or reject code. E.g., what token do we use to decide?
+
+*TODO*
+
+### SemVer implications
+
+> Does this feature create any new ways in which library authors must take care to prevent breaking downstreams when making minor-version releases? Describe these. Are these new hazards "major" or "minor" according to [RFC 1105](https://rust-lang.github.io/rfcs/1105-api-evolution.html)?
+
+*TODO*
+
+### Exposing other features
+
+> Are there any other unstable features whose behavior may be exposed by this feature in any way? What features present the highest risk of that?
+
+*TODO*
+
+## History
+
+> List issues and PRs that are important for understanding how we got here.
+
+- *TODO*
+- *TODO*
+- *TODO*
+
+## Acknowledgments
+
+> Summarize contributors to the feature by name for recognition and so that those people are notified about the stabilization. Does anyone who worked on this *not* think it should be stabilized right now? We'd like to hear about that if so.
+
+*TODO*
+
+## Open items
+
+> List any known items that have not yet been completed and that should be before this is stabilized.
+
+- [ ] *TODO*
+- [ ] *TODO*
+- [ ] *TODO*
diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md
index 5c3ae35..89e4d3e 100644
--- a/src/doc/rustc-dev-guide/src/tests/directives.md
+++ b/src/doc/rustc-dev-guide/src/tests/directives.md
@@ -293,8 +293,6 @@
- `no-auto-check-cfg` — disable auto check-cfg (only for `--check-cfg` tests)
- [`revisions`](compiletest.md#revisions) — compile multiple times
-- [`unused-revision-names`](compiletest.md#ignoring-unused-revision-names) -
- suppress tidy checks for mentioning unknown revision names
-[`forbid-output`](compiletest.md#incremental-tests) — incremental cfail rejects
output pattern
- [`should-ice`](compiletest.md#incremental-tests) — incremental cfail should
@@ -315,6 +313,17 @@
- `llvm-cov-flags` adds extra flags when running LLVM's `llvm-cov` tool.
- Used by [coverage tests](compiletest.md#coverage-tests) in `coverage-run` mode.
+### Tidy specific directives
+
+The following directives control how the [tidy script](../conventions.md#formatting)
+verifies tests.
+
+- `ignore-tidy-target-specific-tests` disables checking that the appropriate
+ LLVM component is required (via a `needs-llvm-components` directive) when a
+ test is compiled for a specific target (via the `--target` flag in a
+ `compile-flag` directive).
+- [`unused-revision-names`](compiletest.md#ignoring-unused-revision-names) -
+ suppress tidy checks for mentioning unknown revision names.
## Substitutions
diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md
index 9bfc60e..782f78d 100644
--- a/src/doc/rustc-dev-guide/src/tests/ui.md
+++ b/src/doc/rustc-dev-guide/src/tests/ui.md
@@ -309,7 +309,9 @@
Use `//~?` to match an error without line information.
`//~?` is precise and will not match errors if their line information is available.
-It should be preferred to using `error-pattern`, which is imprecise and non-exhaustive.
+It should be preferred over `//@ error-pattern`
+for tests wishing to match against compiler diagnostics,
+due to `//@ error-pattern` being imprecise and non-exhaustive.
```rust,ignore
//@ compile-flags: --print yyyy
@@ -319,8 +321,8 @@
### `error-pattern`
-The `error-pattern` [directive](directives.md) can be used for runtime messages, which don't
-have a specific span, or in exceptional cases, for compile time messages.
+The `error-pattern` [directive](directives.md) can be used for runtime messages which don't
+have a specific span, or, in exceptional cases, for compile time messages.
Let's think about this test:
@@ -347,8 +349,6 @@
}
```
-Use of `error-pattern` is not recommended in general.
-
For strict testing of compile time output, try to use the line annotations `//~` as much as
possible, including `//~?` annotations for diagnostics without spans.
@@ -359,7 +359,8 @@
For checking runtime output, `//@ check-run-results` may be preferable.
-Only use `error-pattern` if none of the above works.
+Only use `error-pattern` if none of the above works, such as when finding a
+specific string pattern in a runtime panic output.
Line annotations `//~` and `error-pattern` are compatible and can be used in the same test.
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 1265a39..14295ce 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -36,6 +36,7 @@
use rustc_ast::token::{Token, TokenKind};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry};
use rustc_errors::codes::*;
use rustc_errors::{FatalError, struct_span_code_err};
@@ -987,28 +988,17 @@ fn clean_proc_macro<'tcx>(
kind: MacroKind,
cx: &mut DocContext<'tcx>,
) -> ItemKind {
+ if kind != MacroKind::Derive {
+ return ProcMacroItem(ProcMacro { kind, helpers: vec![] });
+ }
let attrs = cx.tcx.hir_attrs(item.hir_id());
- if kind == MacroKind::Derive
- && let Some(derive_name) =
- hir_attr_lists(attrs, sym::proc_macro_derive).find_map(|mi| mi.ident())
- {
- *name = derive_name.name;
- }
+ let Some((trait_name, helper_attrs)) = find_attr!(attrs, AttributeKind::ProcMacroDerive { trait_name, helper_attrs, ..} => (*trait_name, helper_attrs))
+ else {
+ return ProcMacroItem(ProcMacro { kind, helpers: vec![] });
+ };
+ *name = trait_name;
+ let helpers = helper_attrs.iter().copied().collect();
- let mut helpers = Vec::new();
- for mi in hir_attr_lists(attrs, sym::proc_macro_derive) {
- if !mi.has_name(sym::attributes) {
- continue;
- }
-
- if let Some(list) = mi.meta_item_list() {
- for inner_mi in list {
- if let Some(ident) = inner_mi.ident() {
- helpers.push(ident.name);
- }
- }
- }
- }
ProcMacroItem(ProcMacro { kind, helpers })
}
@@ -1021,17 +1011,16 @@ fn clean_fn_or_proc_macro<'tcx>(
cx: &mut DocContext<'tcx>,
) -> ItemKind {
let attrs = cx.tcx.hir_attrs(item.hir_id());
- let macro_kind = attrs.iter().find_map(|a| {
- if a.has_name(sym::proc_macro) {
- Some(MacroKind::Bang)
- } else if a.has_name(sym::proc_macro_derive) {
- Some(MacroKind::Derive)
- } else if a.has_name(sym::proc_macro_attribute) {
- Some(MacroKind::Attr)
- } else {
- None
- }
- });
+ let macro_kind = if find_attr!(attrs, AttributeKind::ProcMacro(..)) {
+ Some(MacroKind::Bang)
+ } else if find_attr!(attrs, AttributeKind::ProcMacroDerive { .. }) {
+ Some(MacroKind::Derive)
+ } else if find_attr!(attrs, AttributeKind::ProcMacroAttribute(..)) {
+ Some(MacroKind::Attr)
+ } else {
+ None
+ };
+
match macro_kind {
Some(kind) => clean_proc_macro(item, name, kind, cx),
None => {
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 986390d..fed4296 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -173,6 +173,9 @@ pub(crate) struct Options {
/// Arguments to be used when compiling doctests.
pub(crate) doctest_build_args: Vec<String>,
+
+ /// Target modifiers.
+ pub(crate) target_modifiers: BTreeMap<OptionsTargetModifiers, String>,
}
impl fmt::Debug for Options {
@@ -377,7 +380,7 @@ pub(crate) fn from_matches(
early_dcx: &mut EarlyDiagCtxt,
matches: &getopts::Matches,
args: Vec<String>,
- ) -> Option<(InputMode, Options, RenderOptions)> {
+ ) -> Option<(InputMode, Options, RenderOptions, Vec<PathBuf>)> {
// Check for unstable options.
nightly_options::check_nightly_options(early_dcx, matches, &opts());
@@ -640,10 +643,13 @@ fn println_condition(condition: Condition) {
let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s));
- if let Some(ref p) = extension_css
- && !p.is_file()
- {
- dcx.fatal("option --extend-css argument must be a file");
+ let mut loaded_paths = Vec::new();
+
+ if let Some(ref p) = extension_css {
+ loaded_paths.push(p.clone());
+ if !p.is_file() {
+ dcx.fatal("option --extend-css argument must be a file");
+ }
}
let mut themes = Vec::new();
@@ -687,6 +693,7 @@ fn println_condition(condition: Condition) {
))
.emit();
}
+ loaded_paths.push(theme_file.clone());
themes.push(StylePath { path: theme_file });
}
}
@@ -705,6 +712,7 @@ fn println_condition(condition: Condition) {
&mut id_map,
edition,
&None,
+ &mut loaded_paths,
) else {
dcx.fatal("`ExternalHtml::load` failed");
};
@@ -796,7 +804,8 @@ fn println_condition(condition: Condition) {
let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx);
let with_examples = matches.opt_strs("with-examples");
- let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx);
+ let call_locations =
+ crate::scrape_examples::load_call_locations(with_examples, dcx, &mut loaded_paths);
let doctest_build_args = matches.opt_strs("doctest-build-arg");
let unstable_features =
@@ -846,6 +855,7 @@ fn println_condition(condition: Condition) {
unstable_features,
expanded_args: args,
doctest_build_args,
+ target_modifiers,
};
let render_options = RenderOptions {
output,
@@ -881,7 +891,7 @@ fn println_condition(condition: Condition) {
parts_out_dir,
disable_minification,
};
- Some((input, options, render_options))
+ Some((input, options, render_options, loaded_paths))
}
}
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index bd57bb2..e89733b 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -214,6 +214,7 @@ pub(crate) fn create_config(
scrape_examples_options,
expanded_args,
remap_path_prefix,
+ target_modifiers,
..
}: RustdocOptions,
render_options: &RenderOptions,
@@ -277,6 +278,7 @@ pub(crate) fn create_config(
} else {
OutputTypes::new(&[])
},
+ target_modifiers,
..Options::default()
};
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 38ba6b4..a32c2f7 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -444,7 +444,7 @@ fn add_exe_suffix(input: String, target: &TargetTuple) -> String {
let exe_suffix = match target {
TargetTuple::TargetTuple(_) => Target::expect_builtin(target).options.exe_suffix,
TargetTuple::TargetJson { contents, .. } => {
- Target::from_json(contents.parse().unwrap()).unwrap().0.options.exe_suffix
+ Target::from_json(contents).unwrap().0.options.exe_suffix
}
};
input + &exe_suffix
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
index ea2aa96..42ade5b 100644
--- a/src/librustdoc/externalfiles.rs
+++ b/src/librustdoc/externalfiles.rs
@@ -1,4 +1,4 @@
-use std::path::Path;
+use std::path::{Path, PathBuf};
use std::{fs, str};
use rustc_errors::DiagCtxtHandle;
@@ -32,12 +32,13 @@ pub(crate) fn load(
id_map: &mut IdMap,
edition: Edition,
playground: &Option<Playground>,
+ loaded_paths: &mut Vec<PathBuf>,
) -> Option<ExternalHtml> {
let codes = ErrorCodes::from(nightly_build);
- let ih = load_external_files(in_header, dcx)?;
+ let ih = load_external_files(in_header, dcx, loaded_paths)?;
let bc = {
- let mut bc = load_external_files(before_content, dcx)?;
- let m_bc = load_external_files(md_before_content, dcx)?;
+ let mut bc = load_external_files(before_content, dcx, loaded_paths)?;
+ let m_bc = load_external_files(md_before_content, dcx, loaded_paths)?;
Markdown {
content: &m_bc,
links: &[],
@@ -52,8 +53,8 @@ pub(crate) fn load(
bc
};
let ac = {
- let mut ac = load_external_files(after_content, dcx)?;
- let m_ac = load_external_files(md_after_content, dcx)?;
+ let mut ac = load_external_files(after_content, dcx, loaded_paths)?;
+ let m_ac = load_external_files(md_after_content, dcx, loaded_paths)?;
Markdown {
content: &m_ac,
links: &[],
@@ -79,8 +80,10 @@ pub(crate) enum LoadStringError {
pub(crate) fn load_string<P: AsRef<Path>>(
file_path: P,
dcx: DiagCtxtHandle<'_>,
+ loaded_paths: &mut Vec<PathBuf>,
) -> Result<String, LoadStringError> {
let file_path = file_path.as_ref();
+ loaded_paths.push(file_path.to_owned());
let contents = match fs::read(file_path) {
Ok(bytes) => bytes,
Err(e) => {
@@ -101,10 +104,14 @@ pub(crate) fn load_string<P: AsRef<Path>>(
}
}
-fn load_external_files(names: &[String], dcx: DiagCtxtHandle<'_>) -> Option<String> {
+fn load_external_files(
+ names: &[String],
+ dcx: DiagCtxtHandle<'_>,
+ loaded_paths: &mut Vec<PathBuf>,
+) -> Option<String> {
let mut out = String::new();
for name in names {
- let Ok(s) = load_string(name, dcx) else { return None };
+ let Ok(s) = load_string(name, dcx, loaded_paths) else { return None };
out.push_str(&s);
out.push('\n');
}
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 3c9be29..e2f86b8 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -100,9 +100,22 @@ pub(crate) fn build_index(
let crate_doc =
short_markdown_summary(&krate.module.doc_value(), &krate.module.link_names(cache));
+ #[derive(Eq, Ord, PartialEq, PartialOrd)]
+ struct SerSymbolAsStr(Symbol);
+
+ impl Serialize for SerSymbolAsStr {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ self.0.as_str().serialize(serializer)
+ }
+ }
+
+ type AliasMap = BTreeMap<SerSymbolAsStr, Vec<usize>>;
// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
// we need the alias element to have an array of items.
- let mut aliases: BTreeMap<String, Vec<usize>> = BTreeMap::new();
+ let mut aliases: AliasMap = BTreeMap::new();
// Sort search index items. This improves the compressibility of the search index.
cache.search_index.sort_unstable_by(|k1, k2| {
@@ -116,7 +129,7 @@ pub(crate) fn build_index(
// Set up alias indexes.
for (i, item) in cache.search_index.iter().enumerate() {
for alias in &item.aliases[..] {
- aliases.entry(alias.to_string()).or_default().push(i);
+ aliases.entry(SerSymbolAsStr(*alias)).or_default().push(i);
}
}
@@ -474,7 +487,7 @@ struct CrateData<'a> {
// The String is alias name and the vec is the list of the elements with this alias.
//
// To be noted: the `usize` elements are indexes to `items`.
- aliases: &'a BTreeMap<String, Vec<usize>>,
+ aliases: &'a AliasMap,
// Used when a type has more than one impl with an associated item with the same name.
associated_item_disambiguators: &'a Vec<(usize, String)>,
// A list of shard lengths encoded as vlqhex. See the comment in write_vlqhex_to_string
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 3c4af0d..8e3d07b 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -568,7 +568,11 @@
break;
case "-":
ev.preventDefault();
- collapseAllDocs();
+ collapseAllDocs(false);
+ break;
+ case "_":
+ ev.preventDefault();
+ collapseAllDocs(true);
break;
case "?":
@@ -1038,11 +1042,14 @@
innerToggle.children[0].innerText = "Summary";
}
- function collapseAllDocs() {
+ /**
+ * @param {boolean} collapseImpls - also collapse impl blocks if set to true
+ */
+ function collapseAllDocs(collapseImpls) {
const innerToggle = document.getElementById(toggleAllDocsId);
addClass(innerToggle, "will-expand");
onEachLazy(document.getElementsByClassName("toggle"), e => {
- if (e.parentNode.id !== "implementations-list" ||
+ if ((collapseImpls || e.parentNode.id !== "implementations-list") ||
(!hasClass(e, "implementors-toggle") &&
!hasClass(e, "type-contents-toggle"))
) {
@@ -1053,7 +1060,10 @@
innerToggle.children[0].innerText = "Show all";
}
- function toggleAllDocs() {
+ /**
+ * @param {MouseEvent=} ev
+ */
+ function toggleAllDocs(ev) {
const innerToggle = document.getElementById(toggleAllDocsId);
if (!innerToggle) {
return;
@@ -1061,7 +1071,7 @@
if (hasClass(innerToggle, "will-expand")) {
expandAllDocs();
} else {
- collapseAllDocs();
+ collapseAllDocs(ev !== undefined && ev.shiftKey);
}
}
@@ -1519,6 +1529,10 @@
["⏎", "Go to active search result"],
["+", "Expand all sections"],
["-", "Collapse all sections"],
+ // for the sake of brevity, we don't say "inherint impl blocks",
+ // although that would be more correct,
+ // since trait impl blocks are collapsed by -
+ ["_", "Collapse all sections, including impl blocks"],
].map(x => "<dt>" +
x[0].split(" ")
.map((y, index) => ((index & 1) === 0 ? "<kbd>" + y + "</kbd>" : " " + y + " "))
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index 7611372..ca13b89 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -418,7 +418,9 @@
<div id="help-button" tabindex="-1">
<a href="${rootPath}help.html"><span class="label">Help</span></a>
</div>
- <button id="toggle-all-docs"><span class="label">Summary</span></button>`;
+ <button id="toggle-all-docs"
+title="Collapse sections (shift-click to also collapse impl blocks)"><span
+class="label">Summary</span></button>`;
}
}
window.customElements.define("rustdoc-toolbar", RustdocToolbarElement);
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index a3cdc4f..7431ff8 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -799,7 +799,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
// Note that we discard any distinction between different non-zero exit
// codes from `from_matches` here.
- let (input, options, render_options) =
+ let (input, options, render_options, loaded_paths) =
match config::Options::from_matches(early_dcx, &matches, args) {
Some(opts) => opts,
None => return,
@@ -870,6 +870,12 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
interface::run_compiler(config, |compiler| {
let sess = &compiler.sess;
+ // Register the loaded external files in the source map so they show up in depinfo.
+ // We can't load them via the source map because it gets created after we process the options.
+ for external_path in &loaded_paths {
+ let _ = sess.source_map().load_file(external_path);
+ }
+
if sess.opts.describe_lints {
rustc_driver::describe_lints(sess, registered_lints);
return;
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index fceacb6..4d29c74 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -333,9 +333,11 @@ pub(crate) fn run(
pub(crate) fn load_call_locations(
with_examples: Vec<String>,
dcx: DiagCtxtHandle<'_>,
+ loaded_paths: &mut Vec<PathBuf>,
) -> AllCallLocations {
let mut all_calls: AllCallLocations = FxIndexMap::default();
for path in with_examples {
+ loaded_paths.push(path.clone().into());
let bytes = match fs::read(&path) {
Ok(bytes) => bytes,
Err(e) => dcx.fatal(format!("failed to load examples: {e}")),
diff --git a/src/tools/cargo b/src/tools/cargo
index 6833aa7..9b29697 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit 6833aa715d724437dc1247d0166afe314ab6854e
+Subproject commit 9b296973b425ffb159e12cf3cd56580fd5c85382
diff --git a/src/tools/clippy/.github/workflows/feature_freeze.yml b/src/tools/clippy/.github/workflows/feature_freeze.yml
index 7ad58af..ec59be3 100644
--- a/src/tools/clippy/.github/workflows/feature_freeze.yml
+++ b/src/tools/clippy/.github/workflows/feature_freeze.yml
@@ -20,16 +20,26 @@
# of the pull request, as malicious code would be able to access the private
# GitHub token.
steps:
- - name: Check PR Changes
- id: pr-changes
- run: echo "::set-output name=changes::${{ toJson(github.event.pull_request.changed_files) }}"
-
- - name: Create Comment
- if: steps.pr-changes.outputs.changes != '[]'
- run: |
- # Use GitHub API to create a comment on the PR
- PR_NUMBER=${{ github.event.pull_request.number }}
- COMMENT="**Seems that you are trying to add a new lint!**\nWe are currently in a [feature freeze](https://doc.rust-lang.org/nightly/clippy/development/feature_freeze.html), so we are delaying all lint-adding PRs to September 18 and focusing on bugfixes.\nThanks a lot for your contribution, and sorry for the inconvenience.\nWith ❤ from the Clippy team\n\n@rustbot note Feature-freeze\n@rustbot blocked\n@rustbot label +A-lint\n"
- GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}
- COMMENT_URL="https://api.github.com/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments"
- curl -s -H "Authorization: token ${GITHUB_TOKEN}" -X POST $COMMENT_URL -d "{\"body\":\"$COMMENT\"}"
+ - name: Add freeze warning comment
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ PR_NUMBER: ${{ github.event.pull_request.number }}
+ run: |
+ COMMENT=$(echo "**Seems that you are trying to add a new lint!**\n\
+ \n\
+ We are currently in a [feature freeze](https://doc.rust-lang.org/nightly/clippy/development/feature_freeze.html), so we are delaying all lint-adding PRs to September 18 and [focusing on bugfixes](https://github.com/rust-lang/rust-clippy/issues/15086).\n\
+ \n\
+ Thanks a lot for your contribution, and sorry for the inconvenience.\n\
+ \n\
+ With ❤ from the Clippy team.\n\
+ \n\
+ @rustbot note Feature-freeze\n\
+ @rustbot blocked\n\
+ @rustbot label +A-lint"
+ )
+ curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
+ -H "Content-Type: application/vnd.github.raw+json" \
+ -X POST \
+ --data "{\"body\":\"${COMMENT}\"}" \
+ "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments"
diff --git a/src/tools/clippy/.gitignore b/src/tools/clippy/.gitignore
index a7c25b290..36a4cdc 100644
--- a/src/tools/clippy/.gitignore
+++ b/src/tools/clippy/.gitignore
@@ -19,8 +19,10 @@
# Generated by Cargo
*Cargo.lock
+!/clippy_test_deps/Cargo.lock
/target
/clippy_lints/target
+/clippy_lints_internal/target
/clippy_utils/target
/clippy_dev/target
/lintcheck/target
diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs
index bd9e57c..2b2138d 100644
--- a/src/tools/clippy/clippy_dev/src/fmt.rs
+++ b/src/tools/clippy/clippy_dev/src/fmt.rs
@@ -3,7 +3,7 @@
walk_dir_no_dot_or_target,
};
use itertools::Itertools;
-use rustc_lexer::{TokenKind, tokenize};
+use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
use std::fmt::Write;
use std::fs;
use std::io::{self, Read};
@@ -92,7 +92,7 @@ enum State {
let mut fields = Vec::new();
let mut state = State::Start;
- for (i, t) in tokenize(conf)
+ for (i, t) in tokenize(conf, FrontmatterAllowed::No)
.map(|x| {
let start = pos;
pos += x.len;
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index 5ed4c82..184fbbf 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -92,9 +92,11 @@ fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: Lit, _negated
impl ApproxConstant {
fn check_known_consts(&self, cx: &LateContext<'_>, span: Span, s: symbol::Symbol, module: &str) {
let s = s.as_str();
- if s.parse::<f64>().is_ok() {
+ if let Ok(maybe_constant) = s.parse::<f64>() {
for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
- if is_approx_const(constant, s, min_digits) && msrv.is_none_or(|msrv| self.msrv.meets(cx, msrv)) {
+ if is_approx_const(constant, s, maybe_constant, min_digits)
+ && msrv.is_none_or(|msrv| self.msrv.meets(cx, msrv))
+ {
span_lint_and_help(
cx,
APPROX_CONSTANT,
@@ -112,18 +114,35 @@ fn check_known_consts(&self, cx: &LateContext<'_>, span: Span, s: symbol::Symbol
impl_lint_pass!(ApproxConstant => [APPROX_CONSTANT]);
+fn count_digits_after_dot(input: &str) -> usize {
+ input
+ .char_indices()
+ .find(|(_, ch)| *ch == '.')
+ .map_or(0, |(i, _)| input.len() - i - 1)
+}
+
/// Returns `false` if the number of significant figures in `value` are
/// less than `min_digits`; otherwise, returns true if `value` is equal
-/// to `constant`, rounded to the number of digits present in `value`.
+/// to `constant`, rounded to the number of significant digits present in `value`.
#[must_use]
-fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool {
+fn is_approx_const(constant: f64, value: &str, f_value: f64, min_digits: usize) -> bool {
if value.len() <= min_digits {
+ // The value is not precise enough
false
- } else if constant.to_string().starts_with(value) {
- // The value is a truncated constant
+ } else if f_value.to_string().len() > min_digits && constant.to_string().starts_with(&f_value.to_string()) {
+ // The value represents the same value
true
} else {
- let round_const = format!("{constant:.*}", value.len() - 2);
+ // The value is a truncated constant
+
+ // Print constant with numeric formatting (`0`), with the length of `value` as minimum width
+ // (`value_len$`), and with the same precision as `value` (`.value_prec$`).
+ // See https://doc.rust-lang.org/std/fmt/index.html.
+ let round_const = format!(
+ "{constant:0value_len$.value_prec$}",
+ value_len = value.len(),
+ value_prec = count_digits_after_dot(value)
+ );
value == round_const
}
}
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 a9d3015..7b4cf03 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
@@ -8,11 +8,11 @@
use clippy_utils::is_cfg_test;
use rustc_attr_data_structures::AttributeKind;
use rustc_hir::{
- Attribute, FieldDef, HirId, IsAuto, ImplItemId, Item, ItemKind, Mod, OwnerId, QPath, TraitItemId, TyKind,
- Variant, VariantData,
+ Attribute, FieldDef, HirId, ImplItemId, IsAuto, Item, ItemKind, Mod, OwnerId, QPath, TraitItemId, TyKind, Variant,
+ VariantData,
};
-use rustc_middle::ty::AssocKind;
use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::ty::AssocKind;
use rustc_session::impl_lint_pass;
use rustc_span::Ident;
@@ -469,13 +469,14 @@ struct CurItem<'a> {
/// This is implemented here because `rustc_hir` is not a dependency of
/// `clippy_config`.
fn convert_assoc_item_kind(cx: &LateContext<'_>, owner_id: OwnerId) -> SourceItemOrderingTraitAssocItemKind {
- let kind = cx.tcx.associated_item(owner_id.def_id).kind;
-
#[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
use SourceItemOrderingTraitAssocItemKind::*;
+
+ let kind = cx.tcx.associated_item(owner_id.def_id).kind;
+
match kind {
- AssocKind::Const{..} => Const,
- AssocKind::Type {..}=> Type,
+ AssocKind::Const { .. } => Const,
+ AssocKind::Type { .. } => Type,
AssocKind::Fn { .. } => Fn,
}
}
diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
index 9e09fb5..085029a 100644
--- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
+++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
@@ -73,7 +73,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
diag.note(format!(
"`Arc<{arg_ty}>` is not `Send` and `Sync` as `{arg_ty}` is {reason}"
));
- diag.help("if the `Arc` will not used be across threads replace it with an `Rc`");
+ diag.help("if the `Arc` will not be used across threads replace it with an `Rc`");
diag.help(format!(
"otherwise make `{arg_ty}` `Send` and `Sync` or consider a wrapper type such as `Mutex`"
));
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index 8b8b42b..52287be 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -98,7 +98,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
// That is overly conservative - the lint should fire even if there was no initializer,
// but the variable has been initialized before `lhs` was evaluated.
&& path_to_local(lhs).is_none_or(|lhs| local_is_initialized(cx, lhs))
- && let Some(resolved_impl) = cx.tcx.impl_of_method(resolved_fn.def_id())
+ && let Some(resolved_impl) = cx.tcx.impl_of_assoc(resolved_fn.def_id())
// Derived forms don't implement `clone_from`/`clone_into`.
// See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305
&& !cx.tcx.is_builtin_derived(resolved_impl)
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 4059f96..b9b5ced 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
@@ -36,6 +36,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
| sym::unused_braces
| sym::unused_import_braces
| sym::unused_imports
+ | sym::redundant_imports
)
{
return;
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 e4dafde..a1543ca 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
@@ -63,7 +63,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
ExprKind::MethodCall(name, self_arg, ..) if self_arg.hir_id == e.hir_id => {
if matches!(name.ident.name, sym::read_unaligned | sym::write_unaligned)
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
- && let Some(def_id) = cx.tcx.impl_of_method(def_id)
+ && let Some(def_id) = cx.tcx.impl_of_assoc(def_id)
&& cx.tcx.type_of(def_id).instantiate_identity().is_raw_ptr()
{
true
diff --git a/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs
index 769cc12..73347e7 100644
--- a/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs
@@ -37,7 +37,7 @@ fn get_const_name_and_ty_name(
} else {
return None;
}
- } else if let Some(impl_id) = cx.tcx.impl_of_method(method_def_id)
+ } else if let Some(impl_id) = cx.tcx.impl_of_assoc(method_def_id)
&& let Some(ty_name) = get_primitive_ty_name(cx.tcx.type_of(impl_id).instantiate_identity())
&& matches!(
method_name,
@@ -59,9 +59,8 @@ fn get_const_name_and_ty_name(
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
// We allow casts from any function type to any function type.
- match cast_to.kind() {
- ty::FnDef(..) | ty::FnPtr(..) => return,
- _ => { /* continue to checks */ },
+ if cast_to.is_fn() {
+ return;
}
if let ty::FnDef(def_id, generics) = cast_from.kind()
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
index 55e27a0..c5d9643 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
@@ -3,7 +3,7 @@
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::Ty;
use super::{FN_TO_NUMERIC_CAST, utils};
@@ -13,23 +13,20 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
return;
};
- match cast_from.kind() {
- ty::FnDef(..) | ty::FnPtr(..) => {
- let mut applicability = Applicability::MaybeIncorrect;
+ if cast_from.is_fn() {
+ let mut applicability = Applicability::MaybeIncorrect;
- if to_nbits >= cx.tcx.data_layout.pointer_size().bits() && !cast_to.is_usize() {
- let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
- span_lint_and_sugg(
- cx,
- FN_TO_NUMERIC_CAST,
- expr.span,
- format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
- "try",
- format!("{from_snippet} as usize"),
- applicability,
- );
- }
- },
- _ => {},
+ if to_nbits >= cx.tcx.data_layout.pointer_size().bits() && !cast_to.is_usize() {
+ let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
+ span_lint_and_sugg(
+ cx,
+ FN_TO_NUMERIC_CAST,
+ expr.span,
+ format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
+ "try",
+ format!("{from_snippet} as usize"),
+ applicability,
+ );
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
index b22e8f4..43ee91a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
@@ -3,18 +3,17 @@
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::Ty;
use super::FN_TO_NUMERIC_CAST_ANY;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
// We allow casts from any function type to any function type.
- match cast_to.kind() {
- ty::FnDef(..) | ty::FnPtr(..) => return,
- _ => { /* continue to checks */ },
+ if cast_to.is_fn() {
+ return;
}
- if let ty::FnDef(..) | ty::FnPtr(..) = cast_from.kind() {
+ if cast_from.is_fn() {
let mut applicability = Applicability::MaybeIncorrect;
let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
index 4da7920..9a2e44e 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
@@ -3,7 +3,7 @@
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::Ty;
use super::{FN_TO_NUMERIC_CAST_WITH_TRUNCATION, utils};
@@ -12,23 +12,20 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
let Some(to_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_to) else {
return;
};
- match cast_from.kind() {
- ty::FnDef(..) | ty::FnPtr(..) => {
- let mut applicability = Applicability::MaybeIncorrect;
- let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
+ if cast_from.is_fn() {
+ let mut applicability = Applicability::MaybeIncorrect;
+ let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
- if to_nbits < cx.tcx.data_layout.pointer_size().bits() {
- span_lint_and_sugg(
- cx,
- FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
- expr.span,
- format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"),
- "try",
- format!("{from_snippet} as usize"),
- applicability,
- );
- }
- },
- _ => {},
+ if to_nbits < cx.tcx.data_layout.pointer_size().bits() {
+ span_lint_and_sugg(
+ cx,
+ FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
+ expr.span,
+ format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"),
+ "try",
+ format!("{from_snippet} as usize"),
+ applicability,
+ );
+ }
}
}
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 6f94491..ee0f3fa 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
@@ -4,10 +4,9 @@
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Mutability, QPath, TyKind};
-use rustc_hir_pretty::qpath_to_string;
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_span::sym;
+use rustc_span::{Span, sym};
use super::PTR_AS_PTR;
@@ -74,7 +73,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) {
let (help, final_suggestion) = if let Some(method) = omit_cast.corresponding_item() {
// don't force absolute path
- let method = qpath_to_string(&cx.tcx, method);
+ let method = snippet_with_applicability(cx, qpath_span_without_turbofish(method), "..", &mut app);
("try call directly", format!("{method}{turbofish}()"))
} else {
let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app);
@@ -96,3 +95,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) {
);
}
}
+
+fn qpath_span_without_turbofish(qpath: &QPath<'_>) -> Span {
+ if let QPath::Resolved(_, path) = qpath
+ && let [.., last_ident] = path.segments
+ && last_ident.args.is_some()
+ {
+ return qpath.span().shrink_to_lo().to(last_ident.ident.span);
+ }
+
+ qpath.span()
+}
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index d5d937d..518535e 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -110,7 +110,6 @@ fn check<'tcx>(
FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span,
FnKind::Closure => {
let header_span = body_span.with_hi(decl.output.span().lo());
- #[expect(clippy::range_plus_one)]
if let Some(range) = header_span.map_range(cx, |_, src, range| {
let mut idxs = src.get(range.clone())?.match_indices('|');
Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1)
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 2791869..4bd3452 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -1,5 +1,6 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::{span_lint, span_lint_and_note, span_lint_and_then};
+use clippy_utils::higher::has_let_expr;
use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet};
use clippy_utils::ty::{InteriorMut, needs_ordered_drop};
use clippy_utils::visitors::for_each_expr_without_closures;
@@ -11,7 +12,7 @@
use core::iter;
use core::ops::ControlFlow;
use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Node, Stmt, StmtKind, intravisit};
+use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Node, Stmt, StmtKind, intravisit};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::TyCtxt;
use rustc_session::impl_lint_pass;
@@ -189,24 +190,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
}
}
-/// Checks if the given expression is a let chain.
-fn contains_let(e: &Expr<'_>) -> bool {
- match e.kind {
- ExprKind::Let(..) => true,
- ExprKind::Binary(op, lhs, rhs) if op.node == BinOpKind::And => {
- matches!(lhs.kind, ExprKind::Let(..)) || contains_let(rhs)
- },
- _ => false,
- }
-}
-
fn lint_if_same_then_else(cx: &LateContext<'_>, conds: &[&Expr<'_>], blocks: &[&Block<'_>]) -> bool {
let mut eq = SpanlessEq::new(cx);
blocks
.array_windows::<2>()
.enumerate()
.fold(true, |all_eq, (i, &[lhs, rhs])| {
- if eq.eq_block(lhs, rhs) && !contains_let(conds[i]) && conds.get(i + 1).is_none_or(|e| !contains_let(e)) {
+ if eq.eq_block(lhs, rhs) && !has_let_expr(conds[i]) && conds.get(i + 1).is_none_or(|e| !has_let_expr(e)) {
span_lint_and_note(
cx,
IF_SAME_THEN_ELSE,
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 5099df3..995a120 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -364,7 +364,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
// priority.
if let Some(fn_id) = typeck.type_dependent_def_id(hir_id)
- && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+ && let Some(trait_id) = cx.tcx.trait_of_assoc(fn_id)
&& let arg_ty = cx.tcx.erase_regions(adjusted_ty)
&& let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
&& let args =
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 062f7ce..49dd1bb 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -432,6 +432,11 @@ fn visit_fn(
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> Self::Result {
if let ExprKind::Block(block, _) = expr.kind
&& block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
+ && block
+ .span
+ .source_callee()
+ .and_then(|expr| expr.macro_def_id)
+ .is_none_or(|did| !self.cx.tcx.is_diagnostic_item(sym::pin_macro, did))
{
return ControlFlow::Break(());
}
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index d55aeae..23e7c72 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -72,11 +72,11 @@ pub struct DisallowedMacros {
// When a macro is disallowed in an early pass, it's stored
// and emitted during the late pass. This happens for attributes.
- earlies: AttrStorage,
+ early_macro_cache: AttrStorage,
}
impl DisallowedMacros {
- pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf, earlies: AttrStorage) -> Self {
+ pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf, early_macro_cache: AttrStorage) -> Self {
let (disallowed, _) = create_disallowed_map(
tcx,
&conf.disallowed_macros,
@@ -89,7 +89,7 @@ pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf, earlies: AttrStorage) -> Self {
disallowed,
seen: FxHashSet::default(),
derive_src: None,
- earlies,
+ early_macro_cache,
}
}
@@ -130,7 +130,7 @@ fn check(&mut self, cx: &LateContext<'_>, span: Span, derive_src: Option<OwnerId
impl LateLintPass<'_> for DisallowedMacros {
fn check_crate(&mut self, cx: &LateContext<'_>) {
// once we check a crate in the late pass we can emit the early pass lints
- if let Some(attr_spans) = self.earlies.clone().0.get() {
+ if let Some(attr_spans) = self.early_macro_cache.clone().0.get() {
for span in attr_spans {
self.check(cx, *span, None);
}
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 22b781b..ea0da0d 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -1232,7 +1232,6 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
headers
}
-#[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 {
return None;
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 4414aeb..f275740 100644
--- a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
@@ -92,8 +92,10 @@ pub struct EmptyWithBrackets {
impl LateLintPass<'_> for EmptyWithBrackets {
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+ // FIXME: handle `struct $name {}`
if let ItemKind::Struct(ident, _, var_data) = &item.kind
&& !item.span.from_expansion()
+ && !ident.span.from_expansion()
&& has_brackets(var_data)
&& let span_after_ident = item.span.with_lo(ident.span.hi())
&& has_no_fields(cx, var_data, span_after_ident)
@@ -116,10 +118,12 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
}
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_no_fields(cx, &variant.data, span_after_ident) {
+ // FIXME: handle `$name {}`
+ if !variant.span.from_expansion()
+ && !variant.ident.span.from_expansion()
+ && let span_after_ident = variant.span.with_lo(variant.ident.span.hi())
+ && has_no_fields(cx, &variant.data, span_after_ident)
+ {
match variant.data {
VariantData::Struct { .. } => {
// Empty struct variants can be linted immediately
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index db2fea1..fc224fa 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -1,8 +1,8 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_hir;
use rustc_abi::ExternAbi;
-use rustc_hir::{Body, FnDecl, HirId, HirIdSet, Node, Pat, PatKind, intravisit};
use rustc_hir::def::DefKind;
+use rustc_hir::{Body, FnDecl, HirId, HirIdSet, Node, Pat, PatKind, intravisit};
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::FakeReadCause;
@@ -87,16 +87,14 @@ fn check_fn(
let mut trait_self_ty = None;
match cx.tcx.def_kind(parent_id) {
// If the method is an impl for a trait, don't warn.
- DefKind::Impl { of_trait: true } => {
- return
- }
+ DefKind::Impl { of_trait: true } => return,
// find `self` ty for this trait if relevant
DefKind::Trait => {
trait_self_ty = Some(TraitRef::identity(cx.tcx, parent_id.to_def_id()).self_ty());
- }
+ },
- _ => {}
+ _ => {},
}
let mut v = EscapeDelegate {
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 0288747..9b62767 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -29,12 +29,6 @@
/// Needlessly creating a closure adds code for no benefit
/// and gives the optimizer more work.
///
- /// ### Known problems
- /// If creating the closure inside the closure has a side-
- /// effect then moving the closure creation out will change when that side-
- /// effect runs.
- /// See [#1439](https://github.com/rust-lang/rust-clippy/issues/1439) for more details.
- ///
/// ### Example
/// ```rust,ignore
/// xs.map(|x| foo(x))
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 552cd72..fdfcbb5 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -64,8 +64,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
}
fn lint_impl_body(cx: &LateContext<'_>, item_def_id: hir::OwnerId, impl_span: Span) {
- use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::Expr;
+ use rustc_hir::intravisit::{self, Visitor};
struct FindPanicUnwrap<'a, 'tcx> {
lcx: &'a LateContext<'tcx>,
@@ -96,10 +96,12 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
}
}
- for impl_item in cx.tcx.associated_items(item_def_id)
+ for impl_item in cx
+ .tcx
+ .associated_items(item_def_id)
.filter_by_name_unhygienic_and_kind(sym::from, ty::AssocTag::Fn)
{
- let impl_item_def_id= impl_item.def_id.expect_local();
+ let impl_item_def_id = impl_item.def_id.expect_local();
// check the body for `begin_panic` or `unwrap`
let body = cx.tcx.hir_body_owned_by(impl_item_def_id);
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 16c58ec..a251f15 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -17,7 +17,7 @@
FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions,
FormatPlaceholder, FormatTrait,
};
-use rustc_attr_data_structures::RustcVersion;
+use rustc_attr_data_structures::{AttributeKind, RustcVersion, find_attr};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode};
@@ -30,7 +30,6 @@
use rustc_span::{Span, Symbol, sym};
use rustc_trait_selection::infer::TyCtxtInferExt;
use rustc_trait_selection::traits::{Obligation, ObligationCause, Selection, SelectionContext};
-use rustc_attr_data_structures::{AttributeKind, find_attr};
declare_clippy_lint! {
/// ### What it does
@@ -129,6 +128,7 @@
/// # let width = 1;
/// # let prec = 2;
/// format!("{}", var);
+ /// format!("{:?}", var);
/// format!("{v:?}", v = var);
/// format!("{0} {0}", var);
/// format!("{0:1$}", var, width);
@@ -141,6 +141,7 @@
/// # let prec = 2;
/// format!("{var}");
/// format!("{var:?}");
+ /// format!("{var:?}");
/// format!("{var} {var}");
/// format!("{var:width$}");
/// format!("{var:.prec$}");
@@ -164,7 +165,7 @@
/// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
#[clippy::version = "1.66.0"]
pub UNINLINED_FORMAT_ARGS,
- style,
+ pedantic,
"using non-inlined variables in `format!` calls"
}
@@ -657,7 +658,10 @@ fn has_pointer_debug(&mut self, ty: Ty<'tcx>, depth: usize) -> bool {
};
let selection = SelectionContext::new(&infcx).select(&obligation);
let derived = if let Ok(Some(Selection::UserDefined(data))) = selection {
- find_attr!(tcx.get_all_attrs(data.impl_def_id), AttributeKind::AutomaticallyDerived(..))
+ find_attr!(
+ tcx.get_all_attrs(data.impl_def_id),
+ AttributeKind::AutomaticallyDerived(..)
+ )
} else {
false
};
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 85b40ba..1da6952 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -9,7 +9,7 @@
use rustc_errors::Applicability;
use rustc_hir::intravisit::{Visitor, walk_path};
use rustc_hir::{
- FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemId, Item, ItemKind, PatKind, Path,
+ FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItemId, ImplItemKind, Item, ItemKind, PatKind, Path,
PathSegment, Ty, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index d959981..b8d0cec 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -10,7 +10,7 @@
use clippy_utils::attrs::is_proc_macro;
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
-use clippy_utils::source::SpanRangeExt;
+use clippy_utils::source::snippet_indent;
use clippy_utils::ty::is_must_use_ty;
use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{return_ty, trait_ref_of_method};
@@ -28,6 +28,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
if let hir::ItemKind::Fn {
ref sig,
body: ref body_id,
+ ident,
..
} = item.kind
{
@@ -51,8 +52,8 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
sig.decl,
cx.tcx.hir_body(*body_id),
item.span,
+ ident.span,
item.owner_id,
- item.span.with_hi(sig.decl.output.span().hi()),
"this function could have a `#[must_use]` attribute",
);
}
@@ -84,8 +85,8 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
sig.decl,
cx.tcx.hir_body(*body_id),
item.span,
+ item.ident.span,
item.owner_id,
- item.span.with_hi(sig.decl.output.span().hi()),
"this method could have a `#[must_use]` attribute",
);
}
@@ -120,8 +121,8 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
sig.decl,
body,
item.span,
+ item.ident.span,
item.owner_id,
- item.span.with_hi(sig.decl.output.span().hi()),
"this method could have a `#[must_use]` attribute",
);
}
@@ -198,8 +199,8 @@ fn check_must_use_candidate<'tcx>(
decl: &'tcx hir::FnDecl<'_>,
body: &'tcx hir::Body<'_>,
item_span: Span,
+ ident_span: Span,
item_id: hir::OwnerId,
- fn_span: Span,
msg: &'static str,
) {
if has_mutable_arg(cx, body)
@@ -208,18 +209,18 @@ fn check_must_use_candidate<'tcx>(
|| returns_unit(decl)
|| !cx.effective_visibilities.is_exported(item_id.def_id)
|| is_must_use_ty(cx, return_ty(cx, item_id))
+ || item_span.from_expansion()
{
return;
}
- span_lint_and_then(cx, MUST_USE_CANDIDATE, fn_span, msg, |diag| {
- if let Some(snippet) = fn_span.get_source_text(cx) {
- diag.span_suggestion(
- fn_span,
- "add the attribute",
- format!("#[must_use] {snippet}"),
- Applicability::MachineApplicable,
- );
- }
+ span_lint_and_then(cx, MUST_USE_CANDIDATE, ident_span, msg, |diag| {
+ let indent = snippet_indent(cx, item_span).unwrap_or_default();
+ diag.span_suggestion(
+ item_span.shrink_to_lo(),
+ "add the attribute",
+ format!("#[must_use] \n{indent}"),
+ Applicability::MachineApplicable,
+ );
});
}
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 9e94280..7158f94 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
@@ -5,7 +5,8 @@
use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg::Sugg;
use clippy_utils::{
- contains_return, higher, is_else_clause, is_in_const_context, is_res_lang_ctor, path_res, peel_blocks,
+ contains_return, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, is_res_lang_ctor,
+ path_res, peel_blocks,
};
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -92,6 +93,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
expr.span,
format!("this could be simplified with `bool::{method_name}`"),
|diag| {
+ if expr_adjustment_requires_coercion(cx, then_arg) {
+ return;
+ }
+
let mut app = Applicability::MachineApplicable;
let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app)
.maybe_paren()
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 c743501..c634c12 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -339,7 +339,7 @@ fn check_with_condition<'tcx>(
ExprKind::Path(QPath::TypeRelative(_, name)) => {
if name.ident.name == sym::MIN
&& let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(const_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(const_id)
&& let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl
&& cx.tcx.type_of(impl_id).instantiate_identity().is_integral()
{
@@ -350,7 +350,7 @@ fn check_with_condition<'tcx>(
if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind
&& name.ident.name == sym::min_value
&& let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(func_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(func_id)
&& let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl
&& cx.tcx.type_of(impl_id).instantiate_identity().is_integral()
{
diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
index 5d0bd3e..116d63c 100644
--- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
+++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
@@ -1,10 +1,11 @@
use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_in_test;
+use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::Msrv;
+use clippy_utils::{is_in_const_context, is_in_test};
use rustc_attr_data_structures::{RustcVersion, StabilityLevel, StableSince};
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::{Expr, ExprKind, HirId, QPath};
+use rustc_hir::def::DefKind;
+use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, HirId, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::TyCtxt;
use rustc_session::impl_lint_pass;
@@ -33,15 +34,54 @@
///
/// To fix this problem, either increase your MSRV or use another item
/// available in your current MSRV.
+ ///
+ /// You can also locally change the MSRV that should be checked by Clippy,
+ /// for example if a feature in your crate (e.g., `modern_compiler`) should
+ /// allow you to use an item:
+ ///
+ /// ```no_run
+ /// //! This crate has a MSRV of 1.3.0, but we also have an optional feature
+ /// //! `sleep_well` which requires at least Rust 1.4.0.
+ ///
+ /// // When the `sleep_well` feature is set, do not warn for functions available
+ /// // in Rust 1.4.0 and below.
+ /// #![cfg_attr(feature = "sleep_well", clippy::msrv = "1.4.0")]
+ ///
+ /// use std::time::Duration;
+ ///
+ /// #[cfg(feature = "sleep_well")]
+ /// fn sleep_for_some_time() {
+ /// std::thread::sleep(Duration::new(1, 0)); // Will not trigger the lint
+ /// }
+ /// ```
+ ///
+ /// You can also increase the MSRV in tests, by using:
+ ///
+ /// ```no_run
+ /// // Use a much higher MSRV for tests while keeping the main one low
+ /// #![cfg_attr(test, clippy::msrv = "1.85.0")]
+ ///
+ /// #[test]
+ /// fn my_test() {
+ /// // The tests can use items introduced in Rust 1.85.0 and lower
+ /// // without triggering the `incompatible_msrv` lint.
+ /// }
+ /// ```
#[clippy::version = "1.78.0"]
pub INCOMPATIBLE_MSRV,
suspicious,
"ensures that all items used in the crate are available for the current MSRV"
}
+#[derive(Clone, Copy)]
+enum Availability {
+ FeatureEnabled,
+ Since(RustcVersion),
+}
+
pub struct IncompatibleMsrv {
msrv: Msrv,
- is_above_msrv: FxHashMap<DefId, RustcVersion>,
+ availability_cache: FxHashMap<(DefId, bool), Availability>,
check_in_tests: bool,
}
@@ -51,38 +91,50 @@ impl IncompatibleMsrv {
pub fn new(conf: &'static Conf) -> Self {
Self {
msrv: conf.msrv,
- is_above_msrv: FxHashMap::default(),
+ availability_cache: FxHashMap::default(),
check_in_tests: conf.check_incompatible_msrv_in_tests,
}
}
- fn get_def_id_version(&mut self, tcx: TyCtxt<'_>, def_id: DefId) -> RustcVersion {
- if let Some(version) = self.is_above_msrv.get(&def_id) {
- return *version;
+ /// Returns the availability of `def_id`, whether it is enabled through a feature or
+ /// available since a given version (the default being Rust 1.0.0). `needs_const` requires
+ /// the `const`-stability to be looked up instead of the stability in non-`const` contexts.
+ fn get_def_id_availability(&mut self, tcx: TyCtxt<'_>, def_id: DefId, needs_const: bool) -> Availability {
+ if let Some(availability) = self.availability_cache.get(&(def_id, needs_const)) {
+ return *availability;
}
- let version = if let Some(version) = tcx
- .lookup_stability(def_id)
- .and_then(|stability| match stability.level {
- StabilityLevel::Stable {
- since: StableSince::Version(version),
- ..
- } => Some(version),
- _ => None,
- }) {
- version
- } else if let Some(parent_def_id) = tcx.opt_parent(def_id) {
- self.get_def_id_version(tcx, parent_def_id)
+ let (feature, stability_level) = if needs_const {
+ tcx.lookup_const_stability(def_id)
+ .map(|stability| (stability.feature, stability.level))
+ .unzip()
} else {
- RustcVersion {
+ tcx.lookup_stability(def_id)
+ .map(|stability| (stability.feature, stability.level))
+ .unzip()
+ };
+ let version = if feature.is_some_and(|feature| tcx.features().enabled(feature)) {
+ Availability::FeatureEnabled
+ } else if let Some(StableSince::Version(version)) =
+ stability_level.as_ref().and_then(StabilityLevel::stable_since)
+ {
+ Availability::Since(version)
+ } else if needs_const {
+ // Fallback to regular stability
+ self.get_def_id_availability(tcx, def_id, false)
+ } else if let Some(parent_def_id) = tcx.opt_parent(def_id) {
+ self.get_def_id_availability(tcx, parent_def_id, needs_const)
+ } else {
+ Availability::Since(RustcVersion {
major: 1,
minor: 0,
patch: 0,
- }
+ })
};
- self.is_above_msrv.insert(def_id, version);
+ self.availability_cache.insert((def_id, needs_const), version);
version
}
+ /// Emit lint if `def_id`, associated with `node` and `span`, is below the current MSRV.
fn emit_lint_if_under_msrv(&mut self, cx: &LateContext<'_>, def_id: DefId, node: HirId, span: Span) {
if def_id.is_local() {
// We don't check local items since their MSRV is supposed to always be valid.
@@ -108,18 +160,28 @@ fn emit_lint_if_under_msrv(&mut self, cx: &LateContext<'_>, def_id: DefId, node:
return;
}
+ let needs_const = cx.enclosing_body.is_some()
+ && is_in_const_context(cx)
+ && matches!(cx.tcx.def_kind(def_id), DefKind::AssocFn | DefKind::Fn);
+
if (self.check_in_tests || !is_in_test(cx.tcx, node))
&& let Some(current) = self.msrv.current(cx)
- && let version = self.get_def_id_version(cx.tcx, def_id)
+ && let Availability::Since(version) = self.get_def_id_availability(cx.tcx, def_id, needs_const)
&& version > current
{
- span_lint(
+ span_lint_and_then(
cx,
INCOMPATIBLE_MSRV,
span,
format!(
- "current MSRV (Minimum Supported Rust Version) is `{current}` but this item is stable since `{version}`"
+ "current MSRV (Minimum Supported Rust Version) is `{current}` but this item is stable{} since `{version}`",
+ if needs_const { " in a `const` context" } else { "" },
),
+ |diag| {
+ if is_under_cfg_attribute(cx, node) {
+ diag.note_once("you may want to conditionally increase the MSRV considered by Clippy using the `clippy::msrv` attribute");
+ }
+ },
);
}
}
@@ -133,17 +195,38 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
self.emit_lint_if_under_msrv(cx, method_did, expr.hir_id, span);
}
},
- ExprKind::Call(call, _) => {
- // Desugaring into function calls by the compiler will use `QPath::LangItem` variants. Those should
- // not be linted as they will not be generated in older compilers if the function is not available,
- // and the compiler is allowed to call unstable functions.
- if let ExprKind::Path(qpath @ (QPath::Resolved(..) | QPath::TypeRelative(..))) = call.kind
- && let Some(path_def_id) = cx.qpath_res(&qpath, call.hir_id).opt_def_id()
- {
- self.emit_lint_if_under_msrv(cx, path_def_id, expr.hir_id, call.span);
+ // Desugaring into function calls by the compiler will use `QPath::LangItem` variants. Those should
+ // not be linted as they will not be generated in older compilers if the function is not available,
+ // and the compiler is allowed to call unstable functions.
+ ExprKind::Path(qpath @ (QPath::Resolved(..) | QPath::TypeRelative(..))) => {
+ if let Some(path_def_id) = cx.qpath_res(&qpath, expr.hir_id).opt_def_id() {
+ self.emit_lint_if_under_msrv(cx, path_def_id, expr.hir_id, expr.span);
}
},
_ => {},
}
}
+
+ fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
+ if let hir::TyKind::Path(qpath @ (QPath::Resolved(..) | QPath::TypeRelative(..))) = hir_ty.kind
+ && let Some(ty_def_id) = cx.qpath_res(&qpath, hir_ty.hir_id).opt_def_id()
+ // `CStr` and `CString` have been moved around but have been available since Rust 1.0.0
+ && !matches!(cx.tcx.get_diagnostic_name(ty_def_id), Some(sym::cstr_type | sym::cstring_type))
+ {
+ self.emit_lint_if_under_msrv(cx, ty_def_id, hir_ty.hir_id, hir_ty.span);
+ }
+ }
+}
+
+/// Heuristic checking if the node `hir_id` is under a `#[cfg()]` or `#[cfg_attr()]`
+/// attribute.
+fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool {
+ cx.tcx.hir_parent_id_iter(hir_id).any(|id| {
+ cx.tcx.hir_attrs(id).iter().any(|attr| {
+ matches!(
+ attr.ident().map(|ident| ident.name),
+ Some(sym::cfg_trace | sym::cfg_attr_trace)
+ )
+ })
+ })
}
diff --git a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
index 7a75151..a159f61 100644
--- a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
@@ -1,13 +1,12 @@
-use crate::methods::method_call;
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{peel_blocks, sym};
+use clippy_utils::source::SpanRangeExt;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{peel_blocks, peel_hir_expr_while, sym};
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
use rustc_session::declare_lint_pass;
-use rustc_span::{BytePos, Span};
declare_clippy_lint! {
/// ### What it does
@@ -43,53 +42,58 @@
declare_lint_pass!(IneffectiveOpenOptions => [INEFFECTIVE_OPEN_OPTIONS]);
-fn index_if_arg_is_boolean(args: &[Expr<'_>], call_span: Span) -> Option<Span> {
- if let [arg] = args
- && let ExprKind::Lit(lit) = peel_blocks(arg).kind
- && lit.node == LitKind::Bool(true)
- {
- // The `.` is not included in the span so we cheat a little bit to include it as well.
- Some(call_span.with_lo(call_span.lo() - BytePos(1)))
- } else {
- None
- }
-}
-
impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- let Some((sym::open, mut receiver, [_arg], _, _)) = method_call(expr) else {
- return;
- };
- let receiver_ty = cx.typeck_results().expr_ty(receiver);
- match receiver_ty.peel_refs().kind() {
- ty::Adt(adt, _) if cx.tcx.is_diagnostic_item(sym::FsOpenOptions, adt.did()) => {},
- _ => return,
- }
-
- let mut append = None;
- let mut write = None;
-
- while let Some((name, recv, args, _, span)) = method_call(receiver) {
- if name == sym::append {
- append = index_if_arg_is_boolean(args, span);
- } else if name == sym::write {
- write = index_if_arg_is_boolean(args, span);
- }
- receiver = recv;
- }
-
- if let Some(write_span) = write
- && append.is_some()
+ if let ExprKind::MethodCall(name, recv, [_], _) = expr.kind
+ && name.ident.name == sym::open
+ && !expr.span.from_expansion()
+ && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::FsOpenOptions)
{
- span_lint_and_sugg(
- cx,
- INEFFECTIVE_OPEN_OPTIONS,
- write_span,
- "unnecessary use of `.write(true)` because there is `.append(true)`",
- "remove `.write(true)`",
- String::new(),
- Applicability::MachineApplicable,
- );
+ let mut append = false;
+ let mut write = None;
+ peel_hir_expr_while(recv, |e| {
+ if let ExprKind::MethodCall(name, recv, args, call_span) = e.kind
+ && !e.span.from_expansion()
+ {
+ if let [arg] = args
+ && let ExprKind::Lit(lit) = peel_blocks(arg).kind
+ && matches!(lit.node, LitKind::Bool(true))
+ && !arg.span.from_expansion()
+ && !lit.span.from_expansion()
+ {
+ match name.ident.name {
+ sym::append => append = true,
+ sym::write
+ if let Some(range) = call_span.map_range(cx, |_, text, range| {
+ if text.get(..range.start)?.ends_with('.') {
+ Some(range.start - 1..range.end)
+ } else {
+ None
+ }
+ }) =>
+ {
+ write = Some(call_span.with_lo(range.start));
+ },
+ _ => {},
+ }
+ }
+ Some(recv)
+ } else {
+ None
+ }
+ });
+
+ if append && let Some(write_span) = write {
+ span_lint_and_sugg(
+ cx,
+ INEFFECTIVE_OPEN_OPTIONS,
+ write_span,
+ "unnecessary use of `.write(true)` because there is `.append(true)`",
+ "remove `.write(true)`",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ }
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/infallible_try_from.rs b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs
index e79fcec..f7cdf05 100644
--- a/src/tools/clippy/clippy_lints/src/infallible_try_from.rs
+++ b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs
@@ -52,13 +52,17 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
if !cx.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id) {
return;
}
- for ii in cx.tcx.associated_items(item.owner_id.def_id)
+ for ii in cx
+ .tcx
+ .associated_items(item.owner_id.def_id)
.filter_by_name_unhygienic_and_kind(sym::Error, AssocTag::Type)
{
let ii_ty = cx.tcx.type_of(ii.def_id).instantiate_identity();
if !ii_ty.is_inhabited_from(cx.tcx, ii.def_id, cx.typing_env()) {
let mut span = MultiSpan::from_span(cx.tcx.def_span(item.owner_id.to_def_id()));
- let ii_ty_span = cx.tcx.hir_node_by_def_id(ii.def_id.expect_local())
+ let ii_ty_span = cx
+ .tcx
+ .hir_node_by_def_id(ii.def_id.expect_local())
.expect_impl_item()
.expect_type()
.span;
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 9c91cf6..95e16aa 100644
--- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
+++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
@@ -8,6 +8,7 @@
use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, QPath, TyKind, Variant, VariantData};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
+use rustc_span::MacroKind;
use rustc_span::symbol::Symbol;
declare_clippy_lint! {
@@ -502,7 +503,8 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
);
}
- if both_are_public && item_camel.len() > mod_camel.len() {
+ let is_macro_rule = matches!(item.kind, ItemKind::Macro(_, _, MacroKind::Bang));
+ if both_are_public && item_camel.len() > mod_camel.len() && !is_macro_rule {
let matching = count_match_start(mod_camel, &item_camel);
let rmatching = count_match_end(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 03038f0..b89f91f 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -139,11 +139,17 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
// We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method
ty.peel_refs().is_slice() || get_adt_inherent_method(cx, ty, expected_method_name).is_some()
})
- && let Some(iter_assoc_span) = cx.tcx.associated_items(item.owner_id)
+ && let Some(iter_assoc_span) = cx
+ .tcx
+ .associated_items(item.owner_id)
.filter_by_name_unhygienic_and_kind(sym::IntoIter, ty::AssocTag::Type)
.next()
.map(|assoc_item| {
- cx.tcx.hir_node_by_def_id(assoc_item.def_id.expect_local()).expect_impl_item().expect_type().span
+ cx.tcx
+ .hir_node_by_def_id(assoc_item.def_id.expect_local())
+ .expect_impl_item()
+ .expect_type()
+ .span
})
&& is_ty_exported(cx, ty)
{
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index e85d779..c2b7394 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -1,5 +1,6 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_no_std_crate;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_copy};
use rustc_errors::Applicability;
@@ -83,7 +84,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
let mut difference = variants_size[0].size - variants_size[1].size;
if difference > self.maximum_size_difference_allowed {
- let help_text = "consider boxing the large fields to reduce the total size of the enum";
+ let help_text = "consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum";
span_lint_and_then(
cx,
LARGE_ENUM_VARIANT,
@@ -117,7 +118,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
ident.span,
"boxing a variant would require the type no longer be `Copy`",
);
- } else {
+ } else if !is_no_std_crate(cx) {
let sugg: Vec<(Span, String)> = variants_size[0]
.fields_size
.iter()
diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
index b3c63f0..42c6365 100644
--- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
@@ -1,7 +1,8 @@
use clippy_config::Conf;
-use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_from_proc_macro;
use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::{get_parent_expr, is_from_proc_macro};
+use clippy_utils::source::SpanRangeExt;
use hir::def_id::DefId;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -102,39 +103,45 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
}
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
- let ExprKind::Path(qpath) = &expr.kind else {
- return;
- };
-
// `std::<integer>::<CONST>` check
- let (span, sugg, msg) = if let QPath::Resolved(None, path) = qpath
+ let (sugg, msg) = if let ExprKind::Path(qpath) = &expr.kind
+ && let QPath::Resolved(None, path) = qpath
&& let Some(def_id) = path.res.opt_def_id()
&& is_numeric_const(cx, def_id)
- && let def_path = cx.get_def_path(def_id)
- && let [.., mod_name, name] = &*def_path
+ && let [.., mod_name, name] = &*cx.get_def_path(def_id)
// Skip linting if this usage looks identical to the associated constant,
// since this would only require removing a `use` import (which is already linted).
&& !is_numeric_const_path_canonical(path, [*mod_name, *name])
{
(
- expr.span,
- format!("{mod_name}::{name}"),
+ vec![(expr.span, format!("{mod_name}::{name}"))],
"usage of a legacy numeric constant",
)
// `<integer>::xxx_value` check
- } else if let QPath::TypeRelative(_, last_segment) = qpath
- && let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id()
- && let Some(par_expr) = get_parent_expr(cx, expr)
- && let ExprKind::Call(_, []) = par_expr.kind
+ } else if let ExprKind::Call(func, []) = &expr.kind
+ && let ExprKind::Path(qpath) = &func.kind
+ && let QPath::TypeRelative(ty, last_segment) = qpath
+ && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id()
&& is_integer_method(cx, def_id)
{
- let name = last_segment.ident.name.as_str();
-
- (
- last_segment.ident.span.with_hi(par_expr.span.hi()),
- name[..=2].to_ascii_uppercase(),
- "usage of a legacy numeric method",
- )
+ let mut sugg = vec![
+ // Replace the function name up to the end by the constant name
+ (
+ last_segment.ident.span.to(expr.span.shrink_to_hi()),
+ last_segment.ident.name.as_str()[..=2].to_ascii_uppercase(),
+ ),
+ ];
+ let before_span = expr.span.shrink_to_lo().until(ty.span);
+ if !before_span.is_empty() {
+ // Remove everything before the type name
+ sugg.push((before_span, String::new()));
+ }
+ // Use `::` between the type name and the constant
+ let between_span = ty.span.shrink_to_hi().until(last_segment.ident.span);
+ if !between_span.check_source_text(cx, |s| s == "::") {
+ sugg.push((between_span, String::from("::")));
+ }
+ (sugg, "usage of a legacy numeric method")
} else {
return;
};
@@ -143,9 +150,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
&& self.msrv.meets(cx, msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
&& !is_from_proc_macro(cx, expr)
{
- span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| {
- diag.span_suggestion_verbose(
- span,
+ span_lint_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.span, msg, |diag| {
+ diag.multipart_suggestion_verbose(
"use the associated constant instead",
sugg,
Applicability::MaybeIncorrect,
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 1bf0348..6beddc1 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -10,9 +10,9 @@
use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::{
- BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, HirId, ImplItem, ImplItemKind,
- ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy,
- QPath, TraitItemId, TyKind,
+ BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, HirId, ImplItem, ImplItemKind, ImplicitSelfKind,
+ Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy, QPath, TraitItemId,
+ TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, FnSig, Ty};
@@ -266,11 +266,14 @@ fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span {
}
fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Ident, trait_items: &[TraitItemId]) {
- fn is_named_self(cx: &LateContext<'_>, item: &TraitItemId, name: Symbol) -> bool {
+ fn is_named_self(cx: &LateContext<'_>, item: TraitItemId, name: Symbol) -> bool {
cx.tcx.item_name(item.owner_id) == name
&& matches!(
cx.tcx.fn_arg_idents(item.owner_id),
- [Some(Ident { name: kw::SelfLower, .. })],
+ [Some(Ident {
+ name: kw::SelfLower,
+ ..
+ })],
)
}
@@ -284,7 +287,7 @@ fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) {
}
if cx.effective_visibilities.is_exported(visited_trait.owner_id.def_id)
- && trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
+ && trait_items.iter().any(|&i| is_named_self(cx, i, sym::len))
{
let mut current_and_super_traits = DefIdSet::default();
fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx);
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 7837b18..7bb684d 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
@@ -39,7 +39,9 @@ pub(super) fn check<'tcx>(
var: canonical_id,
indexed_mut: FxHashSet::default(),
indexed_indirectly: FxHashMap::default(),
+ unnamed_indexed_indirectly: false,
indexed_directly: FxIndexMap::default(),
+ unnamed_indexed_directly: false,
referenced: FxHashSet::default(),
nonindex: false,
prefer_mutable: false,
@@ -47,7 +49,11 @@ pub(super) fn check<'tcx>(
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 {
+ if visitor.indexed_indirectly.is_empty()
+ && !visitor.unnamed_indexed_indirectly
+ && !visitor.unnamed_indexed_directly
+ && visitor.indexed_directly.len() == 1
+ {
let (indexed, (indexed_extent, indexed_ty)) = visitor
.indexed_directly
.into_iter()
@@ -217,6 +223,7 @@ fn is_end_eq_array_len<'tcx>(
false
}
+#[expect(clippy::struct_excessive_bools)]
struct VarVisitor<'a, 'tcx> {
/// context reference
cx: &'a LateContext<'tcx>,
@@ -226,9 +233,13 @@ struct VarVisitor<'a, 'tcx> {
indexed_mut: FxHashSet<Symbol>,
/// indirectly indexed variables (`v[(i + 4) % N]`), the extend is `None` for global
indexed_indirectly: FxHashMap<Symbol, Option<region::Scope>>,
+ /// indirectly indexed literals, like `[1, 2, 3][(i + 4) % N]`
+ unnamed_indexed_indirectly: bool,
/// subset of `indexed` of vars that are indexed directly: `v[i]`
/// this will not contain cases like `v[calc_index(i)]` or `v[(i + 4) % N]`
indexed_directly: FxIndexMap<Symbol, (Option<region::Scope>, Ty<'tcx>)>,
+ /// directly indexed literals, like `[1, 2, 3][i]`
+ unnamed_indexed_directly: bool,
/// Any names that are used outside an index operation.
/// Used to detect things like `&mut vec` used together with `vec[i]`
referenced: FxHashSet<Symbol>,
@@ -242,6 +253,7 @@ struct VarVisitor<'a, 'tcx> {
impl<'tcx> VarVisitor<'_, 'tcx> {
fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool {
+ let index_used_directly = matches!(idx.kind, ExprKind::Path(_));
if let ExprKind::Path(ref seqpath) = seqexpr.kind
// the indexed container is referenced by a name
&& let QPath::Resolved(None, seqvar) = *seqpath
@@ -251,7 +263,6 @@ fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Ex
if self.prefer_mutable {
self.indexed_mut.insert(seqvar.segments[0].ident.name);
}
- let index_used_directly = matches!(idx.kind, ExprKind::Path(_));
let res = self.cx.qpath_res(seqpath, seqexpr.hir_id);
match res {
Res::Local(hir_id) => {
@@ -286,6 +297,13 @@ fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Ex
},
_ => (),
}
+ } else if let ExprKind::Repeat(..) | ExprKind::Array(..) = seqexpr.kind {
+ if index_used_directly {
+ self.unnamed_indexed_directly = true;
+ } else {
+ self.unnamed_indexed_indirectly = true;
+ }
+ return false;
}
true
}
@@ -299,7 +317,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
.cx
.typeck_results()
.type_dependent_def_id(expr.hir_id)
- .and_then(|def_id| self.cx.tcx.trait_of_item(def_id))
+ .and_then(|def_id| self.cx.tcx.trait_of_assoc(def_id))
&& ((meth.ident.name == sym::index && self.cx.tcx.lang_items().index_trait() == Some(trait_id))
|| (meth.ident.name == sym::index_mut && self.cx.tcx.lang_items().index_mut_trait() == Some(trait_id)))
&& !self.check(args_1, args_0, 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 69c84bc..8a253ae 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -6,9 +6,11 @@
use clippy_utils::source::snippet;
use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
use rustc_errors::Applicability;
-use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind, StructTailExpr};
+use rustc_hir::{
+ Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Node, Pat, Stmt, StmtKind, StructTailExpr,
+};
use rustc_lint::LateContext;
-use rustc_span::{Span, sym};
+use rustc_span::{BytePos, Span, sym};
use std::iter::once;
use std::ops::ControlFlow;
@@ -20,7 +22,7 @@ pub(super) fn check<'tcx>(
for_loop: Option<&ForLoop<'_>>,
) {
match never_loop_block(cx, block, &mut Vec::new(), loop_id) {
- NeverLoopResult::Diverging => {
+ NeverLoopResult::Diverging { ref break_spans } => {
span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| {
if let Some(ForLoop {
arg: iterator,
@@ -38,10 +40,15 @@ pub(super) fn check<'tcx>(
Applicability::Unspecified
};
- diag.span_suggestion_verbose(
+ let mut suggestions = vec![(
for_span.with_hi(iterator.span.hi()),
- "if you need the first element of the iterator, try writing",
for_to_if_let_sugg(cx, iterator, pat),
+ )];
+ // Make sure to clear up the diverging sites when we remove a loopp.
+ suggestions.extend(break_spans.iter().map(|span| (*span, String::new())));
+ diag.multipart_suggestion_verbose(
+ "if you need the first element of the iterator, try writing",
+ suggestions,
app,
);
}
@@ -70,22 +77,22 @@ fn contains_any_break_or_continue(block: &Block<'_>) -> bool {
/// The first two bits of information are in this enum, and the last part is in the
/// `local_labels` variable, which contains a list of `(block_id, reachable)` pairs ordered by
/// scope.
-#[derive(Copy, Clone)]
+#[derive(Clone)]
enum NeverLoopResult {
/// A continue may occur for the main loop.
MayContinueMainLoop,
/// We have not encountered any main loop continue,
/// but we are diverging (subsequent control flow is not reachable)
- Diverging,
+ Diverging { break_spans: Vec<Span> },
/// We have not encountered any main loop continue,
/// and subsequent control flow is (possibly) reachable
Normal,
}
#[must_use]
-fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
+fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult {
match arg {
- NeverLoopResult::Diverging | NeverLoopResult::Normal => NeverLoopResult::Normal,
+ NeverLoopResult::Diverging { .. } | NeverLoopResult::Normal => NeverLoopResult::Normal,
NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
}
}
@@ -94,7 +101,7 @@ fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
#[must_use]
fn combine_seq(first: NeverLoopResult, second: impl FnOnce() -> NeverLoopResult) -> NeverLoopResult {
match first {
- NeverLoopResult::Diverging | NeverLoopResult::MayContinueMainLoop => first,
+ NeverLoopResult::Diverging { .. } | NeverLoopResult::MayContinueMainLoop => first,
NeverLoopResult::Normal => second(),
}
}
@@ -103,7 +110,7 @@ fn combine_seq(first: NeverLoopResult, second: impl FnOnce() -> NeverLoopResult)
#[must_use]
fn combine_seq_many(iter: impl IntoIterator<Item = NeverLoopResult>) -> NeverLoopResult {
for e in iter {
- if let NeverLoopResult::Diverging | NeverLoopResult::MayContinueMainLoop = e {
+ if let NeverLoopResult::Diverging { .. } | NeverLoopResult::MayContinueMainLoop = e {
return e;
}
}
@@ -118,7 +125,19 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
NeverLoopResult::MayContinueMainLoop
},
(NeverLoopResult::Normal, _) | (_, NeverLoopResult::Normal) => NeverLoopResult::Normal,
- (NeverLoopResult::Diverging, NeverLoopResult::Diverging) => NeverLoopResult::Diverging,
+ (
+ NeverLoopResult::Diverging {
+ break_spans: mut break_spans1,
+ },
+ NeverLoopResult::Diverging {
+ break_spans: mut break_spans2,
+ },
+ ) => {
+ break_spans1.append(&mut break_spans2);
+ NeverLoopResult::Diverging {
+ break_spans: break_spans1,
+ }
+ },
}
}
@@ -136,7 +155,7 @@ fn never_loop_block<'tcx>(
combine_seq_many(iter.map(|(e, els)| {
let e = never_loop_expr(cx, e, local_labels, main_loop_id);
// els is an else block in a let...else binding
- els.map_or(e, |els| {
+ els.map_or(e.clone(), |els| {
combine_seq(e, || match never_loop_block(cx, els, local_labels, main_loop_id) {
// Returning MayContinueMainLoop here means that
// we will not evaluate the rest of the body
@@ -144,7 +163,7 @@ fn never_loop_block<'tcx>(
// An else block always diverges, so the Normal case should not happen,
// but the analysis is approximate so it might return Normal anyway.
// Returning Normal here says that nothing more happens on the main path
- NeverLoopResult::Diverging | NeverLoopResult::Normal => NeverLoopResult::Normal,
+ NeverLoopResult::Diverging { .. } | NeverLoopResult::Normal => NeverLoopResult::Normal,
})
})
}))
@@ -159,6 +178,45 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t
}
}
+fn stmt_source_span(stmt: &Stmt<'_>) -> Span {
+ let call_span = stmt.span.source_callsite();
+ // if it is a macro call, the span will be missing the trailing semicolon
+ if stmt.span == call_span {
+ return call_span;
+ }
+
+ // An expression without a trailing semi-colon (must have unit type).
+ if let StmtKind::Expr(..) = stmt.kind {
+ return call_span;
+ }
+
+ call_span.with_hi(call_span.hi() + BytePos(1))
+}
+
+/// Returns a Vec of all the individual spans after the highlighted expression in a block
+fn all_spans_after_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> Vec<Span> {
+ if let Node::Stmt(stmt) = cx.tcx.parent_hir_node(expr.hir_id) {
+ if let Node::Block(block) = cx.tcx.parent_hir_node(stmt.hir_id) {
+ return block
+ .stmts
+ .iter()
+ .skip_while(|inner| inner.hir_id != stmt.hir_id)
+ .map(stmt_source_span)
+ .chain(if let Some(e) = block.expr { vec![e.span] } else { vec![] })
+ .collect();
+ }
+
+ return vec![stmt.span];
+ }
+
+ vec![]
+}
+
+fn is_label_for_block(cx: &LateContext<'_>, dest: &Destination) -> bool {
+ dest.target_id
+ .is_ok_and(|hir_id| matches!(cx.tcx.hir_node(hir_id), Node::Block(_)))
+}
+
#[allow(clippy::too_many_lines)]
fn never_loop_expr<'tcx>(
cx: &LateContext<'tcx>,
@@ -197,7 +255,7 @@ fn never_loop_expr<'tcx>(
ExprKind::Loop(b, _, _, _) => {
// We don't attempt to track reachability after a loop,
// just assume there may have been a break somewhere
- absorb_break(never_loop_block(cx, b, local_labels, main_loop_id))
+ absorb_break(&never_loop_block(cx, b, local_labels, main_loop_id))
},
ExprKind::If(e, e2, e3) => {
let e1 = never_loop_expr(cx, e, local_labels, main_loop_id);
@@ -212,9 +270,10 @@ fn never_loop_expr<'tcx>(
ExprKind::Match(e, arms, _) => {
let e = never_loop_expr(cx, e, local_labels, main_loop_id);
combine_seq(e, || {
- arms.iter().fold(NeverLoopResult::Diverging, |a, b| {
- combine_branches(a, never_loop_expr(cx, b.body, local_labels, main_loop_id))
- })
+ arms.iter()
+ .fold(NeverLoopResult::Diverging { break_spans: vec![] }, |a, b| {
+ combine_branches(a, never_loop_expr(cx, b.body, local_labels, main_loop_id))
+ })
})
},
ExprKind::Block(b, _) => {
@@ -224,7 +283,7 @@ fn never_loop_expr<'tcx>(
let ret = never_loop_block(cx, b, local_labels, main_loop_id);
let jumped_to = b.targeted_by_break && local_labels.pop().unwrap().1;
match ret {
- NeverLoopResult::Diverging if jumped_to => NeverLoopResult::Normal,
+ NeverLoopResult::Diverging { .. } if jumped_to => NeverLoopResult::Normal,
_ => ret,
}
},
@@ -235,25 +294,39 @@ fn never_loop_expr<'tcx>(
if id == main_loop_id {
NeverLoopResult::MayContinueMainLoop
} else {
- NeverLoopResult::Diverging
+ NeverLoopResult::Diverging {
+ break_spans: all_spans_after_expr(cx, expr),
+ }
}
},
- ExprKind::Break(_, e) | ExprKind::Ret(e) => {
+ ExprKind::Ret(e) => {
let first = e.as_ref().map_or(NeverLoopResult::Normal, |e| {
never_loop_expr(cx, e, local_labels, main_loop_id)
});
combine_seq(first, || {
// checks if break targets a block instead of a loop
- if let ExprKind::Break(Destination { target_id: Ok(t), .. }, _) = expr.kind
- && let Some((_, reachable)) = local_labels.iter_mut().find(|(label, _)| *label == t)
- {
- *reachable = true;
+ mark_block_as_reachable(expr, local_labels);
+ NeverLoopResult::Diverging { break_spans: vec![] }
+ })
+ },
+ ExprKind::Break(dest, e) => {
+ let first = e.as_ref().map_or(NeverLoopResult::Normal, |e| {
+ never_loop_expr(cx, e, local_labels, main_loop_id)
+ });
+ combine_seq(first, || {
+ // checks if break targets a block instead of a loop
+ mark_block_as_reachable(expr, local_labels);
+ NeverLoopResult::Diverging {
+ break_spans: if is_label_for_block(cx, &dest) {
+ vec![]
+ } else {
+ all_spans_after_expr(cx, expr)
+ },
}
- NeverLoopResult::Diverging
})
},
ExprKind::Become(e) => combine_seq(never_loop_expr(cx, e, local_labels, main_loop_id), || {
- NeverLoopResult::Diverging
+ NeverLoopResult::Diverging { break_spans: vec![] }
}),
ExprKind::InlineAsm(asm) => combine_seq_many(asm.operands.iter().map(|(o, _)| match o {
InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
@@ -283,12 +356,12 @@ fn never_loop_expr<'tcx>(
};
let result = combine_seq(result, || {
if cx.typeck_results().expr_ty(expr).is_never() {
- NeverLoopResult::Diverging
+ NeverLoopResult::Diverging { break_spans: vec![] }
} else {
NeverLoopResult::Normal
}
});
- if let NeverLoopResult::Diverging = result
+ if let NeverLoopResult::Diverging { .. } = result
&& let Some(macro_call) = root_macro_call_first_node(cx, expr)
&& let Some(sym::todo_macro) = cx.tcx.get_diagnostic_name(macro_call.def_id)
{
@@ -316,3 +389,11 @@ fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>)
format!("if let Some({pat_snippet}) = {iter_snippet}.next()")
}
+
+fn mark_block_as_reachable(expr: &Expr<'_>, local_labels: &mut [(HirId, bool)]) {
+ if let ExprKind::Break(Destination { target_id: Ok(t), .. }, _) = expr.kind
+ && let Some((_, reachable)) = local_labels.iter_mut().find(|(label, _)| *label == t)
+ {
+ *reachable = true;
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index d1a54df..3aa449f 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -1,15 +1,15 @@
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::source::snippet;
use hir::def::{DefKind, Res};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::{self as hir, AmbigArg};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::impl_lint_pass;
+use rustc_span::Span;
use rustc_span::edition::Edition;
-use rustc_span::{Span};
use std::collections::BTreeMap;
-use rustc_attr_data_structures::{AttributeKind, find_attr};
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
index bac4b3d..288f27d 100644
--- a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
@@ -5,7 +5,7 @@
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 clippy_utils::{eq_expr_value, peel_blocks, peel_middle_ty_refs, span_contains_comment};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -62,7 +62,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
&& 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)
+ && let Some((ty, b_n_refs)) = 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)
{
@@ -86,8 +86,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
}
};
let sugg = format!(
- "{}.abs_diff({})",
+ "{}.abs_diff({}{})",
Sugg::hir(cx, a, "..").maybe_paren(),
+ "*".repeat(b_n_refs),
Sugg::hir(cx, b, "..")
);
diag.span_suggestion(expr.span, "replace with `abs_diff`", sugg, applicability);
@@ -100,13 +101,15 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
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>> {
+ fn are_ty_eligible<'tcx>(&self, cx: &LateContext<'tcx>, a: &Expr<'_>, b: &Expr<'_>) -> Option<(Ty<'tcx>, usize)> {
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)
+ let (b_ty, b_n_refs) = peel_middle_ty_refs(cx.typeck_results().expr_ty(b));
+
+ (a_ty == b_ty && (is_int(a_ty) || is_duration(a_ty))).then_some((a_ty, b_n_refs))
}
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index 8378e15..ea6b01a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -60,7 +60,8 @@ 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_paren();
+ let cond_sugg =
+ sugg::Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "..", &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/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 08c0caa..7e530e9 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -152,21 +152,26 @@ fn report_single_pattern(
}) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1,
_ => pat_ref_count,
};
- // References are only implicitly added to the pattern, so no overflow here.
- // e.g. will work: match &Some(_) { Some(_) => () }
- // will not: match Some(_) { &Some(_) => () }
- let ref_count_diff = ty_ref_count - pat_ref_count;
- // Try to remove address of expressions first.
- let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
- let ref_count_diff = ref_count_diff - removed;
+ // References are implicitly removed when `deref_patterns` are used.
+ // They are implicitly added when match ergonomics are used.
+ let (ex, ref_or_deref_adjust) = if ty_ref_count > pat_ref_count {
+ let ref_count_diff = ty_ref_count - pat_ref_count;
+
+ // Try to remove address of expressions first.
+ let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
+
+ (ex, String::from(if ref_count_diff == removed { "" } else { "&" }))
+ } else {
+ (ex, "*".repeat(pat_ref_count - ty_ref_count))
+ };
let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
let sugg = format!(
"if {} == {}{} {}{els_str}",
snippet_with_context(cx, ex.span, ctxt, "..", &mut app).0,
// PartialEq for different reference counts may not exist.
- "&".repeat(ref_count_diff),
+ ref_or_deref_adjust,
snippet_with_applicability(cx, arm.pat.span, "..", &mut app),
expr_block(cx, arm.body, ctxt, "..", Some(expr.span), &mut app),
);
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
index a9f6a41..b8cc5dd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(
bytes_recv: &'tcx hir::Expr<'_>,
) {
if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(bytes_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(bytes_id)
&& cx.tcx.type_of(impl_id).instantiate_identity().is_str()
&& let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs()
&& (ty.is_str() || is_type_lang_item(cx, ty, hir::LangItem::String))
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 292fa08..6f9702f 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
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
}
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
&& cx.tcx.type_of(impl_id).instantiate_identity().is_str()
&& let ExprKind::Lit(Spanned {
node: LitKind::Str(ext_literal, ..),
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 2ecf3eb..0a456d1 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
@@ -28,7 +28,7 @@ pub(super) fn check(
if cx
.typeck_results()
.type_dependent_def_id(expr.hir_id)
- .and_then(|id| cx.tcx.trait_of_item(id))
+ .and_then(|id| cx.tcx.trait_of_assoc(id))
.zip(cx.tcx.lang_items().clone_trait())
.is_none_or(|(x, y)| x != y)
{
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 82e5a6d..6e5da5bd 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
@@ -2,13 +2,15 @@
use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span, root_macro_call_first_node};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{contains_return, is_inside_always_const_context, peel_blocks};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_middle::ty;
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
use std::borrow::Cow;
+use std::ops::ControlFlow;
use super::EXPECT_FUN_CALL;
@@ -23,10 +25,10 @@ pub(super) fn check<'tcx>(
receiver: &'tcx hir::Expr<'tcx>,
args: &'tcx [hir::Expr<'tcx>],
) {
- // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
+ // Strip `{}`, `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
// `&str`
fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
- let mut arg_root = arg;
+ let mut arg_root = peel_blocks(arg);
loop {
arg_root = match &arg_root.kind {
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
@@ -47,124 +49,68 @@ fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Ex
arg_root
}
- // Only `&'static str` or `String` can be used directly in the `panic!`. Other types should be
- // converted to string.
- fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
- let arg_ty = cx.typeck_results().expr_ty(arg);
- if is_type_lang_item(cx, arg_ty, hir::LangItem::String) {
- return false;
+ fn contains_call<'a>(cx: &LateContext<'a>, arg: &'a hir::Expr<'a>) -> bool {
+ for_each_expr(cx, arg, |expr| {
+ if matches!(expr.kind, hir::ExprKind::MethodCall { .. } | hir::ExprKind::Call { .. })
+ && !is_inside_always_const_context(cx.tcx, expr.hir_id)
+ {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(())
+ }
+ })
+ .is_some()
+ }
+
+ if name == sym::expect
+ && let [arg] = args
+ && let arg_root = get_arg_root(cx, arg)
+ && contains_call(cx, arg_root)
+ && !contains_return(arg_root)
+ {
+ let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver);
+ let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) {
+ "||"
+ } else if is_type_diagnostic_item(cx, receiver_type, sym::Result) {
+ "|_|"
+ } else {
+ return;
+ };
+
+ let span_replace_word = method_span.with_hi(expr.span.hi());
+
+ let mut applicability = Applicability::MachineApplicable;
+
+ // Special handling for `format!` as arg_root
+ if let Some(macro_call) = root_macro_call_first_node(cx, arg_root) {
+ if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id)
+ && let Some(format_args) = format_args_storage.get(cx, arg_root, macro_call.expn)
+ {
+ let span = format_args_inputs_span(format_args);
+ let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
+ span_lint_and_sugg(
+ cx,
+ EXPECT_FUN_CALL,
+ span_replace_word,
+ format!("function call inside of `{name}`"),
+ "try",
+ format!("unwrap_or_else({closure_args} panic!({sugg}))"),
+ applicability,
+ );
+ }
+ return;
}
- if let ty::Ref(_, ty, ..) = arg_ty.kind()
- && ty.is_str()
- && can_be_static_str(cx, arg)
- {
- return false;
- }
- true
+
+ let arg_root_snippet: Cow<'_, _> = snippet_with_applicability(cx, arg_root.span, "..", &mut applicability);
+
+ span_lint_and_sugg(
+ cx,
+ EXPECT_FUN_CALL,
+ span_replace_word,
+ format!("function call inside of `{name}`"),
+ "try",
+ format!("unwrap_or_else({closure_args} panic!(\"{{}}\", {arg_root_snippet}))"),
+ applicability,
+ );
}
-
- // Check if an expression could have type `&'static str`, knowing that it
- // has type `&str` for some lifetime.
- fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
- match arg.kind {
- hir::ExprKind::Lit(_) => true,
- hir::ExprKind::Call(fun, _) => {
- if let hir::ExprKind::Path(ref p) = fun.kind {
- match cx.qpath_res(p, fun.hir_id) {
- hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
- cx.tcx.fn_sig(def_id).instantiate_identity().output().skip_binder().kind(),
- ty::Ref(re, ..) if re.is_static(),
- ),
- _ => false,
- }
- } else {
- false
- }
- },
- hir::ExprKind::MethodCall(..) => {
- cx.typeck_results()
- .type_dependent_def_id(arg.hir_id)
- .is_some_and(|method_id| {
- matches!(
- cx.tcx.fn_sig(method_id).instantiate_identity().output().skip_binder().kind(),
- ty::Ref(re, ..) if re.is_static()
- )
- })
- },
- hir::ExprKind::Path(ref p) => matches!(
- cx.qpath_res(p, arg.hir_id),
- hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static { .. }, _)
- ),
- _ => false,
- }
- }
-
- fn is_call(node: &hir::ExprKind<'_>) -> bool {
- match node {
- hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => {
- is_call(&expr.kind)
- },
- hir::ExprKind::Call(..)
- | hir::ExprKind::MethodCall(..)
- // These variants are debatable or require further examination
- | hir::ExprKind::If(..)
- | hir::ExprKind::Match(..)
- | hir::ExprKind::Block{ .. } => true,
- _ => false,
- }
- }
-
- if args.len() != 1 || name != sym::expect || !is_call(&args[0].kind) {
- return;
- }
-
- let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver);
- let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) {
- "||"
- } else if is_type_diagnostic_item(cx, receiver_type, sym::Result) {
- "|_|"
- } else {
- return;
- };
-
- let arg_root = get_arg_root(cx, &args[0]);
-
- let span_replace_word = method_span.with_hi(expr.span.hi());
-
- let mut applicability = Applicability::MachineApplicable;
-
- // Special handling for `format!` as arg_root
- if let Some(macro_call) = root_macro_call_first_node(cx, arg_root) {
- if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id)
- && let Some(format_args) = format_args_storage.get(cx, arg_root, macro_call.expn)
- {
- let span = format_args_inputs_span(format_args);
- let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
- span_lint_and_sugg(
- cx,
- EXPECT_FUN_CALL,
- span_replace_word,
- format!("function call inside of `{name}`"),
- "try",
- format!("unwrap_or_else({closure_args} panic!({sugg}))"),
- applicability,
- );
- }
- return;
- }
-
- let mut arg_root_snippet: Cow<'_, _> = snippet_with_applicability(cx, arg_root.span, "..", &mut applicability);
- if requires_to_string(cx, arg_root) {
- arg_root_snippet.to_mut().push_str(".to_string()");
- }
-
- span_lint_and_sugg(
- cx,
- EXPECT_FUN_CALL,
- span_replace_word,
- format!("function call inside of `{name}`"),
- "try",
- format!("unwrap_or_else({closure_args} {{ panic!(\"{{}}\", {arg_root_snippet}) }})"),
- applicability,
- );
}
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 9659938..94944bd 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,6 +1,6 @@
use super::FILTER_MAP_BOOL_THEN;
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::SpanRangeExt;
+use clippy_utils::source::{SpanRangeExt, snippet_with_context};
use clippy_utils::ty::is_copy;
use clippy_utils::{
CaptureKind, can_move_expr_to_closure, contains_return, is_from_proc_macro, is_trait_method, peel_blocks,
@@ -45,9 +45,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
.filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
.count()
&& let Some(param_snippet) = param.span.get_source_text(cx)
- && let Some(filter) = recv.span.get_source_text(cx)
- && let Some(map) = then_body.span.get_source_text(cx)
{
+ let mut applicability = Applicability::MachineApplicable;
+ let (filter, _) = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut applicability);
+ let (map, _) = snippet_with_context(cx, then_body.span, expr.span.ctxt(), "..", &mut applicability);
+
span_lint_and_then(
cx,
FILTER_MAP_BOOL_THEN,
@@ -62,7 +64,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
"filter(|&{param_snippet}| {derefs}{filter}).map(|{param_snippet}| {map})",
derefs = "*".repeat(needed_derefs)
),
- Applicability::MachineApplicable,
+ applicability,
);
} else {
diag.help("consider using `filter` then `map` instead");
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
index f4465e6..2e1d71c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
@@ -18,7 +18,7 @@ pub(super) fn check<'tcx>(
arg: &'tcx hir::Expr<'_>,
) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
&& let identity = cx.tcx.type_of(impl_id).instantiate_identity()
&& let hir::ExprKind::Lit(Spanned {
node: LitKind::Int(Pu128(0), _),
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 9724463..efa8cee 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -50,7 +50,7 @@ pub fn is_clone_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: h
sym::to_path_buf => is_diag_item_method(cx, method_def_id, sym::Path),
sym::to_vec => cx
.tcx
- .impl_of_method(method_def_id)
+ .impl_of_assoc(method_def_id)
.filter(|&impl_did| {
cx.tcx.type_of(impl_did).instantiate_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()
})
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 f5fe431..f851ebe 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
@@ -44,9 +44,9 @@ pub(super) fn check<'tcx>(
let typeck = cx.typeck_results();
if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
&& let Some(method_id) = typeck.type_dependent_def_id(expr.hir_id)
- && cx.tcx.trait_of_item(method_id) == Some(iter_id)
+ && cx.tcx.trait_of_assoc(method_id) == Some(iter_id)
&& let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id)
- && cx.tcx.trait_of_item(method_id) == Some(iter_id)
+ && cx.tcx.trait_of_assoc(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, sym::Item)
&& matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty))
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
index 21f2ce8..bc96815 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
@@ -100,7 +100,6 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
match x {
UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())),
UseKind::Borrowed(s) => {
- #[expect(clippy::range_plus_one)]
let range = s.map_range(cx, |_, src, range| {
let src = src.get(range.clone())?;
let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']);
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
index c286c5f..077957f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
@@ -18,7 +18,7 @@ pub(super) fn check<'tcx>(
map_expr: &'tcx Expr<'_>,
) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
&& is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Option)
&& let ExprKind::Call(err_path, [err_arg]) = or_expr.kind
&& is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr)
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 8167e4f..a811dd1 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
@@ -59,7 +59,7 @@ pub(super) fn check(
&& is_type_lang_item(cx, cx.typeck_results().expr_ty(collect_expr), LangItem::String)
&& let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id)
&& let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
- && cx.tcx.trait_of_item(take_id) == Some(iter_trait_id)
+ && cx.tcx.trait_of_assoc(take_id) == Some(iter_trait_id)
&& let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg)
&& let ctxt = collect_expr.span.ctxt()
&& ctxt == take_expr.span.ctxt()
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 333a33f..748be9b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -23,7 +23,7 @@ fn should_run_lint(cx: &LateContext<'_>, e: &hir::Expr<'_>, method_id: DefId) ->
return true;
}
// We check if it's an `Option` or a `Result`.
- if let Some(id) = cx.tcx.impl_of_method(method_id) {
+ if let Some(id) = cx.tcx.impl_of_assoc(method_id) {
let identity = cx.tcx.type_of(id).instantiate_identity();
if !is_type_diagnostic_item(cx, identity, sym::Option) && !is_type_diagnostic_item(cx, identity, sym::Result) {
return false;
@@ -69,7 +69,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_
hir::ExprKind::MethodCall(method, obj, [], _) => {
if ident_eq(name, obj) && method.ident.name == sym::clone
&& let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id)
- && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+ && let Some(trait_id) = cx.tcx.trait_of_assoc(fn_id)
&& cx.tcx.lang_items().clone_trait() == Some(trait_id)
// no autoderefs
&& !cx.typeck_results().expr_adjustments(obj).iter()
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
index 5d0d4da..41beda9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
@@ -8,7 +8,7 @@
pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
&& is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Result)
&& let ExprKind::Closure(&Closure {
capture_clause: CaptureBy::Ref,
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index f2dabdd..bcd5455 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -3859,6 +3859,7 @@
declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `option.map(f).unwrap_or_default()` and `result.map(f).unwrap_or_default()` where f is a function or closure that returns the `bool` type.
+ /// Also checks for equality comparisons like `option.map(f) == Some(true)` and `result.map(f) == Ok(true)`.
///
/// ### Why is this bad?
/// Readability. These can be written more concisely as `option.is_some_and(f)` and `result.is_ok_and(f)`.
@@ -3869,6 +3870,11 @@
/// # let result: Result<usize, ()> = Ok(1);
/// option.map(|a| a > 10).unwrap_or_default();
/// result.map(|a| a > 10).unwrap_or_default();
+ ///
+ /// option.map(|a| a > 10) == Some(true);
+ /// result.map(|a| a > 10) == Ok(true);
+ /// option.map(|a| a > 10) != Some(true);
+ /// result.map(|a| a > 10) != Ok(true);
/// ```
/// Use instead:
/// ```no_run
@@ -3876,11 +3882,16 @@
/// # let result: Result<usize, ()> = Ok(1);
/// option.is_some_and(|a| a > 10);
/// result.is_ok_and(|a| a > 10);
+ ///
+ /// option.is_some_and(|a| a > 10);
+ /// result.is_ok_and(|a| a > 10);
+ /// option.is_none_or(|a| a > 10);
+ /// !result.is_ok_and(|a| a > 10);
/// ```
#[clippy::version = "1.77.0"]
pub MANUAL_IS_VARIANT_AND,
pedantic,
- "using `.map(f).unwrap_or_default()`, which is more succinctly expressed as `is_some_and(f)` or `is_ok_and(f)`"
+ "using `.map(f).unwrap_or_default()` or `.map(f) == Some/Ok(true)`, which are more succinctly expressed as `is_some_and(f)` or `is_ok_and(f)`"
}
declare_clippy_lint! {
@@ -5275,10 +5286,6 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
}
map_identity::check(cx, expr, recv, m_arg, name, span);
manual_inspect::check(cx, expr, m_arg, name, span, self.msrv);
- crate::useless_conversion::check_function_application(cx, expr, recv, m_arg);
- },
- (sym::map_break | sym::map_continue, [m_arg]) => {
- crate::useless_conversion::check_function_application(cx, expr, recv, m_arg);
},
(sym::map_or, [def, map]) => {
option_map_or_none::check(cx, expr, recv, def, map);
@@ -5546,7 +5553,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// Handle method calls whose receiver and arguments may come from expansion
if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind {
match (path.ident.name, args) {
- (sym::expect, [_]) if !matches!(method_call(recv), Some((sym::ok | sym::err, _, [], _, _))) => {
+ (sym::expect, [_]) => {
unwrap_expect_used::check(
cx,
expr,
diff --git a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
index 320523a..4235af8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
@@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'
&& let (_, ref_depth, Mutability::Mut) = peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(recv))
&& ref_depth >= 1
&& let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
&& is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex)
{
span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index 9b5f138..37a8e25 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -18,7 +18,7 @@ fn is_open_options(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
&& is_open_options(cx, cx.tcx.type_of(impl_id).instantiate_identity())
{
let mut options = Vec::new();
@@ -111,7 +111,7 @@ fn get_open_options(
// This might be a user defined extension trait with a method like `truncate_write`
// which would be a false positive
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(argument.hir_id)
- && cx.tcx.trait_of_item(method_def_id).is_some()
+ && cx.tcx.trait_of_assoc(method_def_id).is_some()
{
return false;
}
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 6ce7dd3..04f0e3c 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
@@ -242,15 +242,23 @@ fn check_or_fn_call<'tcx>(
let inner_arg = peel_blocks(arg);
for_each_expr(cx, inner_arg, |ex| {
let is_top_most_expr = ex.hir_id == inner_arg.hir_id;
- if let hir::ExprKind::Call(fun, fun_args) = ex.kind {
- let fun_span = if fun_args.is_empty() && is_top_most_expr {
- Some(fun.span)
- } else {
- None
- };
- if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span) {
- return ControlFlow::Break(());
- }
+ match ex.kind {
+ hir::ExprKind::Call(fun, fun_args) => {
+ let fun_span = if fun_args.is_empty() && is_top_most_expr {
+ Some(fun.span)
+ } else {
+ None
+ };
+ if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span) {
+ return ControlFlow::Break(());
+ }
+ },
+ hir::ExprKind::MethodCall(..) => {
+ if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, None) {
+ return ControlFlow::Break(());
+ }
+ },
+ _ => {},
}
ControlFlow::Continue(())
});
diff --git a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
index 38d9c5f..32752ef 100644
--- a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
@@ -11,7 +11,7 @@
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
&& is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::PathBuf)
&& let ExprKind::Lit(lit) = arg.kind
&& let LitKind::Str(ref path_lit, _) = lit.node
diff --git a/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
index aef1443..17d1a6a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
@@ -9,7 +9,7 @@
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
&& cx.tcx.type_of(impl_id).instantiate_identity().is_slice()
&& let Some(slice_type) = is_slice_of_primitives(cx, recv)
{
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 6f78d6c..51dd4ac 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -286,7 +286,7 @@ fn parse_iter_usage<'tcx>(
let iter_id = cx.tcx.get_diagnostic_item(sym::Iterator)?;
match (name.ident.name, args) {
- (sym::next, []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span),
+ (sym::next, []) if cx.tcx.trait_of_assoc(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span),
(sym::next_tuple, []) => {
return if paths::ITERTOOLS_NEXT_TUPLE.matches(cx, did)
&& let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind()
@@ -303,7 +303,7 @@ fn parse_iter_usage<'tcx>(
None
};
},
- (sym::nth | sym::skip, [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
+ (sym::nth | sym::skip, [idx_expr]) if cx.tcx.trait_of_assoc(did) == Some(iter_id) => {
if let Some(Constant::Int(idx)) = ConstEvalCtxt::new(cx).eval(idx_expr) {
let span = if name.ident.as_str() == "nth" {
e.span
@@ -312,7 +312,7 @@ fn parse_iter_usage<'tcx>(
&& next_name.ident.name == sym::next
&& next_expr.span.ctxt() == ctxt
&& let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id)
- && cx.tcx.trait_of_item(next_id) == Some(iter_id)
+ && cx.tcx.trait_of_assoc(next_id) == Some(iter_id)
{
next_expr.span
} else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
index f8b6d43..9876681 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
@@ -10,7 +10,7 @@
pub(super) fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) {
if count <= 1
&& let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(call_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(call_id)
&& cx.tcx.impl_trait_ref(impl_id).is_none()
&& let self_ty = cx.tcx.type_of(impl_id).instantiate_identity()
&& (self_ty.is_slice() || self_ty.is_str())
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs
index ce81282..0ec2d8b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs
@@ -165,7 +165,7 @@ pub(super) fn check_method(cx: &LateContext<'_>, expr: &Expr<'_>) {
pub(super) fn check_function(cx: &LateContext<'_>, expr: &Expr<'_>, callee: &Expr<'_>) {
if let ExprKind::Path(ref qpath) = callee.kind
&& let Some(item_def_id) = cx.qpath_res(qpath, callee.hir_id).opt_def_id()
- && let Some(trait_def_id) = cx.tcx.trait_of_item(item_def_id)
+ && let Some(trait_def_id) = cx.tcx.trait_of_assoc(item_def_id)
{
let qpath_spans = match qpath {
QPath::Resolved(_, path) => {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
index dbff08b..1de9f6a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -114,7 +114,7 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident
fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) -> Option<LintTrigger> {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
&& cx.tcx.type_of(impl_id).instantiate_identity().is_slice()
&& let ExprKind::Closure(&Closure { body, .. }) = arg.kind
&& let closure_body = cx.tcx.hir_body(body)
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 769526d..54f4526 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
@@ -694,7 +694,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx
sym::to_string => cx.tcx.is_diagnostic_item(sym::to_string_method, method_def_id),
sym::to_vec => cx
.tcx
- .impl_of_method(method_def_id)
+ .impl_of_assoc(method_def_id)
.filter(|&impl_did| cx.tcx.type_of(impl_did).instantiate_identity().is_slice())
.is_some(),
_ => false,
@@ -734,7 +734,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx
fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
if let ExprKind::MethodCall(_, caller, &[arg], _) = expr.kind
&& let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
- && cx.tcx.trait_of_item(method_def_id).is_none()
+ && cx.tcx.trait_of_assoc(method_def_id).is_none()
&& let Some(borrow_id) = cx.tcx.get_diagnostic_item(sym::Borrow)
&& cx.tcx.predicates_of(method_def_id).predicates.iter().any(|(pred, _)| {
if let ClauseKind::Trait(trait_pred) = pred.kind().skip_binder()
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index d30c12e..38fad23 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -79,7 +79,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: Symbo
applicability,
);
}
- } else if let Some(impl_id) = cx.tcx.impl_of_method(def_id)
+ } else if let Some(impl_id) = cx.tcx.impl_of_assoc(def_id)
&& let Some(adt) = cx.tcx.type_of(impl_id).instantiate_identity().ty_adt_def()
&& matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Option | sym::Result))
{
@@ -131,7 +131,7 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
hir::ExprKind::MethodCall(method, obj, [], _) => {
if method.ident.name == sym::clone
&& let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id)
- && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+ && let Some(trait_id) = cx.tcx.trait_of_assoc(fn_id)
// We check it's the `Clone` trait.
&& cx.tcx.lang_items().clone_trait().is_some_and(|id| id == trait_id)
// no autoderefs
diff --git a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
index 5ea4ada..bfb481f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
@@ -18,7 +18,7 @@ pub(super) fn check<'tcx>(
name_span: Span,
) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
- && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
&& is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Vec)
&& let ExprKind::Lit(Spanned {
node: LitKind::Int(Pu128(0), _),
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 760ecf0..18e2b38 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
@@ -7,9 +7,7 @@
use rustc_ast::LitKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{
- Block, Expr, ExprKind, Impl, Item, ItemKind, LangItem, Node, QPath, TyKind, VariantData,
-};
+use rustc_hir::{Block, Expr, ExprKind, Impl, Item, ItemKind, LangItem, Node, QPath, TyKind, VariantData};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{Ty, TypeckResults};
use rustc_session::declare_lint_pass;
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index c4a3d10..5a50259 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint;
use rustc_attr_data_structures::{AttributeKind, find_attr};
-use rustc_hir as hir;
-use rustc_hir::Attribute;
+use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, Attribute};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::AssocItemContainer;
use rustc_session::declare_lint_pass;
@@ -97,11 +97,23 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
}
match it.kind {
hir::ItemKind::Fn { .. } => {
+ if fn_is_externally_exported(cx, it.owner_id.to_def_id()) {
+ return;
+ }
+
let desc = "a function";
let attrs = cx.tcx.hir_attrs(it.hir_id());
check_missing_inline_attrs(cx, attrs, it.span, desc);
},
- hir::ItemKind::Trait(ref _constness, ref _is_auto, ref _unsafe, _ident, _generics, _bounds, trait_items) => {
+ hir::ItemKind::Trait(
+ ref _constness,
+ ref _is_auto,
+ ref _unsafe,
+ _ident,
+ _generics,
+ _bounds,
+ trait_items,
+ ) => {
// note: we need to check if the trait is exported so we can't use
// `LateLintPass::check_trait_item` here.
for &tit in trait_items {
@@ -173,3 +185,10 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
check_missing_inline_attrs(cx, attrs, impl_item.span, desc);
}
}
+
+/// Checks if this function is externally exported, where #[inline] wouldn't have the desired effect
+/// and a rustc warning would be triggered, see #15301
+fn fn_is_externally_exported(cx: &LateContext<'_>, def_id: DefId) -> bool {
+ let attrs = cx.tcx.codegen_fn_attrs(def_id);
+ attrs.contains_extern_indicator()
+}
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 fa61d0f..399bf4e 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -66,7 +66,9 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
}) = item.kind
&& let Some(trait_id) = trait_ref.trait_def_id()
{
- let trait_item_ids: DefIdSet = cx.tcx.associated_items(item.owner_id)
+ let trait_item_ids: DefIdSet = cx
+ .tcx
+ .associated_items(item.owner_id)
.in_definition_order()
.filter_map(|assoc_item| assoc_item.trait_item_def_id)
.collect();
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 d9f4fb2..a489c0a 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
@@ -171,14 +171,11 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e),
ExprKind::Call(func, _) => {
let typ = self.cx.typeck_results().expr_ty(func);
- match typ.kind() {
- ty::FnDef(..) | ty::FnPtr(..) => {
- let sig = typ.fn_sig(self.cx.tcx);
- if self.cx.tcx.instantiate_bound_regions_with_erased(sig).output().kind() == &ty::Never {
- self.report_diverging_sub_expr(e);
- }
- },
- _ => {},
+ if typ.is_fn() {
+ let sig = typ.fn_sig(self.cx.tcx);
+ if self.cx.tcx.instantiate_bound_regions_with_erased(sig).output().kind() == &ty::Never {
+ self.report_diverging_sub_expr(e);
+ }
}
},
ExprKind::MethodCall(..) => {
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index 2f1ab3d..31f51b4 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -79,7 +79,7 @@ fn check_arguments<'tcx>(
name: &str,
fn_kind: &str,
) {
- if let ty::FnDef(..) | ty::FnPtr(..) = type_definition.kind() {
+ if type_definition.is_fn() {
let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
for (argument, parameter) in iter::zip(arguments, parameters) {
if let ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) = parameter.kind()
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 6a7c843..a67545e 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -6,7 +6,7 @@
use rustc_span::Span;
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::ty::has_iter_method;
use clippy_utils::{is_trait_method, sym};
@@ -101,18 +101,23 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability);
let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability);
- let body_value_sugg = snippet_with_applicability(cx, body.value.span, "..", &mut applicability);
+ let (body_value_sugg, is_macro_call) =
+ snippet_with_context(cx, body.value.span, for_each_recv.span.ctxt(), "..", &mut applicability);
let sugg = format!(
"for {} in {} {}",
body_param_sugg,
for_each_rev_sugg,
- match body.value.kind {
- ExprKind::Block(block, _) if is_let_desugar(block) => {
- format!("{{ {body_value_sugg} }}")
- },
- ExprKind::Block(_, _) => body_value_sugg.to_string(),
- _ => format!("{{ {body_value_sugg}; }}"),
+ if is_macro_call {
+ format!("{{ {body_value_sugg}; }}")
+ } else {
+ match body.value.kind {
+ ExprKind::Block(block, _) if is_let_desugar(block) => {
+ format!("{{ {body_value_sugg} }}")
+ },
+ ExprKind::Block(_, _) => body_value_sugg.to_string(),
+ _ => format!("{{ {body_value_sugg}; }}"),
+ }
}
);
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 c97ecce..7b05799 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
@@ -246,8 +246,10 @@ fn check_fn(
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")),
+ span.get_source_text(cx).map_or_else(
+ || "change the call to".to_owned(),
+ |src| format!("change `{src}` to"),
+ ),
suggestion,
Applicability::Unspecified,
);
@@ -275,8 +277,10 @@ fn check_fn(
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")),
+ span.get_source_text(cx).map_or_else(
+ || "change the call to".to_owned(),
+ |src| format!("change `{src}` to"),
+ ),
suggestion,
Applicability::Unspecified,
);
@@ -308,9 +312,7 @@ fn check_fn(
/// Functions marked with these attributes must have the exact signature.
pub(crate) fn requires_exact_signature(attrs: &[Attribute]) -> bool {
attrs.iter().any(|attr| {
- [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
- .iter()
- .any(|&allow| attr.has_name(allow))
+ attr.is_proc_macro_attr()
})
}
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 3b86f1d..b598a39 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -65,11 +65,16 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
..
}) = item.kind
{
- for assoc_item in cx.tcx.associated_items(item.owner_id.def_id)
+ for assoc_item in cx
+ .tcx
+ .associated_items(item.owner_id.def_id)
.filter_by_name_unhygienic(sym::new)
{
if let AssocKind::Fn { has_self: false, .. } = assoc_item.kind {
- let impl_item = cx.tcx.hir_node_by_def_id(assoc_item.def_id.expect_local()).expect_impl_item();
+ let impl_item = cx
+ .tcx
+ .hir_node_by_def_id(assoc_item.def_id.expect_local())
+ .expect_impl_item();
if impl_item.span.in_external_macro(cx.sess().source_map()) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index a78a342..466beb0 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -3,12 +3,11 @@
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary};
+use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary, sym};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::impl_lint_pass;
-use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
use {rustc_ast as ast, rustc_hir as hir};
@@ -89,6 +88,18 @@ fn has_allowed_unary(&self, ty: Ty<'_>) -> bool {
self.allowed_unary.contains(ty_string_elem)
}
+ fn is_non_zero_u(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
+ if let ty::Adt(adt, substs) = ty.kind()
+ && cx.tcx.is_diagnostic_item(sym::NonZero, adt.did())
+ && let int_type = substs.type_at(0)
+ && matches!(int_type.kind(), ty::Uint(_))
+ {
+ true
+ } else {
+ false
+ }
+ }
+
/// Verifies built-in types that have specific allowed operations
fn has_specific_allowed_type_and_operation<'tcx>(
cx: &LateContext<'tcx>,
@@ -97,33 +108,12 @@ fn has_specific_allowed_type_and_operation<'tcx>(
rhs_ty: Ty<'tcx>,
) -> bool {
let is_div_or_rem = matches!(op, hir::BinOpKind::Div | hir::BinOpKind::Rem);
- let is_non_zero_u = |cx: &LateContext<'tcx>, ty: Ty<'tcx>| {
- let tcx = cx.tcx;
-
- let ty::Adt(adt, substs) = ty.kind() else { return false };
-
- if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) {
- return false;
- }
-
- let int_type = substs.type_at(0);
- let unsigned_int_types = [
- tcx.types.u8,
- tcx.types.u16,
- tcx.types.u32,
- tcx.types.u64,
- tcx.types.u128,
- tcx.types.usize,
- ];
-
- unsigned_int_types.contains(&int_type)
- };
let is_sat_or_wrap = |ty: Ty<'_>| {
is_type_diagnostic_item(cx, ty, sym::Saturating) || is_type_diagnostic_item(cx, ty, sym::Wrapping)
};
// If the RHS is `NonZero<u*>`, then division or module by zero will never occur.
- if is_non_zero_u(cx, rhs_ty) && is_div_or_rem {
+ if Self::is_non_zero_u(cx, rhs_ty) && is_div_or_rem {
return true;
}
@@ -219,6 +209,18 @@ fn manage_bin_ops<'tcx>(
let (mut actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
actual_lhs = expr_or_init(cx, actual_lhs);
actual_rhs = expr_or_init(cx, actual_rhs);
+
+ // `NonZeroU*.get() - 1`, will never overflow
+ if let hir::BinOpKind::Sub = op
+ && let hir::ExprKind::MethodCall(method, receiver, [], _) = actual_lhs.kind
+ && method.ident.name == sym::get
+ && let receiver_ty = cx.typeck_results().expr_ty(receiver).peel_refs()
+ && Self::is_non_zero_u(cx, receiver_ty)
+ && let Some(1) = Self::literal_integer(cx, actual_rhs)
+ {
+ return;
+ }
+
let lhs_ty = cx.typeck_results().expr_ty(actual_lhs).peel_refs();
let rhs_ty = cx.typeck_results().expr_ty_adjusted(actual_rhs).peel_refs();
if self.has_allowed_binary(lhs_ty, rhs_ty) {
@@ -227,6 +229,7 @@ fn manage_bin_ops<'tcx>(
if Self::has_specific_allowed_type_and_operation(cx, lhs_ty, op, rhs_ty) {
return;
}
+
let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
if let hir::BinOpKind::Shl | hir::BinOpKind::Shr = op {
// At least for integers, shifts are already handled by the CTFE
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 9b2cfd9..22ec4fe 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -41,7 +41,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
ExprKind::MethodCall(_, arg, [], _)
if typeck
.type_dependent_def_id(expr.hir_id)
- .and_then(|id| cx.tcx.trait_of_item(id))
+ .and_then(|id| cx.tcx.trait_of_assoc(id))
.is_some_and(|id| matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ToString | sym::ToOwned))) =>
{
(arg, arg.span)
diff --git a/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs b/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs
index 821178a..55bb78c 100644
--- a/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs
@@ -2,11 +2,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::expr_type_is_certain;
use rustc_ast::BinOpKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, Ty};
use super::MANUAL_IS_MULTIPLE_OF;
@@ -22,9 +23,21 @@ pub(super) fn check<'tcx>(
&& let Some(operand) = uint_compare_to_zero(cx, op, lhs, rhs)
&& let ExprKind::Binary(operand_op, operand_left, operand_right) = operand.kind
&& operand_op.node == BinOpKind::Rem
+ && matches!(
+ cx.typeck_results().expr_ty_adjusted(operand_left).peel_refs().kind(),
+ ty::Uint(_)
+ )
+ && matches!(
+ cx.typeck_results().expr_ty_adjusted(operand_right).peel_refs().kind(),
+ ty::Uint(_)
+ )
+ && expr_type_is_certain(cx, operand_left)
{
let mut app = Applicability::MachineApplicable;
- let divisor = Sugg::hir_with_applicability(cx, operand_right, "_", &mut app);
+ let divisor = deref_sugg(
+ Sugg::hir_with_applicability(cx, operand_right, "_", &mut app),
+ cx.typeck_results().expr_ty_adjusted(operand_right),
+ );
span_lint_and_sugg(
cx,
MANUAL_IS_MULTIPLE_OF,
@@ -64,3 +77,11 @@ fn uint_compare_to_zero<'tcx>(
matches!(cx.typeck_results().expr_ty_adjusted(operand).kind(), ty::Uint(_)).then_some(operand)
}
+
+fn deref_sugg<'a>(sugg: Sugg<'a>, ty: Ty<'_>) -> Sugg<'a> {
+ if let ty::Ref(_, target_ty, _) = ty.kind() {
+ deref_sugg(sugg.deref(), *target_ty)
+ } else {
+ sugg
+ }
+}
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 21e1ab0..0a1f2625 100644
--- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
@@ -179,7 +179,7 @@ fn in_impl<'tcx>(
bin_op: DefId,
) -> Option<(&'tcx rustc_hir::Ty<'tcx>, &'tcx rustc_hir::Ty<'tcx>)> {
if let Some(block) = get_enclosing_block(cx, e.hir_id)
- && let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id())
+ && let Some(impl_def_id) = cx.tcx.impl_of_assoc(block.hir_id.owner.to_def_id())
&& let item = cx.tcx.hir_expect_item(impl_def_id.expect_local())
&& let ItemKind::Impl(item) = &item.kind
&& let Some(of_trait) = &item.of_trait
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 19d9acf..4197680 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -96,6 +96,12 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Match(_, arms, _) = expr.kind {
+ // if the match is generated by an external macro, the writer does not control
+ // how the scrutinee (`match &scrutiny { ... }`) is matched
+ if expr.span.in_external_macro(cx.sess().source_map()) {
+ return;
+ }
+
for arm in arms {
let pat = &arm.pat;
if apply_lint(cx, pat, DerefPossible::Possible) {
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 94cdcf0..b3058c5 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -584,7 +584,13 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
Some((Node::Stmt(_), _)) => (),
Some((Node::LetStmt(l), _)) => {
// Only trace simple bindings. e.g `let x = y;`
- if let PatKind::Binding(BindingMode::NONE, id, _, None) = l.pat.kind {
+ if let PatKind::Binding(BindingMode::NONE, id, ident, None) = l.pat.kind
+ // Let's not lint for the current parameter. The user may still intend to mutate
+ // (or, if not mutate, then perhaps call a method that's not otherwise available
+ // for) the referenced value behind the parameter through this local let binding
+ // with the underscore being only temporary.
+ && !ident.name.as_str().starts_with('_')
+ {
self.bindings.insert(id, args_idx);
} else {
set_skip_flag();
@@ -650,7 +656,14 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
.filter_map(|(i, arg)| {
let param = &body.params[arg.idx];
match param.pat.kind {
- PatKind::Binding(BindingMode::NONE, id, _, None) if !is_lint_allowed(cx, PTR_ARG, param.hir_id) => {
+ PatKind::Binding(BindingMode::NONE, id, ident, None)
+ if !is_lint_allowed(cx, PTR_ARG, param.hir_id)
+ // Let's not lint for the current parameter. The user may still intend to mutate
+ // (or, if not mutate, then perhaps call a method that's not otherwise available
+ // for) the referenced value behind the parameter with the underscore being only
+ // temporary.
+ && !ident.name.as_str().starts_with('_') =>
+ {
Some((id, i))
},
_ => {
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index d292ed8..03d00ba 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -4,15 +4,20 @@
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
-use clippy_utils::{get_parent_expr, higher, is_in_const_context, is_integer_const, path_to_local};
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{
+ expr_use_ctxt, fn_def_id, get_parent_expr, higher, is_in_const_context, is_integer_const, is_path_lang_item,
+ path_to_local,
+};
+use rustc_ast::Mutability;
use rustc_ast::ast::RangeLimits;
use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind, HirId};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
+use rustc_hir::{BinOpKind, Expr, ExprKind, HirId, LangItem, Node};
+use rustc_lint::{LateContext, LateLintPass, Lint};
+use rustc_middle::ty::{self, ClauseKind, GenericArgKind, PredicatePolarity, Ty};
use rustc_session::impl_lint_pass;
-use rustc_span::Span;
use rustc_span::source_map::Spanned;
+use rustc_span::{Span, sym};
use std::cmp::Ordering;
declare_clippy_lint! {
@@ -24,6 +29,12 @@
/// The code is more readable with an inclusive range
/// like `x..=y`.
///
+ /// ### Limitations
+ /// The lint is conservative and will trigger only when switching
+ /// from an exclusive to an inclusive range is provably safe from
+ /// a typing point of view. This corresponds to situations where
+ /// the range is used as an iterator, or for indexing.
+ ///
/// ### Known problems
/// Will add unnecessary pair of parentheses when the
/// expression is not wrapped in a pair but starts with an opening parenthesis
@@ -34,11 +45,6 @@
/// exclusive ranges, because they essentially add an extra branch that
/// LLVM may fail to hoist out of the loop.
///
- /// This will cause a warning that cannot be fixed if the consumer of the
- /// range only accepts a specific range type, instead of the generic
- /// `RangeBounds` trait
- /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
- ///
/// ### Example
/// ```no_run
/// # let x = 0;
@@ -71,11 +77,11 @@
/// The code is more readable with an exclusive range
/// like `x..y`.
///
- /// ### Known problems
- /// This will cause a warning that cannot be fixed if
- /// the consumer of the range only accepts a specific range type, instead of
- /// the generic `RangeBounds` trait
- /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
+ /// ### Limitations
+ /// The lint is conservative and will trigger only when switching
+ /// from an inclusive to an exclusive range is provably safe from
+ /// a typing point of view. This corresponds to situations where
+ /// the range is used as an iterator, or for indexing.
///
/// ### Example
/// ```no_run
@@ -344,70 +350,188 @@ fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) ->
None
}
-// exclusive range plus one: `x..(y+1)`
-fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
- if expr.span.can_be_used_for_suggestions()
- && let Some(higher::Range {
- start,
- end: Some(end),
- limits: RangeLimits::HalfOpen,
- }) = higher::Range::hir(expr)
- && let Some(y) = y_plus_one(cx, end)
+/// Check whether `expr` could switch range types without breaking the typing requirements. This is
+/// generally the case when `expr` is used as an iterator for example, or as a slice or `&str`
+/// index.
+///
+/// FIXME: Note that the current implementation may still return false positives. A proper fix would
+/// check that the obligations are still satisfied after switching the range type.
+fn can_switch_ranges<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ original: RangeLimits,
+ inner_ty: Ty<'tcx>,
+) -> bool {
+ let use_ctxt = expr_use_ctxt(cx, expr);
+ let (Node::Expr(parent_expr), false) = (use_ctxt.node, use_ctxt.is_ty_unified) else {
+ return false;
+ };
+
+ // Check if `expr` is the argument of a compiler-generated `IntoIter::into_iter(expr)`
+ if let ExprKind::Call(func, [arg]) = parent_expr.kind
+ && arg.hir_id == use_ctxt.child_id
+ && is_path_lang_item(cx, func, LangItem::IntoIterIntoIter)
{
- let span = expr.span;
- span_lint_and_then(
- cx,
- RANGE_PLUS_ONE,
- span,
- "an inclusive range would be more readable",
- |diag| {
- 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);
- },
- Some(false) => {
- diag.span_suggestion(
- span,
- "use",
- format!("{start}..={end}"),
- Applicability::MachineApplicable, // snippet
- );
- },
- None => {},
- }
- },
- );
+ return true;
}
+
+ // Check if `expr` is used as the receiver of a method of the `Iterator`, `IntoIterator`,
+ // or `RangeBounds` traits.
+ if let ExprKind::MethodCall(_, receiver, _, _) = parent_expr.kind
+ && receiver.hir_id == use_ctxt.child_id
+ && let Some(method_did) = cx.typeck_results().type_dependent_def_id(parent_expr.hir_id)
+ && let Some(trait_did) = cx.tcx.trait_of_assoc(method_did)
+ && matches!(
+ cx.tcx.get_diagnostic_name(trait_did),
+ Some(sym::Iterator | sym::IntoIterator | sym::RangeBounds)
+ )
+ {
+ return true;
+ }
+
+ // Check if `expr` is an argument of a call which requires an `Iterator`, `IntoIterator`,
+ // or `RangeBounds` trait.
+ if let ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
+ && let Some(id) = fn_def_id(cx, parent_expr)
+ && let Some(arg_idx) = args.iter().position(|e| e.hir_id == use_ctxt.child_id)
+ {
+ let input_idx = if matches!(parent_expr.kind, ExprKind::MethodCall(..)) {
+ arg_idx + 1
+ } else {
+ arg_idx
+ };
+ let inputs = cx
+ .tcx
+ .liberate_late_bound_regions(id, cx.tcx.fn_sig(id).instantiate_identity())
+ .inputs();
+ let expr_ty = inputs[input_idx];
+ // Check that the `expr` type is present only once, otherwise modifying just one of them might be
+ // risky if they are referenced using the same generic type for example.
+ if inputs.iter().enumerate().all(|(n, ty)|
+ n == input_idx
+ || !ty.walk().any(|arg| matches!(arg.kind(),
+ GenericArgKind::Type(ty) if ty == expr_ty)))
+ // Look for a clause requiring `Iterator`, `IntoIterator`, or `RangeBounds`, and resolving to `expr_type`.
+ && cx
+ .tcx
+ .param_env(id)
+ .caller_bounds()
+ .into_iter()
+ .any(|p| {
+ if let ClauseKind::Trait(t) = p.kind().skip_binder()
+ && t.polarity == PredicatePolarity::Positive
+ && matches!(
+ cx.tcx.get_diagnostic_name(t.trait_ref.def_id),
+ Some(sym::Iterator | sym::IntoIterator | sym::RangeBounds)
+ )
+ {
+ t.self_ty() == expr_ty
+ } else {
+ false
+ }
+ })
+ {
+ return true;
+ }
+ }
+
+ // Check if `expr` is used for indexing, and if the switched range type could be used
+ // as well.
+ if let ExprKind::Index(outer_expr, index, _) = parent_expr.kind
+ && index.hir_id == expr.hir_id
+ // Build the switched range type (for example `RangeInclusive<usize>`).
+ && let Some(switched_range_def_id) = match original {
+ RangeLimits::HalfOpen => cx.tcx.lang_items().range_inclusive_struct(),
+ RangeLimits::Closed => cx.tcx.lang_items().range_struct(),
+ }
+ && let switched_range_ty = cx
+ .tcx
+ .type_of(switched_range_def_id)
+ .instantiate(cx.tcx, &[inner_ty.into()])
+ // Check that the switched range type can be used for indexing the original expression
+ // through the `Index` or `IndexMut` trait.
+ && let ty::Ref(_, outer_ty, mutability) = cx.typeck_results().expr_ty_adjusted(outer_expr).kind()
+ && let Some(index_def_id) = match mutability {
+ Mutability::Not => cx.tcx.lang_items().index_trait(),
+ Mutability::Mut => cx.tcx.lang_items().index_mut_trait(),
+ }
+ && implements_trait(cx, *outer_ty, index_def_id, &[switched_range_ty.into()])
+ // We could also check that the associated item of the `index_def_id` trait with the switched range type
+ // return the same type, but it is reasonable to expect so. We can't check that the result is identical
+ // in both `Index<Range<…>>` and `Index<RangeInclusive<…>>` anyway.
+ {
+ return true;
+ }
+
+ false
+}
+
+// exclusive range plus one: `x..(y+1)`
+fn check_exclusive_range_plus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ check_range_switch(
+ cx,
+ expr,
+ RangeLimits::HalfOpen,
+ y_plus_one,
+ RANGE_PLUS_ONE,
+ "an inclusive range would be more readable",
+ "..=",
+ );
}
// inclusive range minus one: `x..=(y-1)`
-fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
+fn check_inclusive_range_minus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ check_range_switch(
+ cx,
+ expr,
+ RangeLimits::Closed,
+ y_minus_one,
+ RANGE_MINUS_ONE,
+ "an exclusive range would be more readable",
+ "..",
+ );
+}
+
+/// Check for a `kind` of range in `expr`, check for `predicate` on the end,
+/// and emit the `lint` with `msg` and the `operator`.
+fn check_range_switch<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ kind: RangeLimits,
+ predicate: impl for<'hir> FnOnce(&LateContext<'_>, &Expr<'hir>) -> Option<&'hir Expr<'hir>>,
+ lint: &'static Lint,
+ msg: &'static str,
+ operator: &str,
+) {
if expr.span.can_be_used_for_suggestions()
&& let Some(higher::Range {
start,
end: Some(end),
- limits: RangeLimits::Closed,
+ limits,
}) = higher::Range::hir(expr)
- && let Some(y) = y_minus_one(cx, end)
+ && limits == kind
+ && let Some(y) = predicate(cx, end)
+ && can_switch_ranges(cx, expr, kind, cx.typeck_results().expr_ty(y))
{
- span_lint_and_then(
- cx,
- RANGE_MINUS_ONE,
- expr.span,
- "an exclusive range would be more readable",
- |diag| {
- 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",
- format!("{start}..{end}"),
- Applicability::MachineApplicable, // snippet
- );
- },
- );
+ let span = expr.span;
+ span_lint_and_then(cx, lint, span, msg, |diag| {
+ let mut app = Applicability::MachineApplicable;
+ let start = start.map_or(String::new(), |x| {
+ Sugg::hir_with_applicability(cx, x, "<x>", &mut app)
+ .maybe_paren()
+ .to_string()
+ });
+ let end = Sugg::hir_with_applicability(cx, y, "<y>", &mut app).maybe_paren();
+ match span.with_source_text(cx, |src| src.starts_with('(') && src.ends_with(')')) {
+ Some(true) => {
+ diag.span_suggestion(span, "use", format!("({start}{operator}{end})"), app);
+ },
+ Some(false) => {
+ diag.span_suggestion(span, "use", format!("{start}{operator}{end}"), app);
+ },
+ None => {},
+ }
+ });
}
}
@@ -494,7 +618,7 @@ fn is_empty_range(limits: RangeLimits, ordering: Ordering) -> bool {
}
}
-fn y_plus_one<'t>(cx: &LateContext<'_>, expr: &'t Expr<'_>) -> Option<&'t Expr<'t>> {
+fn y_plus_one<'tcx>(cx: &LateContext<'_>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
match expr.kind {
ExprKind::Binary(
Spanned {
@@ -515,7 +639,7 @@ fn y_plus_one<'t>(cx: &LateContext<'_>, expr: &'t Expr<'_>) -> Option<&'t Expr<'
}
}
-fn y_minus_one<'t>(cx: &LateContext<'_>, expr: &'t Expr<'_>) -> Option<&'t Expr<'t>> {
+fn y_minus_one<'tcx>(cx: &LateContext<'_>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
match expr.kind {
ExprKind::Binary(
Spanned {
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
index 25929b8..3497216 100644
--- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -113,7 +113,7 @@ fn check_fn(
) {
if matches!(kind, FnKind::Method(_, _))
// We are only interested in methods, not in functions or associated functions.
- && let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id())
+ && let Some(impl_def) = cx.tcx.impl_of_assoc(fn_def.to_def_id())
// We don't want this method to be te implementation of a trait because the
// `#[must_use]` should be put on the trait definition directly.
&& cx.tcx.trait_id_of_impl(impl_def).is_none()
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 85fde78..67eb71f 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, AssocItem};
+use rustc_middle::ty::{AssocItem, AssocKind};
use rustc_session::declare_lint_pass;
use rustc_span::Span;
use rustc_span::symbol::Symbol;
@@ -53,11 +53,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
for id in cx.tcx.hir_free_items() {
if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl { .. })
&& let item = cx.tcx.hir_item(id)
- && let ItemKind::Impl(Impl {
- of_trait,
- self_ty,
- ..
- }) = &item.kind
+ && let ItemKind::Impl(Impl { of_trait, self_ty, .. }) = &item.kind
&& let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
{
if !map.contains_key(res) {
@@ -127,7 +123,9 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
},
None => {
for assoc_item in cx.tcx.associated_items(id.owner_id).in_definition_order() {
- let AssocKind::Fn { name, .. } = assoc_item.kind else { continue };
+ let AssocKind::Fn { name, .. } = assoc_item.kind else {
+ continue;
+ };
let impl_span = cx.tcx.def_span(assoc_item.def_id);
let hir_id = cx.tcx.local_def_id_to_hir_id(assoc_item.def_id.expect_local());
if let Some(trait_spans) = existing_name.trait_methods.get(&name) {
@@ -140,10 +138,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
|diag| {
// TODO should we `span_note` on every trait?
// iterate on trait_spans?
- diag.span_note(
- trait_spans[0],
- format!("existing `{name}` defined here"),
- );
+ diag.span_note(trait_spans[0], format!("existing `{name}` defined here"));
},
);
}
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index d321c48..dcddff5 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -206,7 +206,7 @@ fn check_partial_eq(cx: &LateContext<'_>, method_span: Span, method_def_id: Loca
let arg_ty = cx.typeck_results().expr_ty_adjusted(arg);
if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
- && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+ && let Some(trait_id) = cx.tcx.trait_of_assoc(fn_id)
&& trait_id == trait_def_id
&& matches_ty(receiver_ty, arg_ty, self_arg, other_arg)
{
@@ -250,7 +250,7 @@ fn check_to_string(cx: &LateContext<'_>, method_span: Span, method_def_id: Local
let is_bad = match expr.kind {
ExprKind::MethodCall(segment, _receiver, &[_arg], _) if segment.ident.name == name.name => {
if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
- && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+ && let Some(trait_id) = cx.tcx.trait_of_assoc(fn_id)
&& trait_id == trait_def_id
{
true
@@ -318,7 +318,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow<()> {
&& let ExprKind::Path(qpath) = f.kind
&& is_default_method_on_current_ty(self.cx.tcx, qpath, self.implemented_ty_id)
&& let Some(method_def_id) = path_def_id(self.cx, f)
- && let Some(trait_def_id) = self.cx.tcx.trait_of_item(method_def_id)
+ && let Some(trait_def_id) = self.cx.tcx.trait_of_assoc(method_def_id)
&& self.cx.tcx.is_diagnostic_item(sym::Default, trait_def_id)
{
span_error(self.cx, self.method_span, expr);
@@ -426,7 +426,7 @@ fn check_from(cx: &LateContext<'_>, method_span: Span, method_def_id: LocalDefId
if let Some((fn_def_id, node_args)) = fn_def_id_with_node_args(cx, expr)
&& let [s1, s2] = **node_args
&& let (Some(s1), Some(s2)) = (s1.as_type(), s2.as_type())
- && let Some(trait_def_id) = cx.tcx.trait_of_item(fn_def_id)
+ && let Some(trait_def_id) = cx.tcx.trait_of_assoc(fn_def_id)
&& cx.tcx.is_diagnostic_item(sym::Into, trait_def_id)
&& get_impl_trait_def_id(cx, method_def_id) == cx.tcx.get_diagnostic_item(sym::From)
&& s1 == sig.inputs()[0]
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index e67afc7..5a3e4b7 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -1,8 +1,12 @@
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::is_def_id_trait_method;
+use clippy_utils::usage::is_todo_unimplemented_stub;
use rustc_hir::def::DefKind;
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn};
-use rustc_hir::{Body, Defaultness, Expr, ExprKind, FnDecl, HirId, Node, TraitItem, YieldSource};
+use rustc_hir::{
+ Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, Defaultness, Expr, ExprKind, FnDecl, HirId, Node,
+ TraitItem, YieldSource,
+};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_session::impl_lint_pass;
@@ -81,11 +85,8 @@ fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
let is_async_block = matches!(
ex.kind,
- ExprKind::Closure(rustc_hir::Closure {
- kind: rustc_hir::ClosureKind::Coroutine(rustc_hir::CoroutineKind::Desugared(
- rustc_hir::CoroutineDesugaring::Async,
- _
- )),
+ ExprKind::Closure(Closure {
+ kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)),
..
})
);
@@ -120,6 +121,7 @@ fn check_fn(
&& fn_kind.asyncness().is_async()
&& !is_def_id_trait_method(cx, def_id)
&& !is_default_trait_impl(cx, def_id)
+ && !async_fn_contains_todo_unimplemented_macro(cx, body)
{
let mut visitor = AsyncFnVisitor {
cx,
@@ -203,3 +205,18 @@ fn is_default_trait_impl(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
})
)
}
+
+fn async_fn_contains_todo_unimplemented_macro(cx: &LateContext<'_>, body: &Body<'_>) -> bool {
+ if let ExprKind::Closure(closure) = body.value.kind
+ && let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) = closure.kind
+ && let body = cx.tcx.hir_body(closure.body)
+ && let ExprKind::Block(block, _) = body.value.kind
+ && block.stmts.is_empty()
+ && let Some(expr) = block.expr
+ && let ExprKind::DropTemps(inner) = expr.kind
+ {
+ return is_todo_unimplemented_stub(cx, inner);
+ }
+
+ false
+}
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 12cc109..f3cd3f1 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
/// get desugared to match.
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'tcx>) {
let fn_def_id = block.hir_id.owner.to_def_id();
- if let Some(impl_id) = cx.tcx.impl_of_method(fn_def_id)
+ if let Some(impl_id) = cx.tcx.impl_of_assoc(fn_def_id)
&& let Some(trait_id) = cx.tcx.trait_id_of_impl(impl_id)
{
// We don't want to lint inside io::Read or io::Write implementations, as the author has more
@@ -300,7 +300,7 @@ fn check_io_mode(cx: &LateContext<'_>, call: &hir::Expr<'_>) -> Option<IoOp> {
};
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(call.hir_id)
- && let Some(trait_def_id) = cx.tcx.trait_of_item(method_def_id)
+ && let Some(trait_def_id) = cx.tcx.trait_of_assoc(method_def_id)
{
if let Some(diag_name) = cx.tcx.get_diagnostic_name(trait_def_id) {
match diag_name {
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index 12da891..dff3997 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -1,12 +1,10 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::macros::root_macro_call_first_node;
-use clippy_utils::sym;
+use clippy_utils::usage::is_todo_unimplemented_stub;
use clippy_utils::visitors::is_local_used;
-use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind};
+use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
-use std::ops::ControlFlow;
declare_clippy_lint! {
/// ### What it does
@@ -60,18 +58,6 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &ImplItem<'_>)
let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
let parent_item = cx.tcx.hir_expect_item(parent);
let assoc_item = cx.tcx.associated_item(impl_item.owner_id);
- let contains_todo = |cx, body: &'_ Body<'_>| -> bool {
- clippy_utils::visitors::for_each_expr_without_closures(body.value, |e| {
- if let Some(macro_call) = root_macro_call_first_node(cx, e)
- && cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id)
- {
- ControlFlow::Break(())
- } else {
- ControlFlow::Continue(())
- }
- })
- .is_some()
- };
if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind
&& assoc_item.is_method()
&& let ImplItemKind::Fn(.., body_id) = &impl_item.kind
@@ -79,7 +65,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &ImplItem<'_>)
&& let body = cx.tcx.hir_body(*body_id)
&& let [self_param, ..] = body.params
&& !is_local_used(cx, body, self_param.pat.hir_id)
- && !contains_todo(cx, body)
+ && !is_todo_unimplemented_stub(cx, body.value)
{
span_lint_and_help(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs
index b7a1d5b..12f2804 100644
--- a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs
@@ -6,7 +6,7 @@
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Item, ItemKind, UseKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext as _};
+use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Visibility;
use rustc_session::impl_lint_pass;
use rustc_span::symbol::kw;
@@ -59,7 +59,7 @@ pub fn new(conf: &'static Conf) -> Self {
impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
- if !item.span.in_external_macro(cx.sess().source_map())
+ if !item.span.from_expansion()
&& let ItemKind::Use(path, UseKind::Single(ident)) = item.kind
// Ignore imports that already use Underscore
&& ident.name != kw::Underscore
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 380ddea..e5b20c0 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -176,6 +176,33 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
}
},
+ ExprKind::MethodCall(path, recv, [arg], _) => {
+ if matches!(
+ path.ident.name,
+ sym::map | sym::map_err | sym::map_break | sym::map_continue
+ ) && has_eligible_receiver(cx, recv, e)
+ && (is_trait_item(cx, arg, sym::Into) || is_trait_item(cx, arg, sym::From))
+ && let ty::FnDef(_, args) = cx.typeck_results().expr_ty(arg).kind()
+ && let &[from_ty, to_ty] = args.into_type_list(cx.tcx).as_slice()
+ && same_type_and_consts(from_ty, to_ty)
+ {
+ span_lint_and_then(
+ cx,
+ USELESS_CONVERSION,
+ e.span.with_lo(recv.span.hi()),
+ format!("useless conversion to the same type: `{from_ty}`"),
+ |diag| {
+ diag.suggest_remove_item(
+ cx,
+ e.span.with_lo(recv.span.hi()),
+ "consider removing",
+ Applicability::MachineApplicable,
+ );
+ },
+ );
+ }
+ },
+
ExprKind::MethodCall(name, recv, [], _) => {
if is_trait_method(cx, e, sym::Into) && name.ident.name == sym::into {
let a = cx.typeck_results().expr_ty(e);
@@ -412,32 +439,6 @@ fn check_expr_post(&mut self, _: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
}
}
-/// Check if `arg` is a `Into::into` or `From::from` applied to `receiver` to give `expr`, through a
-/// higher-order mapping function.
-pub fn check_function_application(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
- if has_eligible_receiver(cx, recv, expr)
- && (is_trait_item(cx, arg, sym::Into) || is_trait_item(cx, arg, sym::From))
- && let ty::FnDef(_, args) = cx.typeck_results().expr_ty(arg).kind()
- && let &[from_ty, to_ty] = args.into_type_list(cx.tcx).as_slice()
- && same_type_and_consts(from_ty, to_ty)
- {
- span_lint_and_then(
- cx,
- USELESS_CONVERSION,
- expr.span.with_lo(recv.span.hi()),
- format!("useless conversion to the same type: `{from_ty}`"),
- |diag| {
- diag.suggest_remove_item(
- cx,
- expr.span.with_lo(recv.span.hi()),
- "consider removing",
- Applicability::MachineApplicable,
- );
- },
- );
- }
-}
-
fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>) -> bool {
if is_inherent_method_call(cx, expr) {
matches!(
diff --git a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs
index 88b099c..41fafc0 100644
--- a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs
@@ -2,6 +2,7 @@
use clippy_utils::paths;
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::{AttrStyle, DelimArgs};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_hir::def::Res;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::{
@@ -11,7 +12,6 @@
use rustc_lint_defs::declare_tool_lint;
use rustc_middle::ty::TyCtxt;
use rustc_session::declare_lint_pass;
-use rustc_span::sym;
declare_tool_lint! {
/// ### What it does
@@ -88,7 +88,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
}
// Is it derived?
- if !find_attr!(cx.tcx.get_all_attrs(item.owner_id), AttributeKind::AutomaticallyDerived(..)) {
+ if !find_attr!(
+ cx.tcx.get_all_attrs(item.owner_id),
+ AttributeKind::AutomaticallyDerived(..)
+ ) {
return;
}
diff --git a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
index 45a8660..fda65bc 100644
--- a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
@@ -1,7 +1,7 @@
use crate::internal_paths;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use clippy_utils::is_lint_allowed;
use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::{is_lint_allowed, sym};
use rustc_ast::ast::LitKind;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_hir as hir;
@@ -12,9 +12,9 @@
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Span;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::Symbol;
-use rustc_span::{Span, sym};
declare_tool_lint! {
/// ### What it does
@@ -160,9 +160,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
let body = cx.tcx.hir_body_owned_by(
impl_item_refs
.iter()
- .find(|iiref| iiref.ident.as_str() == "lint_vec")
+ .find(|&&iiref| cx.tcx.item_name(iiref.owner_id) == sym::lint_vec)
.expect("LintPass needs to implement lint_vec")
- .id
.owner_id
.def_id,
);
diff --git a/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs b/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
index 70b3c03..66aeb91 100644
--- a/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
@@ -1,6 +1,7 @@
use crate::internal_paths;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
+use clippy_utils::sym;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -40,7 +41,9 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
.filter(|t| matches!(t.kind(), GenericArgKind::Type(_)))
.any(|t| internal_paths::MSRV_STACK.matches_ty(cx, t.expect_ty()))
})
- && !items.iter().any(|item| item.ident.name.as_str() == "check_attributes")
+ && !items
+ .iter()
+ .any(|&item| cx.tcx.item_name(item.owner_id) == sym::check_attributes)
{
let span = cx.sess().source_map().span_through_char(item.span, '{');
span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index 645b644..19e71f6 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-07-10
+nightly-2025-07-25
```
<!-- end autogenerated nightly -->
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index 8453165..625e1ee 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -22,10 +22,13 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) {
{
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)
- })
+ &option_env!("RUST_RELEASE_NUM").map_or_else(
+ || "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/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 9d38672..eb3f442 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -51,7 +51,7 @@ fn bitor_assign(&mut self, rhs: Self) {
fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion {
use EagernessSuggestion::{Eager, Lazy, NoChange};
- let ty = match cx.tcx.impl_of_method(fn_id) {
+ let ty = match cx.tcx.impl_of_assoc(fn_id) {
Some(id) => cx.tcx.type_of(id).instantiate_identity(),
None => return Lazy,
};
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index ff1ee66..67e09e7 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -89,8 +89,8 @@
use itertools::Itertools;
use rustc_abi::Integer;
-use rustc_ast::join_path_syms;
use rustc_ast::ast::{self, LitKind, RangeLimits};
+use rustc_ast::join_path_syms;
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::packed::Pu128;
@@ -114,7 +114,7 @@
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::lint::LevelAndSource;
use rustc_middle::mir::{AggregateKind, Operand, RETURN_PLACE, Rvalue, StatementKind, TerminatorKind};
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, PointerCoercion};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{
self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt,
@@ -349,7 +349,7 @@ pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
/// Checks if the given method call expression calls an inherent method.
pub fn is_inherent_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
- cx.tcx.trait_of_item(method_id).is_none()
+ cx.tcx.trait_of_assoc(method_id).is_none()
} else {
false
}
@@ -357,7 +357,7 @@ 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(impl_did) = cx.tcx.impl_of_assoc(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());
@@ -367,7 +367,7 @@ pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbo
/// Checks if a method is in a diagnostic item trait
pub fn is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
- if let Some(trait_did) = cx.tcx.trait_of_item(def_id) {
+ if let Some(trait_did) = cx.tcx.trait_of_assoc(def_id) {
return cx.tcx.is_diagnostic_item(diag_item, trait_did);
}
false
@@ -620,7 +620,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
if let QPath::TypeRelative(_, method) = path
&& method.ident.name == sym::new
- && let Some(impl_did) = cx.tcx.impl_of_method(def_id)
+ && let Some(impl_did) = cx.tcx.impl_of_assoc(def_id)
&& let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def()
{
return std_types_symbols.iter().any(|&symbol| {
@@ -1897,6 +1897,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
/// * `|x| { return x }`
/// * `|x| { return x; }`
/// * `|(x, y)| (x, y)`
+/// * `|[x, y]| [x, y]`
///
/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
@@ -1907,9 +1908,9 @@ fn check_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
.get(pat.hir_id)
.is_some_and(|mode| matches!(mode.0, ByRef::Yes(_)))
{
- // If a tuple `(x, y)` is of type `&(i32, i32)`, then due to match ergonomics,
- // the inner patterns become references. Don't consider this the identity function
- // as that changes types.
+ // If the parameter is `(x, y)` of type `&(T, T)`, or `[x, y]` of type `&[T; 2]`, then
+ // due to match ergonomics, the inner patterns become references. Don't consider this
+ // the identity function as that changes types.
return false;
}
@@ -1922,6 +1923,13 @@ fn check_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
{
pats.iter().zip(tup).all(|(pat, expr)| check_pat(cx, pat, expr))
},
+ (PatKind::Slice(before, slice, after), ExprKind::Array(arr))
+ if slice.is_none() && before.len() + after.len() == arr.len() =>
+ {
+ (before.iter().chain(after))
+ .zip(arr)
+ .all(|(pat, expr)| check_pat(cx, pat, expr))
+ },
_ => false,
}
}
@@ -3269,15 +3277,13 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
if go_up_by > max_super {
// `super` chain would be too long, just use the absolute path instead
- join_path_syms(
- once(kw::Crate).chain(to.data.iter().filter_map(|el| {
- if let DefPathData::TypeNs(sym) = el.data {
- Some(sym)
- } else {
- None
- }
- }))
- )
+ join_path_syms(once(kw::Crate).chain(to.data.iter().filter_map(|el| {
+ if let DefPathData::TypeNs(sym) = el.data {
+ Some(sym)
+ } else {
+ None
+ }
+ })))
} else {
join_path_syms(repeat_n(kw::Super, go_up_by).chain(path))
}
@@ -3560,3 +3566,14 @@ pub fn potential_return_of_enclosing_body(cx: &LateContext<'_>, expr: &Expr<'_>)
// enclosing body.
false
}
+
+/// Checks if the expression has adjustments that require coercion, for example: dereferencing with
+/// overloaded deref, coercing pointers and `dyn` objects.
+pub fn expr_adjustment_requires_coercion(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ cx.typeck_results().expr_adjustments(expr).iter().any(|adj| {
+ matches!(
+ adj.kind,
+ Adjust::Deref(Some(_)) | Adjust::Pointer(PointerCoercion::Unsize) | Adjust::NeverToAny
+ )
+ })
+}
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index c681806..ea8cfc5 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -308,10 +308,11 @@ fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, n
None
}
}),
- ItemKind::Impl(..) | ItemKind::Trait(..)
- => tcx.associated_items(local_id).filter_by_name_unhygienic(name)
- .find(|assoc_item| ns.matches(Some(assoc_item.namespace())))
- .map(|assoc_item| assoc_item.def_id),
+ ItemKind::Impl(..) | ItemKind::Trait(..) => tcx
+ .associated_items(local_id)
+ .filter_by_name_unhygienic(name)
+ .find(|assoc_item| ns.matches(Some(assoc_item.namespace())))
+ .map(|assoc_item| assoc_item.def_id),
_ => None,
}
}
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index b335645..11c17a7 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -420,7 +420,7 @@ pub fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bo
.lookup_const_stability(def_id)
.or_else(|| {
cx.tcx
- .trait_of_item(def_id)
+ .trait_of_assoc(def_id)
.and_then(|trait_def_id| cx.tcx.lookup_const_stability(trait_def_id))
})
.is_none_or(|const_stab| {
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 8a8218c..934be97 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -98,6 +98,7 @@ macro_rules! generate {
ceil_char_boundary,
chain,
chars,
+ check_attributes,
checked_abs,
checked_add,
checked_isqrt,
@@ -196,6 +197,7 @@ macro_rules! generate {
kw,
last,
lazy_static,
+ lint_vec,
ln,
lock,
lock_api,
@@ -261,6 +263,7 @@ macro_rules! generate {
read_to_end,
read_to_string,
read_unaligned,
+ redundant_imports,
redundant_pub_crate,
regex,
rem_euclid,
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index fe208c0..d70232e 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -492,10 +492,7 @@ fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutabi
/// Returns `true` if the given type is an `unsafe` function.
pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
- match ty.kind() {
- ty::FnDef(..) | ty::FnPtr(..) => ty.fn_sig(cx.tcx).safety().is_unsafe(),
- _ => false,
- }
+ ty.is_fn() && ty.fn_sig(cx.tcx).safety().is_unsafe()
}
/// Returns the base type for HIR references and pointers.
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index 84df36c..d9c7e6e 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -12,10 +12,11 @@
//! be considered a bug.
use crate::paths::{PathNS, lookup_path};
+use rustc_ast::{LitFloatType, LitIntType, LitKind};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_qpath, walk_ty};
-use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind};
+use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, GenericArgs, HirId, Node, Param, PathSegment, QPath, TyKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty};
use rustc_span::Span;
@@ -24,22 +25,24 @@
use certainty::{Certainty, Meet, join, meet};
pub fn expr_type_is_certain(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- expr_type_certainty(cx, expr).is_certain()
+ expr_type_certainty(cx, expr, false).is_certain()
}
-fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
+/// Determine the type certainty of `expr`. `in_arg` indicates that the expression happens within
+/// the evaluation of a function or method call argument.
+fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>, in_arg: bool) -> Certainty {
let certainty = match &expr.kind {
ExprKind::Unary(_, expr)
| ExprKind::Field(expr, _)
| ExprKind::Index(expr, _, _)
- | ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr),
+ | ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr, in_arg),
- ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr))),
+ ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr, in_arg))),
ExprKind::Call(callee, args) => {
- let lhs = expr_type_certainty(cx, callee);
+ let lhs = expr_type_certainty(cx, callee, false);
let rhs = if type_is_inferable_from_arguments(cx, expr) {
- meet(args.iter().map(|arg| expr_type_certainty(cx, arg)))
+ meet(args.iter().map(|arg| expr_type_certainty(cx, arg, true)))
} else {
Certainty::Uncertain
};
@@ -47,7 +50,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
},
ExprKind::MethodCall(method, receiver, args, _) => {
- let mut receiver_type_certainty = expr_type_certainty(cx, receiver);
+ let mut receiver_type_certainty = expr_type_certainty(cx, receiver, false);
// Even if `receiver_type_certainty` is `Certain(Some(..))`, the `Self` type in the method
// identified by `type_dependent_def_id(..)` can differ. This can happen as a result of a `deref`,
// for example. So update the `DefId` in `receiver_type_certainty` (if any).
@@ -59,7 +62,8 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
let lhs = path_segment_certainty(cx, receiver_type_certainty, method, false);
let rhs = if type_is_inferable_from_arguments(cx, expr) {
meet(
- std::iter::once(receiver_type_certainty).chain(args.iter().map(|arg| expr_type_certainty(cx, arg))),
+ std::iter::once(receiver_type_certainty)
+ .chain(args.iter().map(|arg| expr_type_certainty(cx, arg, true))),
)
} else {
Certainty::Uncertain
@@ -67,16 +71,39 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
lhs.join(rhs)
},
- ExprKind::Tup(exprs) => meet(exprs.iter().map(|expr| expr_type_certainty(cx, expr))),
+ ExprKind::Tup(exprs) => meet(exprs.iter().map(|expr| expr_type_certainty(cx, expr, in_arg))),
- ExprKind::Binary(_, lhs, rhs) => expr_type_certainty(cx, lhs).meet(expr_type_certainty(cx, rhs)),
+ ExprKind::Binary(_, lhs, rhs) => {
+ // If one of the side of the expression is uncertain, the certainty will come from the other side,
+ // with no information on the type.
+ match (
+ expr_type_certainty(cx, lhs, in_arg),
+ expr_type_certainty(cx, rhs, in_arg),
+ ) {
+ (Certainty::Uncertain, Certainty::Certain(_)) | (Certainty::Certain(_), Certainty::Uncertain) => {
+ Certainty::Certain(None)
+ },
+ (l, r) => l.meet(r),
+ }
+ },
- ExprKind::Lit(_) => Certainty::Certain(None),
+ ExprKind::Lit(lit) => {
+ if !in_arg
+ && matches!(
+ lit.node,
+ LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed)
+ )
+ {
+ Certainty::Uncertain
+ } else {
+ Certainty::Certain(None)
+ }
+ },
ExprKind::Cast(_, ty) => type_certainty(cx, ty),
ExprKind::If(_, if_expr, Some(else_expr)) => {
- expr_type_certainty(cx, if_expr).join(expr_type_certainty(cx, else_expr))
+ expr_type_certainty(cx, if_expr, in_arg).join(expr_type_certainty(cx, else_expr, in_arg))
},
ExprKind::Path(qpath) => qpath_certainty(cx, qpath, false),
@@ -188,6 +215,20 @@ fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bo
certainty
}
+/// Tries to tell whether `param` resolves to something certain, e.g., a non-wildcard type if
+/// present. The certainty `DefId` is cleared before returning.
+fn param_certainty(cx: &LateContext<'_>, param: &Param<'_>) -> Certainty {
+ let owner_did = cx.tcx.hir_enclosing_body_owner(param.hir_id);
+ let Some(fn_decl) = cx.tcx.hir_fn_decl_by_hir_id(cx.tcx.local_def_id_to_hir_id(owner_did)) else {
+ return Certainty::Uncertain;
+ };
+ let inputs = fn_decl.inputs;
+ let body_params = cx.tcx.hir_body_owned_by(owner_did).params;
+ std::iter::zip(body_params, inputs)
+ .find(|(p, _)| p.hir_id == param.hir_id)
+ .map_or(Certainty::Uncertain, |(_, ty)| type_certainty(cx, ty).clear_def_id())
+}
+
fn path_segment_certainty(
cx: &LateContext<'_>,
parent_certainty: Certainty,
@@ -240,15 +281,16 @@ fn path_segment_certainty(
// `get_parent` because `hir_id` refers to a `Pat`, and we're interested in the node containing the `Pat`.
Res::Local(hir_id) => match cx.tcx.parent_hir_node(hir_id) {
- // An argument's type is always certain.
- Node::Param(..) => Certainty::Certain(None),
+ // A parameter's type is not always certain, as it may come from an untyped closure definition,
+ // or from a wildcard in a typed closure definition.
+ Node::Param(param) => param_certainty(cx, param),
// A local's type is certain if its type annotation is certain or it has an initializer whose
// type is certain.
Node::LetStmt(local) => {
let lhs = local.ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty));
let rhs = local
.init
- .map_or(Certainty::Uncertain, |init| expr_type_certainty(cx, init));
+ .map_or(Certainty::Uncertain, |init| expr_type_certainty(cx, init, false));
let certainty = lhs.join(rhs);
if resolves_to_type {
certainty
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 1b049b6..76d43fe 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -1,3 +1,4 @@
+use crate::macros::root_macro_call_first_node;
use crate::visitors::{Descend, Visitable, for_each_expr, for_each_expr_without_closures};
use crate::{self as utils, get_enclosing_loop_or_multi_call_closure};
use core::ops::ControlFlow;
@@ -9,6 +10,7 @@
use rustc_middle::hir::nested_filter;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty;
+use rustc_span::sym;
/// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option<HirIdSet> {
@@ -140,6 +142,46 @@ fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
}
}
+/// Checks if the given expression is a macro call to `todo!()` or `unimplemented!()`.
+pub fn is_todo_unimplemented_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ root_macro_call_first_node(cx, expr).is_some_and(|macro_call| {
+ [sym::todo_macro, sym::unimplemented_macro]
+ .iter()
+ .any(|&sym| cx.tcx.is_diagnostic_item(sym, macro_call.def_id))
+ })
+}
+
+/// Checks if the given expression is a stub, i.e., a `todo!()` or `unimplemented!()` expression,
+/// or a block whose last expression is a `todo!()` or `unimplemented!()`.
+pub fn is_todo_unimplemented_stub(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ if let ExprKind::Block(block, _) = expr.kind {
+ if let Some(last_expr) = block.expr {
+ return is_todo_unimplemented_macro(cx, last_expr);
+ }
+
+ return block.stmts.last().is_some_and(|stmt| {
+ if let hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) = stmt.kind {
+ return is_todo_unimplemented_macro(cx, expr);
+ }
+ false
+ });
+ }
+
+ is_todo_unimplemented_macro(cx, expr)
+}
+
+/// Checks if the given expression contains macro call to `todo!()` or `unimplemented!()`.
+pub fn contains_todo_unimplement_macro(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
+ for_each_expr_without_closures(expr, |e| {
+ if is_todo_unimplemented_macro(cx, e) {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(())
+ }
+ })
+ .is_some()
+}
+
pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
for_each_expr_without_closures(expression, |e| {
match e.kind {
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index f46e079..0edb80e 100644
--- a/src/tools/clippy/rust-toolchain.toml
+++ b/src/tools/clippy/rust-toolchain.toml
@@ -1,6 +1,6 @@
[toolchain]
# begin autogenerated nightly
-channel = "nightly-2025-07-10"
+channel = "nightly-2025-07-25"
# 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 b45edf2..194ed84 100644
--- a/src/tools/clippy/rustc_tools_util/src/lib.rs
+++ b/src/tools/clippy/rustc_tools_util/src/lib.rs
@@ -157,7 +157,8 @@ pub fn get_commit_date() -> Option<String> {
#[must_use]
pub fn get_compiler_version() -> Option<String> {
- get_output("rustc", &["-V"])
+ let compiler = std::option_env!("RUSTC").unwrap_or("rustc");
+ get_output(compiler, &["-V"])
}
#[must_use]
@@ -172,6 +173,8 @@ pub fn get_channel(compiler_version: Option<String>) -> String {
return String::from("beta");
} else if rustc_output.contains("nightly") {
return String::from("nightly");
+ } else if rustc_output.contains("dev") {
+ return String::from("dev");
}
}
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 83f91cc..464efc4 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -162,6 +162,10 @@ fn base_config(&self, test_dir: &str, mandatory_annotations: bool) -> Config {
// however has some staging logic that is hurting us here, so to work around
// that we set both the "real" and "staging" rustc to TEST_RUSTC, including the
// associated library paths.
+ #[expect(
+ clippy::option_env_unwrap,
+ reason = "TEST_RUSTC will ensure that the requested env vars are set during compile time"
+ )]
if let Some(rustc) = option_env!("TEST_RUSTC") {
let libdir = option_env!("TEST_RUSTC_LIB").unwrap();
let sysroot = option_env!("TEST_SYSROOT").unwrap();
@@ -169,10 +173,7 @@ fn base_config(&self, test_dir: &str, mandatory_annotations: bool) -> Config {
p.envs.push(("RUSTC_REAL_LIBDIR".into(), Some(libdir.into())));
p.envs.push(("RUSTC_SNAPSHOT".into(), Some(rustc.into())));
p.envs.push(("RUSTC_SNAPSHOT_LIBDIR".into(), Some(libdir.into())));
- p.envs.push((
- "RUSTC_SYSROOT".into(),
- Some(sysroot.into()),
- ));
+ p.envs.push(("RUSTC_SYSROOT".into(), Some(sysroot.into())));
}
p
},
diff --git a/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.enabled.stderr b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.enabled.stderr
index 8a85d38..608264b 100644
--- a/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.enabled.stderr
+++ b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.enabled.stderr
@@ -18,6 +18,8 @@
|
LL | sleep(Duration::new(1, 0));
| ^^^^^
+ |
+ = note: you may want to conditionally increase the MSRV considered by Clippy using the `clippy::msrv` attribute
error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui-toml/enum_variant_size/enum_variant_size.stderr b/src/tools/clippy/tests/ui-toml/enum_variant_size/enum_variant_size.stderr
index 020b3cc..a5dfd70 100644
--- a/src/tools/clippy/tests/ui-toml/enum_variant_size/enum_variant_size.stderr
+++ b/src/tools/clippy/tests/ui-toml/enum_variant_size/enum_variant_size.stderr
@@ -12,7 +12,7 @@
|
= note: `-D clippy::large-enum-variant` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::large_enum_variant)]`
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - B([u8; 501]),
LL + B(Box<[u8; 501]>),
diff --git a/src/tools/clippy/tests/ui/approx_const.rs b/src/tools/clippy/tests/ui/approx_const.rs
index 6461666..fc49342 100644
--- a/src/tools/clippy/tests/ui/approx_const.rs
+++ b/src/tools/clippy/tests/ui/approx_const.rs
@@ -106,4 +106,19 @@ fn main() {
//~^ approx_constant
let no_tau = 6.3;
+
+ // issue #15194
+ #[allow(clippy::excessive_precision)]
+ let x: f64 = 3.1415926535897932384626433832;
+ //~^ approx_constant
+
+ #[allow(clippy::excessive_precision)]
+ let _: f64 = 003.14159265358979311599796346854418516159057617187500;
+ //~^ approx_constant
+
+ let almost_frac_1_sqrt_2 = 00.70711;
+ //~^ approx_constant
+
+ let almost_frac_1_sqrt_2 = 00.707_11;
+ //~^ approx_constant
}
diff --git a/src/tools/clippy/tests/ui/approx_const.stderr b/src/tools/clippy/tests/ui/approx_const.stderr
index f7bda04..32a3517 100644
--- a/src/tools/clippy/tests/ui/approx_const.stderr
+++ b/src/tools/clippy/tests/ui/approx_const.stderr
@@ -184,5 +184,37 @@
|
= help: consider using the constant directly
-error: aborting due to 23 previous errors
+error: approximate value of `f{32, 64}::consts::PI` found
+ --> tests/ui/approx_const.rs:112:18
+ |
+LL | let x: f64 = 3.1415926535897932384626433832;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using the constant directly
+
+error: approximate value of `f{32, 64}::consts::PI` found
+ --> tests/ui/approx_const.rs:116:18
+ |
+LL | let _: f64 = 003.14159265358979311599796346854418516159057617187500;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using the constant directly
+
+error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found
+ --> tests/ui/approx_const.rs:119:32
+ |
+LL | let almost_frac_1_sqrt_2 = 00.70711;
+ | ^^^^^^^^
+ |
+ = help: consider using the constant directly
+
+error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found
+ --> tests/ui/approx_const.rs:122:32
+ |
+LL | let almost_frac_1_sqrt_2 = 00.707_11;
+ | ^^^^^^^^^
+ |
+ = help: consider using the constant directly
+
+error: aborting due to 27 previous errors
diff --git a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr
index 5556b0d..ce72620 100644
--- a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr
+++ b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `Arc<RefCell<i32>>` is not `Send` and `Sync` as `RefCell<i32>` is not `Sync`
- = help: if the `Arc` will not used be across threads replace it with an `Rc`
+ = help: if the `Arc` will not be used across threads replace it with an `Rc`
= help: otherwise make `RefCell<i32>` `Send` and `Sync` or consider a wrapper type such as `Mutex`
= note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::arc_with_non_send_sync)]`
@@ -17,7 +17,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `Arc<MutexGuard<'_, i32>>` is not `Send` and `Sync` as `MutexGuard<'_, i32>` is not `Send`
- = help: if the `Arc` will not used be across threads replace it with an `Rc`
+ = help: if the `Arc` will not be used across threads replace it with an `Rc`
= help: otherwise make `MutexGuard<'_, i32>` `Send` and `Sync` or consider a wrapper type such as `Mutex`
error: usage of an `Arc` that is not `Send` and `Sync`
@@ -27,7 +27,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `Arc<*const i32>` is not `Send` and `Sync` as `*const i32` is neither `Send` nor `Sync`
- = help: if the `Arc` will not used be across threads replace it with an `Rc`
+ = help: if the `Arc` will not be used across threads replace it with an `Rc`
= help: otherwise make `*const i32` `Send` and `Sync` or consider a wrapper type such as `Mutex`
error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
index 21be2af..3245b2c 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
@@ -664,6 +664,20 @@ pub fn issue_12318() {
//~^ arithmetic_side_effects
}
+pub fn issue_15225() {
+ use core::num::{NonZero, NonZeroU8};
+
+ let one = const { NonZeroU8::new(1).unwrap() };
+ let _ = one.get() - 1;
+
+ let one: NonZero<u8> = const { NonZero::new(1).unwrap() };
+ let _ = one.get() - 1;
+
+ type AliasedType = u8;
+ let one: NonZero<AliasedType> = const { NonZero::new(1).unwrap() };
+ let _ = one.get() - 1;
+}
+
pub fn explicit_methods() {
use core::ops::Add;
let one: i32 = 1;
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
index e15fb61..4150493 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
@@ -758,13 +758,13 @@
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> tests/ui/arithmetic_side_effects.rs:670:5
+ --> tests/ui/arithmetic_side_effects.rs:684:5
|
LL | one.add(&one);
| ^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> tests/ui/arithmetic_side_effects.rs:672:5
+ --> tests/ui/arithmetic_side_effects.rs:686:5
|
LL | Box::new(one).add(one);
| ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed
index eee61f9..3754b9d 100644
--- a/src/tools/clippy/tests/ui/assign_ops.fixed
+++ b/src/tools/clippy/tests/ui/assign_ops.fixed
@@ -84,6 +84,7 @@
const ONE: Self;
}
+ #[rustfmt::skip] // rustfmt doesn't understand the order of pub const on traits (yet)
pub const trait NumberConstants {
fn constant(value: usize) -> Self;
}
diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs
index 13ffcee..0b878d4 100644
--- a/src/tools/clippy/tests/ui/assign_ops.rs
+++ b/src/tools/clippy/tests/ui/assign_ops.rs
@@ -84,6 +84,7 @@ pub trait Number: Copy + Add<Self, Output = Self> + AddAssign {
const ONE: Self;
}
+ #[rustfmt::skip] // rustfmt doesn't understand the order of pub const on traits (yet)
pub const trait NumberConstants {
fn constant(value: usize) -> Self;
}
diff --git a/src/tools/clippy/tests/ui/auxiliary/external_item.rs b/src/tools/clippy/tests/ui/auxiliary/external_item.rs
index ca4bc36..621e18f 100644
--- a/src/tools/clippy/tests/ui/auxiliary/external_item.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/external_item.rs
@@ -4,4 +4,4 @@ impl _ExternalStruct {
pub fn _foo(self) {}
}
-pub fn _exernal_foo() {}
+pub fn _external_foo() {}
diff --git a/src/tools/clippy/tests/ui/checked_conversions.fixed b/src/tools/clippy/tests/ui/checked_conversions.fixed
index 279a5b6..6175275 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.fixed
+++ b/src/tools/clippy/tests/ui/checked_conversions.fixed
@@ -95,7 +95,7 @@
#[clippy::msrv = "1.33"]
fn msrv_1_33() {
let value: i64 = 33;
- let _ = value <= (u32::MAX as i64) && value >= 0;
+ let _ = value <= (u32::max_value() as i64) && value >= 0;
}
#[clippy::msrv = "1.34"]
diff --git a/src/tools/clippy/tests/ui/checked_conversions.rs b/src/tools/clippy/tests/ui/checked_conversions.rs
index c339bc6..9ed0e8f 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.rs
+++ b/src/tools/clippy/tests/ui/checked_conversions.rs
@@ -95,13 +95,13 @@ pub const fn issue_8898(i: u32) -> bool {
#[clippy::msrv = "1.33"]
fn msrv_1_33() {
let value: i64 = 33;
- let _ = value <= (u32::MAX as i64) && value >= 0;
+ let _ = value <= (u32::max_value() as i64) && value >= 0;
}
#[clippy::msrv = "1.34"]
fn msrv_1_34() {
let value: i64 = 34;
- let _ = value <= (u32::MAX as i64) && value >= 0;
+ let _ = value <= (u32::max_value() as i64) && value >= 0;
//~^ checked_conversions
}
diff --git a/src/tools/clippy/tests/ui/checked_conversions.stderr b/src/tools/clippy/tests/ui/checked_conversions.stderr
index 3841b9d..624876d 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.stderr
+++ b/src/tools/clippy/tests/ui/checked_conversions.stderr
@@ -100,8 +100,8 @@
error: checked cast can be simplified
--> tests/ui/checked_conversions.rs:104:13
|
-LL | let _ = value <= (u32::MAX as i64) && value >= 0;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
+LL | let _ = value <= (u32::max_value() as i64) && value >= 0;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
error: aborting due to 17 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 a4bf009..26e3601 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -328,7 +328,7 @@
LL | if X.is_some() {
| ^^^^^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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: `#[deny(static_mut_refs)]` on by default
diff --git a/src/tools/clippy/tests/ui/expect.rs b/src/tools/clippy/tests/ui/expect.rs
index 8f7379f..1ab01ec 100644
--- a/src/tools/clippy/tests/ui/expect.rs
+++ b/src/tools/clippy/tests/ui/expect.rs
@@ -16,7 +16,26 @@ fn expect_result() {
//~^ expect_used
}
+#[allow(clippy::ok_expect)]
+#[allow(clippy::err_expect)]
+fn issue_15247() {
+ let x: Result<u8, u8> = Err(0);
+ x.ok().expect("Huh");
+ //~^ expect_used
+
+ { x.ok() }.expect("...");
+ //~^ expect_used
+
+ let y: Result<u8, u8> = Ok(0);
+ y.err().expect("Huh");
+ //~^ expect_used
+
+ { y.err() }.expect("...");
+ //~^ expect_used
+}
+
fn main() {
expect_option();
expect_result();
+ issue_15247();
}
diff --git a/src/tools/clippy/tests/ui/expect.stderr b/src/tools/clippy/tests/ui/expect.stderr
index 70cf307..353fb77 100644
--- a/src/tools/clippy/tests/ui/expect.stderr
+++ b/src/tools/clippy/tests/ui/expect.stderr
@@ -24,5 +24,37 @@
|
= note: if this value is an `Ok`, it will panic
-error: aborting due to 3 previous errors
+error: used `expect()` on an `Option` value
+ --> tests/ui/expect.rs:23:5
+ |
+LL | x.ok().expect("Huh");
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: if this value is `None`, it will panic
+
+error: used `expect()` on an `Option` value
+ --> tests/ui/expect.rs:26:5
+ |
+LL | { x.ok() }.expect("...");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: if this value is `None`, it will panic
+
+error: used `expect()` on an `Option` value
+ --> tests/ui/expect.rs:30:5
+ |
+LL | y.err().expect("Huh");
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: if this value is `None`, it will panic
+
+error: used `expect()` on an `Option` value
+ --> tests/ui/expect.rs:33:5
+ |
+LL | { y.err() }.expect("...");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: if this value is `None`, it will panic
+
+error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/expect_fun_call.fixed b/src/tools/clippy/tests/ui/expect_fun_call.fixed
index 73eaebf..b923521 100644
--- a/src/tools/clippy/tests/ui/expect_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/expect_fun_call.fixed
@@ -90,17 +90,30 @@
"foo"
}
- Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) });
+ const fn const_evaluable() -> &'static str {
+ "foo"
+ }
+
+ Some("foo").unwrap_or_else(|| panic!("{}", get_string()));
//~^ expect_fun_call
- Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) });
+ Some("foo").unwrap_or_else(|| panic!("{}", get_string()));
//~^ expect_fun_call
- Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) });
+ Some("foo").unwrap_or_else(|| panic!("{}", get_string()));
//~^ expect_fun_call
- Some("foo").unwrap_or_else(|| { panic!("{}", get_static_str()) });
+ Some("foo").unwrap_or_else(|| panic!("{}", get_static_str()));
//~^ expect_fun_call
- Some("foo").unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) });
+ Some("foo").unwrap_or_else(|| panic!("{}", get_non_static_str(&0)));
//~^ expect_fun_call
+
+ Some("foo").unwrap_or_else(|| panic!("{}", const_evaluable()));
+ //~^ expect_fun_call
+
+ const {
+ Some("foo").expect(const_evaluable());
+ }
+
+ Some("foo").expect(const { const_evaluable() });
}
//Issue #3839
@@ -122,4 +135,15 @@
let format_capture_and_value: Option<i32> = None;
format_capture_and_value.unwrap_or_else(|| panic!("{error_code}, {}", 1));
//~^ expect_fun_call
+
+ // Issue #15056
+ let a = false;
+ Some(5).expect(if a { "a" } else { "b" });
+
+ let return_in_expect: Option<i32> = None;
+ return_in_expect.expect(if true {
+ "Error"
+ } else {
+ return;
+ });
}
diff --git a/src/tools/clippy/tests/ui/expect_fun_call.rs b/src/tools/clippy/tests/ui/expect_fun_call.rs
index ecebc9e..bc58d24 100644
--- a/src/tools/clippy/tests/ui/expect_fun_call.rs
+++ b/src/tools/clippy/tests/ui/expect_fun_call.rs
@@ -90,6 +90,10 @@ fn get_non_static_str(_: &u32) -> &str {
"foo"
}
+ const fn const_evaluable() -> &'static str {
+ "foo"
+ }
+
Some("foo").expect(&get_string());
//~^ expect_fun_call
Some("foo").expect(get_string().as_ref());
@@ -101,6 +105,15 @@ fn get_non_static_str(_: &u32) -> &str {
//~^ expect_fun_call
Some("foo").expect(get_non_static_str(&0));
//~^ expect_fun_call
+
+ Some("foo").expect(const_evaluable());
+ //~^ expect_fun_call
+
+ const {
+ Some("foo").expect(const_evaluable());
+ }
+
+ Some("foo").expect(const { const_evaluable() });
}
//Issue #3839
@@ -122,4 +135,15 @@ fn get_non_static_str(_: &u32) -> &str {
let format_capture_and_value: Option<i32> = None;
format_capture_and_value.expect(&format!("{error_code}, {}", 1));
//~^ expect_fun_call
+
+ // Issue #15056
+ let a = false;
+ Some(5).expect(if a { "a" } else { "b" });
+
+ let return_in_expect: Option<i32> = None;
+ return_in_expect.expect(if true {
+ "Error"
+ } else {
+ return;
+ });
}
diff --git a/src/tools/clippy/tests/ui/expect_fun_call.stderr b/src/tools/clippy/tests/ui/expect_fun_call.stderr
index 3671319..0692ecb 100644
--- a/src/tools/clippy/tests/ui/expect_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/expect_fun_call.stderr
@@ -38,58 +38,64 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{} {}", 1, 2))`
error: function call inside of `expect`
- --> tests/ui/expect_fun_call.rs:93:21
- |
-LL | Some("foo").expect(&get_string());
- | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })`
-
-error: function call inside of `expect`
- --> tests/ui/expect_fun_call.rs:95:21
- |
-LL | Some("foo").expect(get_string().as_ref());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })`
-
-error: function call inside of `expect`
--> tests/ui/expect_fun_call.rs:97:21
|
-LL | Some("foo").expect(get_string().as_str());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })`
+LL | Some("foo").expect(&get_string());
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{}", get_string()))`
error: function call inside of `expect`
- --> tests/ui/expect_fun_call.rs:100:21
+ --> tests/ui/expect_fun_call.rs:99:21
+ |
+LL | Some("foo").expect(get_string().as_ref());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{}", get_string()))`
+
+error: function call inside of `expect`
+ --> tests/ui/expect_fun_call.rs:101:21
+ |
+LL | Some("foo").expect(get_string().as_str());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{}", get_string()))`
+
+error: function call inside of `expect`
+ --> tests/ui/expect_fun_call.rs:104:21
|
LL | Some("foo").expect(get_static_str());
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_static_str()) })`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{}", get_static_str()))`
error: function call inside of `expect`
- --> tests/ui/expect_fun_call.rs:102:21
+ --> tests/ui/expect_fun_call.rs:106:21
|
LL | Some("foo").expect(get_non_static_str(&0));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{}", get_non_static_str(&0)))`
error: function call inside of `expect`
- --> tests/ui/expect_fun_call.rs:107:16
+ --> tests/ui/expect_fun_call.rs:109:21
+ |
+LL | Some("foo").expect(const_evaluable());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{}", const_evaluable()))`
+
+error: function call inside of `expect`
+ --> tests/ui/expect_fun_call.rs:120:16
|
LL | Some(true).expect(&format!("key {}, {}", 1, 2));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))`
error: function call inside of `expect`
- --> tests/ui/expect_fun_call.rs:114:17
+ --> tests/ui/expect_fun_call.rs:127:17
|
LL | opt_ref.expect(&format!("{:?}", opt_ref));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{:?}", opt_ref))`
error: function call inside of `expect`
- --> tests/ui/expect_fun_call.rs:119:20
+ --> tests/ui/expect_fun_call.rs:132:20
|
LL | format_capture.expect(&format!("{error_code}"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}"))`
error: function call inside of `expect`
- --> tests/ui/expect_fun_call.rs:123:30
+ --> tests/ui/expect_fun_call.rs:136:30
|
LL | format_capture_and_value.expect(&format!("{error_code}, {}", 1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}, {}", 1))`
-error: aborting due to 15 previous errors
+error: aborting due to 16 previous errors
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.fixed b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed
index b3e112f..d370b85 100644
--- a/src/tools/clippy/tests/ui/filter_map_bool_then.fixed
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed
@@ -89,3 +89,24 @@
let _: Vec<usize> = bools.iter().enumerate().filter(|&(i, b)| ****b).map(|(i, b)| i).collect();
//~^ filter_map_bool_then
}
+
+fn issue15047() {
+ #[derive(Clone, Copy)]
+ enum MyEnum {
+ A,
+ B,
+ C,
+ }
+
+ macro_rules! foo {
+ ($e:expr) => {
+ $e + 1
+ };
+ }
+
+ let x = 1;
+ let _ = [(MyEnum::A, "foo", 1i32)]
+ .iter()
+ .filter(|&(t, s, i)| matches!(t, MyEnum::A if s.starts_with("bar"))).map(|(t, s, i)| foo!(x));
+ //~^ filter_map_bool_then
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.rs b/src/tools/clippy/tests/ui/filter_map_bool_then.rs
index d996b3c..12295cc 100644
--- a/src/tools/clippy/tests/ui/filter_map_bool_then.rs
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.rs
@@ -89,3 +89,24 @@ fn deref(&self) -> &Self::Target {
let _: Vec<usize> = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect();
//~^ filter_map_bool_then
}
+
+fn issue15047() {
+ #[derive(Clone, Copy)]
+ enum MyEnum {
+ A,
+ B,
+ C,
+ }
+
+ macro_rules! foo {
+ ($e:expr) => {
+ $e + 1
+ };
+ }
+
+ let x = 1;
+ let _ = [(MyEnum::A, "foo", 1i32)]
+ .iter()
+ .filter_map(|(t, s, i)| matches!(t, MyEnum::A if s.starts_with("bar")).then(|| foo!(x)));
+ //~^ filter_map_bool_then
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.stderr b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr
index aeb1bae..edf6c65 100644
--- a/src/tools/clippy/tests/ui/filter_map_bool_then.stderr
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr
@@ -61,5 +61,11 @@
LL | let _: Vec<usize> = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(i, b)| ****b).map(|(i, b)| i)`
-error: aborting due to 10 previous errors
+error: usage of `bool::then` in `filter_map`
+ --> tests/ui/filter_map_bool_then.rs:110:10
+ |
+LL | .filter_map(|(t, s, i)| matches!(t, MyEnum::A if s.starts_with("bar")).then(|| foo!(x)));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(t, s, i)| matches!(t, MyEnum::A if s.starts_with("bar"))).map(|(t, s, i)| foo!(x))`
+
+error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/flat_map_identity.fixed b/src/tools/clippy/tests/ui/flat_map_identity.fixed
index f620623..06a3eee 100644
--- a/src/tools/clippy/tests/ui/flat_map_identity.fixed
+++ b/src/tools/clippy/tests/ui/flat_map_identity.fixed
@@ -16,3 +16,16 @@
let _ = iterator.flatten();
//~^ flat_map_identity
}
+
+fn issue15198() {
+ let x = [[1, 2], [3, 4]];
+ // don't lint: this is an `Iterator<Item = &[i32, i32]>`
+ // match ergonomics makes the binding patterns into references
+ // so that its type changes to `Iterator<Item = [&i32, &i32]>`
+ let _ = x.iter().flat_map(|[x, y]| [x, y]);
+ let _ = x.iter().flat_map(|x| [x[0]]);
+
+ // no match ergonomics for `[i32, i32]`
+ let _ = x.iter().copied().flatten();
+ //~^ flat_map_identity
+}
diff --git a/src/tools/clippy/tests/ui/flat_map_identity.rs b/src/tools/clippy/tests/ui/flat_map_identity.rs
index c59e749..1cab7d5 100644
--- a/src/tools/clippy/tests/ui/flat_map_identity.rs
+++ b/src/tools/clippy/tests/ui/flat_map_identity.rs
@@ -16,3 +16,16 @@ fn main() {
let _ = iterator.flat_map(|x| return x);
//~^ flat_map_identity
}
+
+fn issue15198() {
+ let x = [[1, 2], [3, 4]];
+ // don't lint: this is an `Iterator<Item = &[i32, i32]>`
+ // match ergonomics makes the binding patterns into references
+ // so that its type changes to `Iterator<Item = [&i32, &i32]>`
+ let _ = x.iter().flat_map(|[x, y]| [x, y]);
+ let _ = x.iter().flat_map(|x| [x[0]]);
+
+ // no match ergonomics for `[i32, i32]`
+ let _ = x.iter().copied().flat_map(|[x, y]| [x, y]);
+ //~^ flat_map_identity
+}
diff --git a/src/tools/clippy/tests/ui/flat_map_identity.stderr b/src/tools/clippy/tests/ui/flat_map_identity.stderr
index 75137f5..18c863b 100644
--- a/src/tools/clippy/tests/ui/flat_map_identity.stderr
+++ b/src/tools/clippy/tests/ui/flat_map_identity.stderr
@@ -19,5 +19,11 @@
LL | let _ = iterator.flat_map(|x| return x);
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
-error: aborting due to 3 previous errors
+error: use of `flat_map` with an identity function
+ --> tests/ui/flat_map_identity.rs:29:31
+ |
+LL | let _ = x.iter().copied().flat_map(|[x, y]| [x, y]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.fixed b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed
index f774608..d14a805 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.fixed
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed
@@ -122,3 +122,46 @@
// Should not issue an error in `const` context
if x > 42 { Some(150) } else { None }
}
+
+mod issue15257 {
+ struct Range {
+ start: u8,
+ end: u8,
+ }
+
+ fn can_be_safely_rewrite(rs: &[&Range]) -> Option<Vec<u8>> {
+ (rs.len() == 1 && rs[0].start == rs[0].end).then(|| vec![rs[0].start])
+ }
+
+ fn reborrow_as_ptr(i: *mut i32) -> Option<*const i32> {
+ let modulo = unsafe { *i % 2 };
+ (modulo == 0).then_some(i)
+ }
+
+ fn reborrow_as_fn_ptr(i: i32) {
+ fn do_something(fn_: Option<fn(i32)>) {
+ todo!()
+ }
+
+ fn item_fn(i: i32) {
+ todo!()
+ }
+
+ do_something((i % 2 == 0).then_some(item_fn));
+ }
+
+ fn reborrow_as_fn_unsafe(i: i32) {
+ fn do_something(fn_: Option<unsafe fn(i32)>) {
+ todo!()
+ }
+
+ fn item_fn(i: i32) {
+ todo!()
+ }
+
+ do_something((i % 2 == 0).then_some(item_fn));
+
+ let closure_fn = |i: i32| {};
+ do_something((i % 2 == 0).then_some(closure_fn));
+ }
+}
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.rs b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
index 8b8ff0a..bb0072f 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.rs
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
@@ -143,3 +143,71 @@ const fn issue12103(x: u32) -> Option<u32> {
// Should not issue an error in `const` context
if x > 42 { Some(150) } else { None }
}
+
+mod issue15257 {
+ struct Range {
+ start: u8,
+ end: u8,
+ }
+
+ fn can_be_safely_rewrite(rs: &[&Range]) -> Option<Vec<u8>> {
+ if rs.len() == 1 && rs[0].start == rs[0].end {
+ //~^ if_then_some_else_none
+ Some(vec![rs[0].start])
+ } else {
+ None
+ }
+ }
+
+ fn reborrow_as_ptr(i: *mut i32) -> Option<*const i32> {
+ let modulo = unsafe { *i % 2 };
+ if modulo == 0 {
+ //~^ if_then_some_else_none
+ Some(i)
+ } else {
+ None
+ }
+ }
+
+ fn reborrow_as_fn_ptr(i: i32) {
+ fn do_something(fn_: Option<fn(i32)>) {
+ todo!()
+ }
+
+ fn item_fn(i: i32) {
+ todo!()
+ }
+
+ do_something(if i % 2 == 0 {
+ //~^ if_then_some_else_none
+ Some(item_fn)
+ } else {
+ None
+ });
+ }
+
+ fn reborrow_as_fn_unsafe(i: i32) {
+ fn do_something(fn_: Option<unsafe fn(i32)>) {
+ todo!()
+ }
+
+ fn item_fn(i: i32) {
+ todo!()
+ }
+
+ do_something(if i % 2 == 0 {
+ //~^ if_then_some_else_none
+ Some(item_fn)
+ } else {
+ None
+ });
+
+ let closure_fn = |i: i32| {};
+ do_something(if i % 2 == 0 {
+ //~^ if_then_some_else_none
+ Some(closure_fn)
+ } else {
+ None
+ });
+ }
+}
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
index 7128557..c2e624a 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
@@ -58,5 +58,63 @@
LL | if s == "1" { Some(true) } else { None }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(s == "1").then(|| true)`
-error: aborting due to 6 previous errors
+error: this could be simplified with `bool::then`
+ --> tests/ui/if_then_some_else_none.rs:154:9
+ |
+LL | / if rs.len() == 1 && rs[0].start == rs[0].end {
+LL | |
+LL | | Some(vec![rs[0].start])
+LL | | } else {
+LL | | None
+LL | | }
+ | |_________^ help: try: `(rs.len() == 1 && rs[0].start == rs[0].end).then(|| vec![rs[0].start])`
+
+error: this could be simplified with `bool::then_some`
+ --> tests/ui/if_then_some_else_none.rs:164:9
+ |
+LL | / if modulo == 0 {
+LL | |
+LL | | Some(i)
+LL | | } else {
+LL | | None
+LL | | }
+ | |_________^ help: try: `(modulo == 0).then_some(i)`
+
+error: this could be simplified with `bool::then_some`
+ --> tests/ui/if_then_some_else_none.rs:181:22
+ |
+LL | do_something(if i % 2 == 0 {
+ | ______________________^
+LL | |
+LL | | Some(item_fn)
+LL | | } else {
+LL | | None
+LL | | });
+ | |_________^ help: try: `(i % 2 == 0).then_some(item_fn)`
+
+error: this could be simplified with `bool::then_some`
+ --> tests/ui/if_then_some_else_none.rs:198:22
+ |
+LL | do_something(if i % 2 == 0 {
+ | ______________________^
+LL | |
+LL | | Some(item_fn)
+LL | | } else {
+LL | | None
+LL | | });
+ | |_________^ help: try: `(i % 2 == 0).then_some(item_fn)`
+
+error: this could be simplified with `bool::then_some`
+ --> tests/ui/if_then_some_else_none.rs:206:22
+ |
+LL | do_something(if i % 2 == 0 {
+ | ______________________^
+LL | |
+LL | | Some(closure_fn)
+LL | | } else {
+LL | | None
+LL | | });
+ | |_________^ help: try: `(i % 2 == 0).then_some(closure_fn)`
+
+error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none_unfixable.rs b/src/tools/clippy/tests/ui/if_then_some_else_none_unfixable.rs
new file mode 100644
index 0000000..be04299
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none_unfixable.rs
@@ -0,0 +1,35 @@
+#![warn(clippy::if_then_some_else_none)]
+#![allow(clippy::manual_is_multiple_of)]
+
+mod issue15257 {
+ use std::pin::Pin;
+
+ #[derive(Default)]
+ pub struct Foo {}
+ pub trait Bar {}
+ impl Bar for Foo {}
+
+ fn pointer_unsized_coercion(i: u32) -> Option<Box<dyn Bar>> {
+ if i % 2 == 0 {
+ //~^ if_then_some_else_none
+ Some(Box::new(Foo::default()))
+ } else {
+ None
+ }
+ }
+
+ fn reborrow_as_pin(i: Pin<&mut i32>) {
+ use std::ops::Rem;
+
+ fn do_something(i: Option<&i32>) {
+ todo!()
+ }
+
+ do_something(if i.rem(2) == 0 {
+ //~^ if_then_some_else_none
+ Some(&i)
+ } else {
+ None
+ });
+ }
+}
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none_unfixable.stderr b/src/tools/clippy/tests/ui/if_then_some_else_none_unfixable.stderr
new file mode 100644
index 0000000..f77ce79
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none_unfixable.stderr
@@ -0,0 +1,28 @@
+error: this could be simplified with `bool::then`
+ --> tests/ui/if_then_some_else_none_unfixable.rs:13:9
+ |
+LL | / if i % 2 == 0 {
+LL | |
+LL | | Some(Box::new(Foo::default()))
+LL | | } else {
+LL | | None
+LL | | }
+ | |_________^
+ |
+ = note: `-D clippy::if-then-some-else-none` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::if_then_some_else_none)]`
+
+error: this could be simplified with `bool::then`
+ --> tests/ui/if_then_some_else_none_unfixable.rs:28:22
+ |
+LL | do_something(if i.rem(2) == 0 {
+ | ______________________^
+LL | |
+LL | | Some(&i)
+LL | | } else {
+LL | | None
+LL | | });
+ | |_________^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/incompatible_msrv.rs b/src/tools/clippy/tests/ui/incompatible_msrv.rs
index 99101b2..f7f21e1 100644
--- a/src/tools/clippy/tests/ui/incompatible_msrv.rs
+++ b/src/tools/clippy/tests/ui/incompatible_msrv.rs
@@ -1,8 +1,10 @@
#![warn(clippy::incompatible_msrv)]
#![feature(custom_inner_attributes)]
-#![feature(panic_internals)]
+#![allow(stable_features)]
+#![feature(strict_provenance)] // For use in test
#![clippy::msrv = "1.3.0"]
+use std::cell::Cell;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::future::Future;
@@ -13,6 +15,8 @@ fn foo() {
let mut map: HashMap<&str, u32> = HashMap::new();
assert_eq!(map.entry("poneyland").key(), &"poneyland");
//~^ incompatible_msrv
+ //~| NOTE: `-D clippy::incompatible-msrv` implied by `-D warnings`
+ //~| HELP: to override `-D warnings` add `#[allow(clippy::incompatible_msrv)]`
if let Entry::Vacant(v) = map.entry("poneyland") {
v.into_key();
@@ -23,6 +27,18 @@ fn foo() {
//~^ incompatible_msrv
}
+#[clippy::msrv = "1.2.0"]
+static NO_BODY_BAD_MSRV: Option<Duration> = None;
+//~^ incompatible_msrv
+
+static NO_BODY_GOOD_MSRV: Option<Duration> = None;
+
+#[clippy::msrv = "1.2.0"]
+fn bad_type_msrv() {
+ let _: Option<Duration> = None;
+ //~^ incompatible_msrv
+}
+
#[test]
fn test() {
sleep(Duration::new(1, 0));
@@ -43,21 +59,22 @@ fn core_special_treatment(p: bool) {
// But still lint code calling `core` functions directly
if p {
- core::panicking::panic("foo");
- //~^ ERROR: is `1.3.0` but this item is stable since `1.6.0`
+ let _ = core::iter::once_with(|| 0);
+ //~^ incompatible_msrv
}
// Lint code calling `core` from non-`core` macros
macro_rules! my_panic {
($msg:expr) => {
- core::panicking::panic($msg)
- }; //~^ ERROR: is `1.3.0` but this item is stable since `1.6.0`
+ let _ = core::iter::once_with(|| $msg);
+ //~^ incompatible_msrv
+ };
}
my_panic!("foo");
// Lint even when the macro comes from `core` and calls `core` functions
- assert!(core::panicking::panic("out of luck"));
- //~^ ERROR: is `1.3.0` but this item is stable since `1.6.0`
+ assert!(core::iter::once_with(|| 0).next().is_some());
+ //~^ incompatible_msrv
}
#[clippy::msrv = "1.26.0"]
@@ -70,7 +87,85 @@ fn lang_items() {
#[clippy::msrv = "1.80.0"]
fn issue14212() {
let _ = std::iter::repeat_n((), 5);
- //~^ ERROR: is `1.80.0` but this item is stable since `1.82.0`
+ //~^ incompatible_msrv
+}
+
+#[clippy::msrv = "1.0.0"]
+fn cstr_and_cstring_ok() {
+ let _: Option<&'static std::ffi::CStr> = None;
+ let _: Option<std::ffi::CString> = None;
+}
+
+fn local_msrv_change_suggestion() {
+ let _ = std::iter::repeat_n((), 5);
+ //~^ incompatible_msrv
+
+ #[cfg(any(test, not(test)))]
+ {
+ let _ = std::iter::repeat_n((), 5);
+ //~^ incompatible_msrv
+ //~| NOTE: you may want to conditionally increase the MSRV
+
+ // Emit the additional note only once
+ let _ = std::iter::repeat_n((), 5);
+ //~^ incompatible_msrv
+ }
+}
+
+#[clippy::msrv = "1.78.0"]
+fn feature_enable_14425(ptr: *const u8) -> usize {
+ // Do not warn, because it is enabled through a feature even though
+ // it is stabilized only since Rust 1.84.0.
+ let r = ptr.addr();
+
+ // Warn about this which has been introduced in the same Rust version
+ // but is not allowed through a feature.
+ r.isqrt()
+ //~^ incompatible_msrv
+}
+
+fn non_fn_items() {
+ let _ = std::io::ErrorKind::CrossesDevices;
+ //~^ incompatible_msrv
+}
+
+#[clippy::msrv = "1.87.0"]
+fn msrv_non_ok_in_const() {
+ {
+ let c = Cell::new(42);
+ _ = c.get();
+ }
+ const {
+ let c = Cell::new(42);
+ _ = c.get();
+ //~^ incompatible_msrv
+ }
+}
+
+#[clippy::msrv = "1.88.0"]
+fn msrv_ok_in_const() {
+ {
+ let c = Cell::new(42);
+ _ = c.get();
+ }
+ const {
+ let c = Cell::new(42);
+ _ = c.get();
+ }
+}
+
+#[clippy::msrv = "1.86.0"]
+fn enum_variant_not_ok() {
+ let _ = std::io::ErrorKind::InvalidFilename;
+ //~^ incompatible_msrv
+ let _ = const { std::io::ErrorKind::InvalidFilename };
+ //~^ incompatible_msrv
+}
+
+#[clippy::msrv = "1.87.0"]
+fn enum_variant_ok() {
+ let _ = std::io::ErrorKind::InvalidFilename;
+ let _ = const { std::io::ErrorKind::InvalidFilename };
}
fn main() {}
diff --git a/src/tools/clippy/tests/ui/incompatible_msrv.stderr b/src/tools/clippy/tests/ui/incompatible_msrv.stderr
index 5ea2bb9..e42360d 100644
--- a/src/tools/clippy/tests/ui/incompatible_msrv.stderr
+++ b/src/tools/clippy/tests/ui/incompatible_msrv.stderr
@@ -1,5 +1,5 @@
error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.10.0`
- --> tests/ui/incompatible_msrv.rs:14:39
+ --> tests/ui/incompatible_msrv.rs:16:39
|
LL | assert_eq!(map.entry("poneyland").key(), &"poneyland");
| ^^^^^
@@ -8,45 +8,107 @@
= help: to override `-D warnings` add `#[allow(clippy::incompatible_msrv)]`
error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.12.0`
- --> tests/ui/incompatible_msrv.rs:18:11
+ --> tests/ui/incompatible_msrv.rs:22:11
|
LL | v.into_key();
| ^^^^^^^^^^
error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.4.0`
- --> tests/ui/incompatible_msrv.rs:22:5
+ --> tests/ui/incompatible_msrv.rs:26:5
|
LL | sleep(Duration::new(1, 0));
| ^^^^^
-error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.6.0`
- --> tests/ui/incompatible_msrv.rs:46:9
+error: current MSRV (Minimum Supported Rust Version) is `1.2.0` but this item is stable since `1.3.0`
+ --> tests/ui/incompatible_msrv.rs:31:33
|
-LL | core::panicking::panic("foo");
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | static NO_BODY_BAD_MSRV: Option<Duration> = None;
+ | ^^^^^^^^
-error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.6.0`
- --> tests/ui/incompatible_msrv.rs:53:13
+error: current MSRV (Minimum Supported Rust Version) is `1.2.0` but this item is stable since `1.3.0`
+ --> tests/ui/incompatible_msrv.rs:38:19
|
-LL | core::panicking::panic($msg)
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | let _: Option<Duration> = None;
+ | ^^^^^^^^
+
+error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.43.0`
+ --> tests/ui/incompatible_msrv.rs:62:17
+ |
+LL | let _ = core::iter::once_with(|| 0);
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.43.0`
+ --> tests/ui/incompatible_msrv.rs:69:21
+ |
+LL | let _ = core::iter::once_with(|| $msg);
+ | ^^^^^^^^^^^^^^^^^^^^^
...
LL | my_panic!("foo");
| ---------------- in this macro invocation
|
= note: this error originates in the macro `my_panic` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.6.0`
- --> tests/ui/incompatible_msrv.rs:59:13
+error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.43.0`
+ --> tests/ui/incompatible_msrv.rs:76:13
|
-LL | assert!(core::panicking::panic("out of luck"));
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | assert!(core::iter::once_with(|| 0).next().is_some());
+ | ^^^^^^^^^^^^^^^^^^^^^
error: current MSRV (Minimum Supported Rust Version) is `1.80.0` but this item is stable since `1.82.0`
- --> tests/ui/incompatible_msrv.rs:72:13
+ --> tests/ui/incompatible_msrv.rs:89:13
|
LL | let _ = std::iter::repeat_n((), 5);
| ^^^^^^^^^^^^^^^^^^^
-error: aborting due to 7 previous errors
+error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.82.0`
+ --> tests/ui/incompatible_msrv.rs:100:13
+ |
+LL | let _ = std::iter::repeat_n((), 5);
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.82.0`
+ --> tests/ui/incompatible_msrv.rs:105:17
+ |
+LL | let _ = std::iter::repeat_n((), 5);
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: you may want to conditionally increase the MSRV considered by Clippy using the `clippy::msrv` attribute
+
+error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.82.0`
+ --> tests/ui/incompatible_msrv.rs:110:17
+ |
+LL | let _ = std::iter::repeat_n((), 5);
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: current MSRV (Minimum Supported Rust Version) is `1.78.0` but this item is stable since `1.84.0`
+ --> tests/ui/incompatible_msrv.rs:123:7
+ |
+LL | r.isqrt()
+ | ^^^^^^^
+
+error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.85.0`
+ --> tests/ui/incompatible_msrv.rs:128:13
+ |
+LL | let _ = std::io::ErrorKind::CrossesDevices;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: current MSRV (Minimum Supported Rust Version) is `1.87.0` but this item is stable in a `const` context since `1.88.0`
+ --> tests/ui/incompatible_msrv.rs:140:15
+ |
+LL | _ = c.get();
+ | ^^^^^
+
+error: current MSRV (Minimum Supported Rust Version) is `1.86.0` but this item is stable since `1.87.0`
+ --> tests/ui/incompatible_msrv.rs:159:13
+ |
+LL | let _ = std::io::ErrorKind::InvalidFilename;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: current MSRV (Minimum Supported Rust Version) is `1.86.0` but this item is stable since `1.87.0`
+ --> tests/ui/incompatible_msrv.rs:161:21
+ |
+LL | let _ = const { std::io::ErrorKind::InvalidFilename };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 17 previous errors
diff --git a/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr b/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr
index 80ca5da..ac1ed27 100644
--- a/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr
+++ b/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr
@@ -12,7 +12,7 @@
|
= note: `-D clippy::large-enum-variant` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::large_enum_variant)]`
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - B([i32; 8000]),
LL + B(Box<[i32; 8000]>),
@@ -30,7 +30,7 @@
LL | | }
| |_^ the entire enum is at least 32004 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - ContainingLargeEnum(LargeEnum),
LL + ContainingLargeEnum(Box<LargeEnum>),
@@ -49,7 +49,7 @@
LL | | }
| |_^ the entire enum is at least 70008 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
LL + ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>),
@@ -67,7 +67,7 @@
LL | | }
| |_^ the entire enum is at least 32008 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - StructLikeLarge { x: [i32; 8000], y: i32 },
LL + StructLikeLarge { x: Box<[i32; 8000]>, y: i32 },
@@ -85,7 +85,7 @@
LL | | }
| |_^ the entire enum is at least 32004 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - StructLikeLarge2 { x: [i32; 8000] },
LL + StructLikeLarge2 { x: Box<[i32; 8000]> },
@@ -104,7 +104,7 @@
LL | | }
| |_^ the entire enum is at least 1256 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - B([u8; 1255]),
LL + B(Box<[u8; 1255]>),
@@ -122,7 +122,7 @@
LL | | }
| |_^ the entire enum is at least 70132 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
LL + ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]),
@@ -140,7 +140,7 @@
LL | | }
| |_^ the entire enum is at least 32004 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - B(Struct2),
LL + B(Box<Struct2>),
@@ -158,7 +158,7 @@
LL | | }
| |_^ the entire enum is at least 32000 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - B(Struct2),
LL + B(Box<Struct2>),
@@ -176,7 +176,7 @@
LL | | }
| |_^ the entire enum is at least 32000 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - B(Struct2),
LL + B(Box<Struct2>),
@@ -199,7 +199,7 @@
|
LL | enum CopyableLargeEnum {
| ^^^^^^^^^^^^^^^^^
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
--> tests/ui/large_enum_variant.rs:118:5
|
LL | B([u64; 8000]),
@@ -222,7 +222,7 @@
|
LL | enum ManuallyCopyLargeEnum {
| ^^^^^^^^^^^^^^^^^^^^^
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
--> tests/ui/large_enum_variant.rs:124:5
|
LL | B([u64; 8000]),
@@ -245,7 +245,7 @@
|
LL | enum SomeGenericPossiblyCopyEnum<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
--> tests/ui/large_enum_variant.rs:138:5
|
LL | B([u64; 4000]),
@@ -263,7 +263,7 @@
LL | | }
| |_^ the entire enum is at least 512 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - Large((T, [u8; 512])),
LL + Large(Box<(T, [u8; 512])>),
@@ -281,7 +281,7 @@
LL | | }
| |_^ the entire enum is at least 516 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - Large([Foo<u64>; 64]),
LL + Large(Box<[Foo<u64>; 64]>),
@@ -299,7 +299,7 @@
LL | | }
| |_^ the entire enum is at least 514 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - Error(PossiblyLargeEnumWithConst<256>),
LL + Error(Box<PossiblyLargeEnumWithConst<256>>),
@@ -317,7 +317,7 @@
LL | | }
| |_^ the entire enum is at least 516 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - Large([u64; 64]),
LL + Large(Box<[u64; 64]>),
@@ -335,7 +335,7 @@
LL | | }
| |_^ the entire enum is at least 516 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - Error(WithRecursionAndGenerics<u64>),
LL + Error(Box<WithRecursionAndGenerics<u64>>),
diff --git a/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr b/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr
index 559bdf2..d8199f9 100644
--- a/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr
+++ b/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr
@@ -12,7 +12,7 @@
|
= note: `-D clippy::large-enum-variant` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::large_enum_variant)]`
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - B([i32; 8000]),
LL + B(Box<[i32; 8000]>),
@@ -30,7 +30,7 @@
LL | | }
| |_^ the entire enum is at least 32004 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - ContainingLargeEnum(LargeEnum),
LL + ContainingLargeEnum(Box<LargeEnum>),
@@ -49,7 +49,7 @@
LL | | }
| |_^ the entire enum is at least 70008 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
LL + ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>),
@@ -67,7 +67,7 @@
LL | | }
| |_^ the entire enum is at least 32008 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - StructLikeLarge { x: [i32; 8000], y: i32 },
LL + StructLikeLarge { x: Box<[i32; 8000]>, y: i32 },
@@ -85,7 +85,7 @@
LL | | }
| |_^ the entire enum is at least 32004 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - StructLikeLarge2 { x: [i32; 8000] },
LL + StructLikeLarge2 { x: Box<[i32; 8000]> },
@@ -104,7 +104,7 @@
LL | | }
| |_^ the entire enum is at least 1256 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - B([u8; 1255]),
LL + B(Box<[u8; 1255]>),
@@ -122,7 +122,7 @@
LL | | }
| |_^ the entire enum is at least 70132 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
LL + ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]),
@@ -140,7 +140,7 @@
LL | | }
| |_^ the entire enum is at least 32004 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - B(Struct2),
LL + B(Box<Struct2>),
@@ -158,7 +158,7 @@
LL | | }
| |_^ the entire enum is at least 32000 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - B(Struct2),
LL + B(Box<Struct2>),
@@ -176,7 +176,7 @@
LL | | }
| |_^ the entire enum is at least 32000 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - B(Struct2),
LL + B(Box<Struct2>),
@@ -199,7 +199,7 @@
|
LL | enum CopyableLargeEnum {
| ^^^^^^^^^^^^^^^^^
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
--> tests/ui/large_enum_variant.rs:118:5
|
LL | B([u64; 8000]),
@@ -222,7 +222,7 @@
|
LL | enum ManuallyCopyLargeEnum {
| ^^^^^^^^^^^^^^^^^^^^^
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
--> tests/ui/large_enum_variant.rs:124:5
|
LL | B([u64; 8000]),
@@ -245,7 +245,7 @@
|
LL | enum SomeGenericPossiblyCopyEnum<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
--> tests/ui/large_enum_variant.rs:138:5
|
LL | B([u64; 4000]),
@@ -263,7 +263,7 @@
LL | | }
| |_^ the entire enum is at least 512 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - Large((T, [u8; 512])),
LL + Large(Box<(T, [u8; 512])>),
@@ -281,7 +281,7 @@
LL | | }
| |_^ the entire enum is at least 520 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - Large([Foo<u64>; 64]),
LL + Large(Box<[Foo<u64>; 64]>),
@@ -299,7 +299,7 @@
LL | | }
| |_^ the entire enum is at least 514 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - Error(PossiblyLargeEnumWithConst<256>),
LL + Error(Box<PossiblyLargeEnumWithConst<256>>),
@@ -317,7 +317,7 @@
LL | | }
| |_^ the entire enum is at least 520 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - Large([u64; 64]),
LL + Large(Box<[u64; 64]>),
@@ -335,7 +335,7 @@
LL | | }
| |_^ the entire enum is at least 520 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - Error(WithRecursionAndGenerics<u64>),
LL + Error(Box<WithRecursionAndGenerics<u64>>),
@@ -353,7 +353,7 @@
LL | | }
| |_____^ the entire enum is at least 296 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - BigBoi(PublishWithBytes),
LL + BigBoi(Box<PublishWithBytes>),
@@ -371,7 +371,7 @@
LL | | }
| |_____^ the entire enum is at least 224 bytes
|
-help: consider boxing the large fields to reduce the total size of the enum
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
|
LL - BigBoi(PublishWithVec),
LL + BigBoi(Box<PublishWithVec>),
diff --git a/src/tools/clippy/tests/ui/large_enum_variant_no_std.rs b/src/tools/clippy/tests/ui/large_enum_variant_no_std.rs
new file mode 100644
index 0000000..ff02131
--- /dev/null
+++ b/src/tools/clippy/tests/ui/large_enum_variant_no_std.rs
@@ -0,0 +1,8 @@
+#![no_std]
+#![warn(clippy::large_enum_variant)]
+
+enum Myenum {
+ //~^ ERROR: large size difference between variants
+ Small(u8),
+ Large([u8; 1024]),
+}
diff --git a/src/tools/clippy/tests/ui/large_enum_variant_no_std.stderr b/src/tools/clippy/tests/ui/large_enum_variant_no_std.stderr
new file mode 100644
index 0000000..4f32e3e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/large_enum_variant_no_std.stderr
@@ -0,0 +1,22 @@
+error: large size difference between variants
+ --> tests/ui/large_enum_variant_no_std.rs:4:1
+ |
+LL | / enum Myenum {
+LL | |
+LL | | Small(u8),
+ | | --------- the second-largest variant contains at least 1 bytes
+LL | | Large([u8; 1024]),
+ | | ----------------- the largest variant contains at least 1024 bytes
+LL | | }
+ | |_^ the entire enum is at least 1025 bytes
+ |
+help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
+ --> tests/ui/large_enum_variant_no_std.rs:7:5
+ |
+LL | Large([u8; 1024]),
+ | ^^^^^^^^^^^^^^^^^
+ = note: `-D clippy::large-enum-variant` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::large_enum_variant)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed b/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed
index 30bb549..d90e7be 100644
--- a/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed
+++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed
@@ -79,9 +79,31 @@
f64::consts::E;
b!();
+ std::primitive::i32::MAX;
+ //~^ ERROR: usage of a legacy numeric method
+ //~| HELP: use the associated constant instead
[(0, "", i128::MAX)];
//~^ ERROR: usage of a legacy numeric constant
//~| HELP: use the associated constant instead
+ i32::MAX;
+ //~^ ERROR: usage of a legacy numeric method
+ //~| HELP: use the associated constant instead
+ assert_eq!(0, -i32::MAX);
+ //~^ ERROR: usage of a legacy numeric method
+ //~| HELP: use the associated constant instead
+ i128::MAX;
+ //~^ ERROR: usage of a legacy numeric constant
+ //~| HELP: use the associated constant instead
+ u32::MAX;
+ //~^ ERROR: usage of a legacy numeric method
+ //~| HELP: use the associated constant instead
+ i32::MAX;
+ //~^ ERROR: usage of a legacy numeric method
+ //~| HELP: use the associated constant instead
+ type Ω = i32;
+ Ω::MAX;
+ //~^ ERROR: usage of a legacy numeric method
+ //~| HELP: use the associated constant instead
}
#[warn(clippy::legacy_numeric_constants)]
diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.rs b/src/tools/clippy/tests/ui/legacy_numeric_constants.rs
index d387819..4a2ef3f 100644
--- a/src/tools/clippy/tests/ui/legacy_numeric_constants.rs
+++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.rs
@@ -79,9 +79,31 @@ fn main() {
f64::consts::E;
b!();
+ <std::primitive::i32>::max_value();
+ //~^ ERROR: usage of a legacy numeric method
+ //~| HELP: use the associated constant instead
[(0, "", std::i128::MAX)];
//~^ ERROR: usage of a legacy numeric constant
//~| HELP: use the associated constant instead
+ (i32::max_value());
+ //~^ ERROR: usage of a legacy numeric method
+ //~| HELP: use the associated constant instead
+ assert_eq!(0, -(i32::max_value()));
+ //~^ ERROR: usage of a legacy numeric method
+ //~| HELP: use the associated constant instead
+ (std::i128::MAX);
+ //~^ ERROR: usage of a legacy numeric constant
+ //~| HELP: use the associated constant instead
+ (<u32>::max_value());
+ //~^ ERROR: usage of a legacy numeric method
+ //~| HELP: use the associated constant instead
+ ((i32::max_value)());
+ //~^ ERROR: usage of a legacy numeric method
+ //~| HELP: use the associated constant instead
+ type Ω = i32;
+ Ω::max_value();
+ //~^ ERROR: usage of a legacy numeric method
+ //~| HELP: use the associated constant instead
}
#[warn(clippy::legacy_numeric_constants)]
diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr b/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr
index 4d69b81..0b4f32e 100644
--- a/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr
+++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr
@@ -72,10 +72,10 @@
| +++++
error: usage of a legacy numeric method
- --> tests/ui/legacy_numeric_constants.rs:50:10
+ --> tests/ui/legacy_numeric_constants.rs:50:5
|
LL | i32::max_value();
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
@@ -84,10 +84,10 @@
|
error: usage of a legacy numeric method
- --> tests/ui/legacy_numeric_constants.rs:53:9
+ --> tests/ui/legacy_numeric_constants.rs:53:5
|
LL | u8::max_value();
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
@@ -96,10 +96,10 @@
|
error: usage of a legacy numeric method
- --> tests/ui/legacy_numeric_constants.rs:56:9
+ --> tests/ui/legacy_numeric_constants.rs:56:5
|
LL | u8::min_value();
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
@@ -120,10 +120,10 @@
|
error: usage of a legacy numeric method
- --> tests/ui/legacy_numeric_constants.rs:62:27
+ --> tests/ui/legacy_numeric_constants.rs:62:5
|
LL | ::std::primitive::u8::min_value();
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
@@ -132,10 +132,10 @@
|
error: usage of a legacy numeric method
- --> tests/ui/legacy_numeric_constants.rs:65:26
+ --> tests/ui/legacy_numeric_constants.rs:65:5
|
LL | std::primitive::i32::max_value();
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
@@ -171,8 +171,20 @@
LL + let x = u64::MAX;
|
+error: usage of a legacy numeric method
+ --> tests/ui/legacy_numeric_constants.rs:82:5
+ |
+LL | <std::primitive::i32>::max_value();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: use the associated constant instead
+ |
+LL - <std::primitive::i32>::max_value();
+LL + std::primitive::i32::MAX;
+ |
+
error: usage of a legacy numeric constant
- --> tests/ui/legacy_numeric_constants.rs:82:14
+ --> tests/ui/legacy_numeric_constants.rs:85:14
|
LL | [(0, "", std::i128::MAX)];
| ^^^^^^^^^^^^^^
@@ -183,8 +195,80 @@
LL + [(0, "", i128::MAX)];
|
+error: usage of a legacy numeric method
+ --> tests/ui/legacy_numeric_constants.rs:88:5
+ |
+LL | (i32::max_value());
+ | ^^^^^^^^^^^^^^^^^^
+ |
+help: use the associated constant instead
+ |
+LL - (i32::max_value());
+LL + i32::MAX;
+ |
+
+error: usage of a legacy numeric method
+ --> tests/ui/legacy_numeric_constants.rs:91:20
+ |
+LL | assert_eq!(0, -(i32::max_value()));
+ | ^^^^^^^^^^^^^^^^^^
+ |
+help: use the associated constant instead
+ |
+LL - assert_eq!(0, -(i32::max_value()));
+LL + assert_eq!(0, -i32::MAX);
+ |
+
error: usage of a legacy numeric constant
- --> tests/ui/legacy_numeric_constants.rs:116:5
+ --> tests/ui/legacy_numeric_constants.rs:94:5
+ |
+LL | (std::i128::MAX);
+ | ^^^^^^^^^^^^^^^^
+ |
+help: use the associated constant instead
+ |
+LL - (std::i128::MAX);
+LL + i128::MAX;
+ |
+
+error: usage of a legacy numeric method
+ --> tests/ui/legacy_numeric_constants.rs:97:5
+ |
+LL | (<u32>::max_value());
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+help: use the associated constant instead
+ |
+LL - (<u32>::max_value());
+LL + u32::MAX;
+ |
+
+error: usage of a legacy numeric method
+ --> tests/ui/legacy_numeric_constants.rs:100:5
+ |
+LL | ((i32::max_value)());
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+help: use the associated constant instead
+ |
+LL - ((i32::max_value)());
+LL + i32::MAX;
+ |
+
+error: usage of a legacy numeric method
+ --> tests/ui/legacy_numeric_constants.rs:104:5
+ |
+LL | Ω::max_value();
+ | ^^^^^^^^^^^^^^
+ |
+help: use the associated constant instead
+ |
+LL - Ω::max_value();
+LL + Ω::MAX;
+ |
+
+error: usage of a legacy numeric constant
+ --> tests/ui/legacy_numeric_constants.rs:138:5
|
LL | std::u32::MAX;
| ^^^^^^^^^^^^^
@@ -195,5 +279,5 @@
LL + u32::MAX;
|
-error: aborting due to 16 previous errors
+error: aborting due to 23 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_abs_diff.fixed b/src/tools/clippy/tests/ui/manual_abs_diff.fixed
index f1b1278..2766942 100644
--- a/src/tools/clippy/tests/ui/manual_abs_diff.fixed
+++ b/src/tools/clippy/tests/ui/manual_abs_diff.fixed
@@ -104,3 +104,7 @@
let (a, b) = (S(10), S(20));
let _ = if a < b { b - a } else { a - b };
}
+
+fn issue15254(a: &usize, b: &usize) -> usize {
+ b.abs_diff(*a)
+}
diff --git a/src/tools/clippy/tests/ui/manual_abs_diff.rs b/src/tools/clippy/tests/ui/manual_abs_diff.rs
index 60ef819..2c408f2 100644
--- a/src/tools/clippy/tests/ui/manual_abs_diff.rs
+++ b/src/tools/clippy/tests/ui/manual_abs_diff.rs
@@ -114,3 +114,12 @@ fn sub(self, rhs: Self) -> Self::Output {
let (a, b) = (S(10), S(20));
let _ = if a < b { b - a } else { a - b };
}
+
+fn issue15254(a: &usize, b: &usize) -> usize {
+ if a < b {
+ //~^ manual_abs_diff
+ 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
index c14c1dc..bb6d312 100644
--- a/src/tools/clippy/tests/ui/manual_abs_diff.stderr
+++ b/src/tools/clippy/tests/ui/manual_abs_diff.stderr
@@ -79,5 +79,16 @@
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
+error: manual absolute difference pattern without using `abs_diff`
+ --> tests/ui/manual_abs_diff.rs:119:5
+ |
+LL | / if a < b {
+LL | |
+LL | | b - a
+LL | | } else {
+LL | | a - b
+LL | | }
+ | |_____^ help: replace with `abs_diff`: `b.abs_diff(*a)`
+
+error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
index 8cedf2c..221cddf 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
@@ -189,5 +189,23 @@
LL + const BAR: () = assert!(!(N == 0), );
|
-error: aborting due to 10 previous errors
+error: only a `panic!` in `if`-then statement
+ --> tests/ui/manual_assert.rs:116:5
+ |
+LL | / if !is_x86_feature_detected!("ssse3") {
+LL | |
+LL | | panic!("SSSE3 is not supported");
+LL | | }
+ | |_____^
+ |
+help: try instead
+ |
+LL - if !is_x86_feature_detected!("ssse3") {
+LL -
+LL - panic!("SSSE3 is not supported");
+LL - }
+LL + assert!(is_x86_feature_detected!("ssse3"), "SSSE3 is not supported");
+ |
+
+error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
index 8cedf2c..221cddf 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
@@ -189,5 +189,23 @@
LL + const BAR: () = assert!(!(N == 0), );
|
-error: aborting due to 10 previous errors
+error: only a `panic!` in `if`-then statement
+ --> tests/ui/manual_assert.rs:116:5
+ |
+LL | / if !is_x86_feature_detected!("ssse3") {
+LL | |
+LL | | panic!("SSSE3 is not supported");
+LL | | }
+ | |_____^
+ |
+help: try instead
+ |
+LL - if !is_x86_feature_detected!("ssse3") {
+LL -
+LL - panic!("SSSE3 is not supported");
+LL - }
+LL + assert!(is_x86_feature_detected!("ssse3"), "SSSE3 is not supported");
+ |
+
+error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_assert.rs b/src/tools/clippy/tests/ui/manual_assert.rs
index 46a42c3..ab02bd5 100644
--- a/src/tools/clippy/tests/ui/manual_assert.rs
+++ b/src/tools/clippy/tests/ui/manual_assert.rs
@@ -105,3 +105,17 @@ impl<T, const N: usize> Foo<T, N> {
};
}
}
+
+fn issue15227(left: u64, right: u64) -> u64 {
+ macro_rules! is_x86_feature_detected {
+ ($feature:literal) => {
+ $feature.len() > 0 && $feature.starts_with("ss")
+ };
+ }
+
+ if !is_x86_feature_detected!("ssse3") {
+ //~^ manual_assert
+ panic!("SSSE3 is not supported");
+ }
+ unsafe { todo!() }
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed b/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed
index 6735b99..03f75e7 100644
--- a/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed
+++ b/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed
@@ -23,3 +23,81 @@
fn g(a: u64, b: u64) {
let _ = a % b == 0;
}
+
+fn needs_deref(a: &u64, b: &u64) {
+ let _ = a.is_multiple_of(*b); //~ manual_is_multiple_of
+}
+
+fn closures(a: u64, b: u64) {
+ // Do not lint, types are ambiguous at this point
+ let cl = |a, b| a % b == 0;
+ let _ = cl(a, b);
+
+ // Do not lint, types are ambiguous at this point
+ let cl = |a: _, b: _| a % b == 0;
+ let _ = cl(a, b);
+
+ // Type of `a` is enough
+ let cl = |a: u64, b| a.is_multiple_of(b); //~ manual_is_multiple_of
+ let _ = cl(a, b);
+
+ // Type of `a` is enough
+ let cl = |a: &u64, b| a.is_multiple_of(b); //~ manual_is_multiple_of
+ let _ = cl(&a, b);
+
+ // Type of `b` is not enough
+ let cl = |a, b: u64| a % b == 0;
+ let _ = cl(&a, b);
+}
+
+fn any_rem<T: std::ops::Rem<Output = u32>>(a: T, b: T) {
+ // An arbitrary `Rem` implementation should not lint
+ let _ = a % b == 0;
+}
+
+mod issue15103 {
+ fn foo() -> Option<u64> {
+ let mut n: u64 = 150_000_000;
+
+ (2..).find(|p| {
+ while n.is_multiple_of(*p) {
+ //~^ manual_is_multiple_of
+ n /= p;
+ }
+ n <= 1
+ })
+ }
+
+ const fn generate_primes<const N: usize>() -> [u64; N] {
+ let mut result = [0; N];
+ if N == 0 {
+ return result;
+ }
+ result[0] = 2;
+ if N == 1 {
+ return result;
+ }
+ let mut idx = 1;
+ let mut p = 3;
+ while idx < N {
+ let mut j = 0;
+ while j < idx && p % result[j] != 0 {
+ j += 1;
+ }
+ if j == idx {
+ result[idx] = p;
+ idx += 1;
+ }
+ p += 1;
+ }
+ result
+ }
+
+ fn bar() -> u32 {
+ let d = |n: u32| -> u32 { (1..=n / 2).filter(|i| n.is_multiple_of(*i)).sum() };
+ //~^ manual_is_multiple_of
+
+ let d = |n| (1..=n / 2).filter(|i| n % i == 0).sum();
+ (1..1_000).filter(|&i| i == d(d(i)) && i != d(i)).sum()
+ }
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_multiple_of.rs b/src/tools/clippy/tests/ui/manual_is_multiple_of.rs
index 00b638e..7b6fa64 100644
--- a/src/tools/clippy/tests/ui/manual_is_multiple_of.rs
+++ b/src/tools/clippy/tests/ui/manual_is_multiple_of.rs
@@ -23,3 +23,81 @@ fn f(a: u64, b: u64) {
fn g(a: u64, b: u64) {
let _ = a % b == 0;
}
+
+fn needs_deref(a: &u64, b: &u64) {
+ let _ = a % b == 0; //~ manual_is_multiple_of
+}
+
+fn closures(a: u64, b: u64) {
+ // Do not lint, types are ambiguous at this point
+ let cl = |a, b| a % b == 0;
+ let _ = cl(a, b);
+
+ // Do not lint, types are ambiguous at this point
+ let cl = |a: _, b: _| a % b == 0;
+ let _ = cl(a, b);
+
+ // Type of `a` is enough
+ let cl = |a: u64, b| a % b == 0; //~ manual_is_multiple_of
+ let _ = cl(a, b);
+
+ // Type of `a` is enough
+ let cl = |a: &u64, b| a % b == 0; //~ manual_is_multiple_of
+ let _ = cl(&a, b);
+
+ // Type of `b` is not enough
+ let cl = |a, b: u64| a % b == 0;
+ let _ = cl(&a, b);
+}
+
+fn any_rem<T: std::ops::Rem<Output = u32>>(a: T, b: T) {
+ // An arbitrary `Rem` implementation should not lint
+ let _ = a % b == 0;
+}
+
+mod issue15103 {
+ fn foo() -> Option<u64> {
+ let mut n: u64 = 150_000_000;
+
+ (2..).find(|p| {
+ while n % p == 0 {
+ //~^ manual_is_multiple_of
+ n /= p;
+ }
+ n <= 1
+ })
+ }
+
+ const fn generate_primes<const N: usize>() -> [u64; N] {
+ let mut result = [0; N];
+ if N == 0 {
+ return result;
+ }
+ result[0] = 2;
+ if N == 1 {
+ return result;
+ }
+ let mut idx = 1;
+ let mut p = 3;
+ while idx < N {
+ let mut j = 0;
+ while j < idx && p % result[j] != 0 {
+ j += 1;
+ }
+ if j == idx {
+ result[idx] = p;
+ idx += 1;
+ }
+ p += 1;
+ }
+ result
+ }
+
+ fn bar() -> u32 {
+ let d = |n: u32| -> u32 { (1..=n / 2).filter(|i| n % i == 0).sum() };
+ //~^ manual_is_multiple_of
+
+ let d = |n| (1..=n / 2).filter(|i| n % i == 0).sum();
+ (1..1_000).filter(|&i| i == d(d(i)) && i != d(i)).sum()
+ }
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr b/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr
index 0b1ae70..8523599 100644
--- a/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr
+++ b/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr
@@ -37,5 +37,35 @@
LL | let _ = 0 < a % b;
| ^^^^^^^^^ help: replace with: `!a.is_multiple_of(b)`
-error: aborting due to 6 previous errors
+error: manual implementation of `.is_multiple_of()`
+ --> tests/ui/manual_is_multiple_of.rs:28:13
+ |
+LL | let _ = a % b == 0;
+ | ^^^^^^^^^^ help: replace with: `a.is_multiple_of(*b)`
+
+error: manual implementation of `.is_multiple_of()`
+ --> tests/ui/manual_is_multiple_of.rs:41:26
+ |
+LL | let cl = |a: u64, b| a % b == 0;
+ | ^^^^^^^^^^ help: replace with: `a.is_multiple_of(b)`
+
+error: manual implementation of `.is_multiple_of()`
+ --> tests/ui/manual_is_multiple_of.rs:45:27
+ |
+LL | let cl = |a: &u64, b| a % b == 0;
+ | ^^^^^^^^^^ help: replace with: `a.is_multiple_of(b)`
+
+error: manual implementation of `.is_multiple_of()`
+ --> tests/ui/manual_is_multiple_of.rs:63:19
+ |
+LL | while n % p == 0 {
+ | ^^^^^^^^^^ help: replace with: `n.is_multiple_of(*p)`
+
+error: manual implementation of `.is_multiple_of()`
+ --> tests/ui/manual_is_multiple_of.rs:97:58
+ |
+LL | let d = |n: u32| -> u32 { (1..=n / 2).filter(|i| n % i == 0).sum() };
+ | ^^^^^^^^^^ help: replace with: `n.is_multiple_of(*i)`
+
+error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/map_identity.fixed b/src/tools/clippy/tests/ui/map_identity.fixed
index 83b2dac..b82d3e6 100644
--- a/src/tools/clippy/tests/ui/map_identity.fixed
+++ b/src/tools/clippy/tests/ui/map_identity.fixed
@@ -87,3 +87,15 @@
let _ = { it }.next();
//~^ map_identity
}
+
+// same as `issue11764`, but for arrays
+fn issue15198() {
+ let x = [[1, 2], [3, 4]];
+ // don't lint: `&[i32; 2]` becomes `[&i32; 2]`
+ let _ = x.iter().map(|[x, y]| [x, y]);
+ let _ = x.iter().map(|x| [x[0]]).map(|[x]| x);
+
+ // no match ergonomics for `[i32, i32]`
+ let _ = x.iter().copied();
+ //~^ map_identity
+}
diff --git a/src/tools/clippy/tests/ui/map_identity.rs b/src/tools/clippy/tests/ui/map_identity.rs
index e839c55..c295bf8 100644
--- a/src/tools/clippy/tests/ui/map_identity.rs
+++ b/src/tools/clippy/tests/ui/map_identity.rs
@@ -93,3 +93,15 @@ fn issue13904() {
let _ = { it }.map(|x| x).next();
//~^ map_identity
}
+
+// same as `issue11764`, but for arrays
+fn issue15198() {
+ let x = [[1, 2], [3, 4]];
+ // don't lint: `&[i32; 2]` becomes `[&i32; 2]`
+ let _ = x.iter().map(|[x, y]| [x, y]);
+ let _ = x.iter().map(|x| [x[0]]).map(|[x]| x);
+
+ // no match ergonomics for `[i32, i32]`
+ let _ = x.iter().copied().map(|[x, y]| [x, y]);
+ //~^ map_identity
+}
diff --git a/src/tools/clippy/tests/ui/map_identity.stderr b/src/tools/clippy/tests/ui/map_identity.stderr
index 9836f3b..9b624a0 100644
--- a/src/tools/clippy/tests/ui/map_identity.stderr
+++ b/src/tools/clippy/tests/ui/map_identity.stderr
@@ -87,5 +87,11 @@
LL | let _ = { it }.map(|x| x).next();
| ^^^^^^^^^^^ help: remove the call to `map`
-error: aborting due to 13 previous errors
+error: unnecessary map of the identity function
+ --> tests/ui/map_identity.rs:105:30
+ |
+LL | let _ = x.iter().copied().map(|[x, y]| [x, y]);
+ | ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
+
+error: aborting due to 14 previous errors
diff --git a/src/tools/clippy/tests/ui/missing_inline.rs b/src/tools/clippy/tests/ui/missing_inline.rs
index c180100..223c744 100644
--- a/src/tools/clippy/tests/ui/missing_inline.rs
+++ b/src/tools/clippy/tests/ui/missing_inline.rs
@@ -80,3 +80,20 @@ pub fn PubFooImpl() {}
// do not lint this since users cannot control the external code
#[derive(Debug)]
pub struct S;
+
+pub mod issue15301 {
+ #[unsafe(no_mangle)]
+ pub extern "C" fn call_from_c() {
+ println!("Just called a Rust function from C!");
+ }
+
+ #[unsafe(no_mangle)]
+ pub extern "Rust" fn call_from_rust() {
+ println!("Just called a Rust function from Rust!");
+ }
+
+ #[unsafe(no_mangle)]
+ pub fn call_from_rust_no_extern() {
+ println!("Just called a Rust function from Rust!");
+ }
+}
diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.rs b/src/tools/clippy/tests/ui/module_name_repetitions.rs
index 2fde98d..5d16858 100644
--- a/src/tools/clippy/tests/ui/module_name_repetitions.rs
+++ b/src/tools/clippy/tests/ui/module_name_repetitions.rs
@@ -55,3 +55,21 @@ pub trait TryFromFoo {}
}
fn main() {}
+
+pub mod issue14095 {
+ pub mod widget {
+ #[macro_export]
+ macro_rules! define_widget {
+ ($id:ident) => {
+ /* ... */
+ };
+ }
+
+ #[macro_export]
+ macro_rules! widget_impl {
+ ($id:ident) => {
+ /* ... */
+ };
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed
index 4c1d6b1..1e8589c 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.fixed
+++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed
@@ -13,13 +13,15 @@
pub struct MyAtomic(AtomicBool);
pub struct MyPure;
-#[must_use] pub fn pure(i: u8) -> u8 {
+#[must_use]
+pub fn pure(i: u8) -> u8 {
//~^ must_use_candidate
i
}
impl MyPure {
- #[must_use] pub fn inherent_pure(&self) -> u8 {
+ #[must_use]
+ pub fn inherent_pure(&self) -> u8 {
//~^ must_use_candidate
0
}
@@ -51,7 +53,8 @@
f(0)
}
-#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
+#[must_use]
+pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
//~^ must_use_candidate
true
}
@@ -64,7 +67,8 @@
b.load(Ordering::SeqCst)
}
-#[must_use] pub fn rcd(_x: Rc<u32>) -> bool {
+#[must_use]
+pub fn rcd(_x: Rc<u32>) -> bool {
//~^ must_use_candidate
true
}
@@ -73,7 +77,8 @@
true
}
-#[must_use] pub fn arcd(_x: Arc<u32>) -> bool {
+#[must_use]
+pub fn arcd(_x: Arc<u32>) -> bool {
//~^ must_use_candidate
false
}
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.stderr b/src/tools/clippy/tests/ui/must_use_candidates.stderr
index 590253d..5ddbd02 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.stderr
+++ b/src/tools/clippy/tests/ui/must_use_candidates.stderr
@@ -1,35 +1,64 @@
error: this function could have a `#[must_use]` attribute
- --> tests/ui/must_use_candidates.rs:16:1
+ --> tests/ui/must_use_candidates.rs:16:8
|
LL | pub fn pure(i: u8) -> u8 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8`
+ | ^^^^
|
= note: `-D clippy::must-use-candidate` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::must_use_candidate)]`
+help: add the attribute
+ |
+LL + #[must_use]
+LL | pub fn pure(i: u8) -> u8 {
+ |
error: this method could have a `#[must_use]` attribute
- --> tests/ui/must_use_candidates.rs:22:5
+ --> tests/ui/must_use_candidates.rs:22:12
|
LL | pub fn inherent_pure(&self) -> u8 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn inherent_pure(&self) -> u8`
+ | ^^^^^^^^^^^^^
+ |
+help: add the attribute
+ |
+LL ~ #[must_use]
+LL ~ pub fn inherent_pure(&self) -> u8 {
+ |
error: this function could have a `#[must_use]` attribute
- --> tests/ui/must_use_candidates.rs:54:1
+ --> tests/ui/must_use_candidates.rs:54:8
|
LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool`
+ | ^^^^^^^^^^^
+ |
+help: add the attribute
+ |
+LL + #[must_use]
+LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
+ |
error: this function could have a `#[must_use]` attribute
- --> tests/ui/must_use_candidates.rs:67:1
+ --> tests/ui/must_use_candidates.rs:67:8
|
LL | pub fn rcd(_x: Rc<u32>) -> bool {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn rcd(_x: Rc<u32>) -> bool`
+ | ^^^
+ |
+help: add the attribute
+ |
+LL + #[must_use]
+LL | pub fn rcd(_x: Rc<u32>) -> bool {
+ |
error: this function could have a `#[must_use]` attribute
- --> tests/ui/must_use_candidates.rs:76:1
+ --> tests/ui/must_use_candidates.rs:76:8
|
LL | pub fn arcd(_x: Arc<u32>) -> bool {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc<u32>) -> bool`
+ | ^^^^
+ |
+help: add the attribute
+ |
+LL + #[must_use]
+LL | pub fn arcd(_x: Arc<u32>) -> bool {
+ |
error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
index a73aff5..a6d64d9 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
@@ -143,3 +143,9 @@
//~^ needless_for_each
}
}
+
+fn issue15256() {
+ let vec: Vec<i32> = Vec::new();
+ for v in vec.iter() { println!("{v}"); }
+ //~^ needless_for_each
+}
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
index d92f055..7e74d2b 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
@@ -143,3 +143,9 @@ fn single_expr(rows: &[u8]) {
//~^ needless_for_each
}
}
+
+fn issue15256() {
+ let vec: Vec<i32> = Vec::new();
+ vec.iter().for_each(|v| println!("{v}"));
+ //~^ needless_for_each
+}
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr
index f801445..204cfa3 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr
@@ -148,5 +148,11 @@
LL | rows.iter().for_each(|x| do_something(x, 1u8));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in rows.iter() { do_something(x, 1u8); }`
-error: aborting due to 10 previous errors
+error: needless use of `for_each`
+ --> tests/ui/needless_for_each_fixable.rs:149:5
+ |
+LL | vec.iter().for_each(|v| println!("{v}"));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for v in vec.iter() { println!("{v}"); }`
+
+error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/needless_range_loop.rs b/src/tools/clippy/tests/ui/needless_range_loop.rs
index 8a1c1be..70cf9fa 100644
--- a/src/tools/clippy/tests/ui/needless_range_loop.rs
+++ b/src/tools/clippy/tests/ui/needless_range_loop.rs
@@ -185,3 +185,28 @@ pub fn test<H: Handle>() -> H {
unimplemented!()
}
}
+
+fn needless_loop() {
+ use std::hint::black_box;
+ let x = [0; 64];
+ for i in 0..64 {
+ let y = [0; 64];
+
+ black_box(x[i]);
+ black_box(y[i]);
+ }
+
+ for i in 0..64 {
+ black_box(x[i]);
+ black_box([0; 64][i]);
+ }
+
+ for i in 0..64 {
+ black_box(x[i]);
+ black_box([1, 2, 3, 4, 5, 6, 7, 8][i]);
+ }
+
+ for i in 0..64 {
+ black_box([1, 2, 3, 4, 5, 6, 7, 8][i]);
+ }
+}
diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs
index e0f54ef..48d4b8a 100644
--- a/src/tools/clippy/tests/ui/never_loop.rs
+++ b/src/tools/clippy/tests/ui/never_loop.rs
@@ -466,3 +466,35 @@ fn main() {
test13();
test14();
}
+
+fn issue15059() {
+ 'a: for _ in 0..1 {
+ //~^ never_loop
+ break 'a;
+ }
+
+ let mut b = 1;
+ 'a: for i in 0..1 {
+ //~^ never_loop
+ match i {
+ 0 => {
+ b *= 2;
+ break 'a;
+ },
+ x => {
+ b += x;
+ break 'a;
+ },
+ }
+ }
+
+ #[allow(clippy::unused_unit)]
+ for v in 0..10 {
+ //~^ never_loop
+ break;
+ println!("{v}");
+ // This is comment and should be kept
+ println!("This is a comment");
+ ()
+ }
+}
diff --git a/src/tools/clippy/tests/ui/never_loop.stderr b/src/tools/clippy/tests/ui/never_loop.stderr
index bc9a7ec..54b4632 100644
--- a/src/tools/clippy/tests/ui/never_loop.stderr
+++ b/src/tools/clippy/tests/ui/never_loop.stderr
@@ -176,8 +176,10 @@
|
help: if you need the first element of the iterator, try writing
|
-LL - for v in 0..10 {
-LL + if let Some(v) = (0..10).next() {
+LL ~ if let Some(v) = (0..10).next() {
+LL |
+LL ~
+LL ~
|
error: this loop never actually loops
@@ -232,5 +234,68 @@
LL | | }
| |_________^
-error: aborting due to 21 previous errors
+error: this loop never actually loops
+ --> tests/ui/never_loop.rs:471:5
+ |
+LL | / 'a: for _ in 0..1 {
+LL | |
+LL | | break 'a;
+LL | | }
+ | |_____^
+ |
+help: if you need the first element of the iterator, try writing
+ |
+LL ~ if let Some(_) = (0..1).next() {
+LL |
+LL ~
+ |
+
+error: this loop never actually loops
+ --> tests/ui/never_loop.rs:477:5
+ |
+LL | / 'a: for i in 0..1 {
+LL | |
+LL | | match i {
+LL | | 0 => {
+... |
+LL | | }
+ | |_____^
+ |
+help: if you need the first element of the iterator, try writing
+ |
+LL ~ if let Some(i) = (0..1).next() {
+LL |
+...
+LL | b *= 2;
+LL ~
+LL | },
+LL | x => {
+LL | b += x;
+LL ~
+ |
+
+error: this loop never actually loops
+ --> tests/ui/never_loop.rs:492:5
+ |
+LL | / for v in 0..10 {
+LL | |
+LL | | break;
+LL | | println!("{v}");
+... |
+LL | | ()
+LL | | }
+ | |_____^
+ |
+help: if you need the first element of the iterator, try writing
+ |
+LL ~ if let Some(v) = (0..10).next() {
+LL |
+LL ~
+LL ~
+LL | // This is comment and should be kept
+LL ~
+LL ~
+ |
+
+error: aborting due to 24 previous errors
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index bcd2602..0a8525a 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -283,6 +283,8 @@
let _ = Some(4).map_or_else(g, f);
//~^ or_fun_call
let _ = Some(4).map_or(0, f);
+ let _ = Some(4).map_or_else(|| "asd".to_string().len() as i32, f);
+ //~^ or_fun_call
}
}
@@ -426,6 +428,8 @@
let _ = x.map_or_else(|_| g(), f);
//~^ or_fun_call
let _ = x.map_or(0, f);
+ let _ = x.map_or_else(|_| "asd".to_string().len() as i32, f);
+ //~^ or_fun_call
}
}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index 8d1202e..b4f9b95 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -283,6 +283,8 @@ fn test_map_or() {
let _ = Some(4).map_or(g(), f);
//~^ or_fun_call
let _ = Some(4).map_or(0, f);
+ let _ = Some(4).map_or("asd".to_string().len() as i32, f);
+ //~^ or_fun_call
}
}
@@ -426,6 +428,8 @@ fn test_map_or() {
let _ = x.map_or(g(), f);
//~^ or_fun_call
let _ = x.map_or(0, f);
+ let _ = x.map_or("asd".to_string().len() as i32, f);
+ //~^ or_fun_call
}
}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 585ee2d..3e4df77 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -154,62 +154,68 @@
LL | let _ = Some(4).map_or(g(), f);
| ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)`
+error: function call inside of `map_or`
+ --> tests/ui/or_fun_call.rs:286:25
+ |
+LL | let _ = Some(4).map_or("asd".to_string().len() as i32, f);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| "asd".to_string().len() as i32, f)`
+
error: use of `unwrap_or_else` to construct default value
- --> tests/ui/or_fun_call.rs:315:18
+ --> tests/ui/or_fun_call.rs:317: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:319:28
+ --> tests/ui/or_fun_call.rs:321: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:323:27
+ --> tests/ui/or_fun_call.rs:325: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:327:22
+ --> tests/ui/or_fun_call.rs:329: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:331:23
+ --> tests/ui/or_fun_call.rs:333: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:335:25
+ --> tests/ui/or_fun_call.rs:337: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:339:25
+ --> tests/ui/or_fun_call.rs:341: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:381:17
+ --> tests/ui/or_fun_call.rs:383: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:386:17
+ --> tests/ui/or_fun_call.rs:388: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:391:17
+ --> tests/ui/or_fun_call.rs:393:17
|
LL | let _ = opt.unwrap_or({
| _________________^
@@ -229,52 +235,58 @@
|
error: function call inside of `map_or`
- --> tests/ui/or_fun_call.rs:397:17
+ --> tests/ui/or_fun_call.rs:399: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:402:17
+ --> tests/ui/or_fun_call.rs:404: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:409:21
+ --> tests/ui/or_fun_call.rs:411:21
|
LL | let _ = opt_foo.unwrap_or(Foo { val: String::default() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })`
error: function call inside of `map_or`
- --> tests/ui/or_fun_call.rs:424:19
+ --> tests/ui/or_fun_call.rs:426:19
|
LL | let _ = x.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:426:19
+ --> tests/ui/or_fun_call.rs:428:19
|
LL | let _ = x.map_or(g(), f);
| ^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), f)`
+error: function call inside of `map_or`
+ --> tests/ui/or_fun_call.rs:431:19
+ |
+LL | let _ = x.map_or("asd".to_string().len() as i32, f);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| "asd".to_string().len() as i32, f)`
+
error: function call inside of `get_or_insert`
- --> tests/ui/or_fun_call.rs:438:15
+ --> tests/ui/or_fun_call.rs:442:15
|
LL | let _ = x.get_or_insert(g());
| ^^^^^^^^^^^^^^^^^^ help: try: `get_or_insert_with(g)`
error: function call inside of `and`
- --> tests/ui/or_fun_call.rs:448:15
+ --> tests/ui/or_fun_call.rs:452:15
|
LL | let _ = x.and(g());
| ^^^^^^^^ help: try: `and_then(|_| g())`
error: function call inside of `and`
- --> tests/ui/or_fun_call.rs:458:15
+ --> tests/ui/or_fun_call.rs:462:15
|
LL | let _ = x.and(g());
| ^^^^^^^^ help: try: `and_then(|_| g())`
-error: aborting due to 43 previous errors
+error: aborting due to 45 previous errors
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/auxiliary/external.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/auxiliary/external.rs
new file mode 100644
index 0000000..cd27c5c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/auxiliary/external.rs
@@ -0,0 +1,13 @@
+//! **FAKE** external macro crate.
+
+#[macro_export]
+macro_rules! macro_with_match {
+ ( $p:pat ) => {
+ let something = ();
+
+ match &something {
+ $p => true,
+ _ => false,
+ }
+ };
+}
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 49ea1d3..aa988a5 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs
@@ -6,6 +6,9 @@
clippy::single_match
)]
+//@aux-build:external.rs
+use external::macro_with_match;
+
fn main() {}
fn syntax_match() {
@@ -159,3 +162,9 @@ macro_rules! matching_macro {
let value = &Some(23);
matching_macro!(value);
}
+
+fn external_macro_expansion() {
+ macro_with_match! {
+ ()
+ };
+}
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 cd604d6..636841e 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:16:9
+ --> tests/ui/pattern_type_mismatch/syntax.rs:19: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:36:12
+ --> tests/ui/pattern_type_mismatch/syntax.rs:39: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:48:15
+ --> tests/ui/pattern_type_mismatch/syntax.rs:51: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:68:9
+ --> tests/ui/pattern_type_mismatch/syntax.rs:71: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:79:9
+ --> tests/ui/pattern_type_mismatch/syntax.rs:82: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:89:12
+ --> tests/ui/pattern_type_mismatch/syntax.rs:92: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:104:10
+ --> tests/ui/pattern_type_mismatch/syntax.rs:107: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:121:9
+ --> tests/ui/pattern_type_mismatch/syntax.rs:124: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:142:17
+ --> tests/ui/pattern_type_mismatch/syntax.rs:145:17
|
LL | Some(_) => (),
| ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index 578641e..be14e07 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -123,7 +123,7 @@ fn test_cow_with_ref(c: &Cow<[i32]>) {}
//~^ ptr_arg
fn test_cow(c: Cow<[i32]>) {
- let _c = c;
+ let d = c;
}
trait Foo2 {
@@ -141,36 +141,36 @@ mod issue_5644 {
use std::path::PathBuf;
fn allowed(
- #[allow(clippy::ptr_arg)] _v: &Vec<u32>,
- #[allow(clippy::ptr_arg)] _s: &String,
- #[allow(clippy::ptr_arg)] _p: &PathBuf,
- #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
- #[expect(clippy::ptr_arg)] _expect: &Cow<[i32]>,
+ #[allow(clippy::ptr_arg)] v: &Vec<u32>,
+ #[allow(clippy::ptr_arg)] s: &String,
+ #[allow(clippy::ptr_arg)] p: &PathBuf,
+ #[allow(clippy::ptr_arg)] c: &Cow<[i32]>,
+ #[expect(clippy::ptr_arg)] expect: &Cow<[i32]>,
) {
}
- fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec<u32>, _s: &String) {}
+ fn some_allowed(#[allow(clippy::ptr_arg)] v: &Vec<u32>, s: &String) {}
//~^ ptr_arg
struct S;
impl S {
fn allowed(
- #[allow(clippy::ptr_arg)] _v: &Vec<u32>,
- #[allow(clippy::ptr_arg)] _s: &String,
- #[allow(clippy::ptr_arg)] _p: &PathBuf,
- #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
- #[expect(clippy::ptr_arg)] _expect: &Cow<[i32]>,
+ #[allow(clippy::ptr_arg)] v: &Vec<u32>,
+ #[allow(clippy::ptr_arg)] s: &String,
+ #[allow(clippy::ptr_arg)] p: &PathBuf,
+ #[allow(clippy::ptr_arg)] c: &Cow<[i32]>,
+ #[expect(clippy::ptr_arg)] expect: &Cow<[i32]>,
) {
}
}
trait T {
fn allowed(
- #[allow(clippy::ptr_arg)] _v: &Vec<u32>,
- #[allow(clippy::ptr_arg)] _s: &String,
- #[allow(clippy::ptr_arg)] _p: &PathBuf,
- #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
- #[expect(clippy::ptr_arg)] _expect: &Cow<[i32]>,
+ #[allow(clippy::ptr_arg)] v: &Vec<u32>,
+ #[allow(clippy::ptr_arg)] s: &String,
+ #[allow(clippy::ptr_arg)] p: &PathBuf,
+ #[allow(clippy::ptr_arg)] c: &Cow<[i32]>,
+ #[expect(clippy::ptr_arg)] expect: &Cow<[i32]>,
) {
}
}
@@ -182,22 +182,22 @@ mod issue6509 {
fn foo_vec(vec: &Vec<u8>) {
//~^ ptr_arg
- let _ = vec.clone().pop();
- let _ = vec.clone().clone();
+ let a = vec.clone().pop();
+ let b = vec.clone().clone();
}
fn foo_path(path: &PathBuf) {
//~^ ptr_arg
- let _ = path.clone().pop();
- let _ = path.clone().clone();
+ let c = path.clone().pop();
+ let d = path.clone().clone();
}
- fn foo_str(str: &PathBuf) {
+ fn foo_str(str: &String) {
//~^ ptr_arg
- let _ = str.clone().pop();
- let _ = str.clone().clone();
+ let e = str.clone().pop();
+ let f = str.clone().clone();
}
}
@@ -340,8 +340,8 @@ fn repro2(source: &str, destination: &mut String) {
ToOwned::clone_into(source, destination);
}
- fn h1(_: &<String as Deref>::Target) {}
- fn h2<T: Deref>(_: T, _: &T::Target) {}
+ fn h1(x: &<String as Deref>::Target) {}
+ fn h2<T: Deref>(x: T, y: &T::Target) {}
// Other cases that are still ok to lint and ideally shouldn't regress
fn good(v1: &String, v2: &String) {
@@ -352,3 +352,91 @@ fn good(v1: &String, v2: &String) {
h2(String::new(), v2);
}
}
+
+mod issue_13489_and_13728 {
+ // This is a no-lint from now on.
+ fn foo(_x: &Vec<i32>) {
+ todo!();
+ }
+
+ // But this still gives us a lint.
+ fn foo_used(x: &Vec<i32>) {
+ //~^ ptr_arg
+
+ todo!();
+ }
+
+ // This is also a no-lint from now on.
+ fn foo_local(x: &Vec<i32>) {
+ let _y = x;
+
+ todo!();
+ }
+
+ // But this still gives us a lint.
+ fn foo_local_used(x: &Vec<i32>) {
+ //~^ ptr_arg
+
+ let y = x;
+
+ todo!();
+ }
+
+ // This only lints once from now on.
+ fn foofoo(_x: &Vec<i32>, y: &String) {
+ //~^ ptr_arg
+
+ todo!();
+ }
+
+ // And this is also a no-lint from now on.
+ fn foofoo_local(_x: &Vec<i32>, y: &String) {
+ let _z = y;
+
+ todo!();
+ }
+}
+
+mod issue_13489_and_13728_mut {
+ // This is a no-lint from now on.
+ fn bar(_x: &mut Vec<u32>) {
+ todo!()
+ }
+
+ // But this still gives us a lint.
+ fn bar_used(x: &mut Vec<u32>) {
+ //~^ ptr_arg
+
+ todo!()
+ }
+
+ // This is also a no-lint from now on.
+ fn bar_local(x: &mut Vec<u32>) {
+ let _y = x;
+
+ todo!()
+ }
+
+ // But this still gives us a lint.
+ fn bar_local_used(x: &mut Vec<u32>) {
+ //~^ ptr_arg
+
+ let y = x;
+
+ todo!()
+ }
+
+ // This only lints once from now on.
+ fn barbar(_x: &mut Vec<u32>, y: &mut String) {
+ //~^ ptr_arg
+
+ todo!()
+ }
+
+ // And this is also a no-lint from now on.
+ fn barbar_local(_x: &mut Vec<u32>, y: &mut String) {
+ let _z = y;
+
+ todo!()
+ }
+}
diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr
index fd9cedd..8723505 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.stderr
+++ b/src/tools/clippy/tests/ui/ptr_arg.stderr
@@ -127,10 +127,10 @@
| ^^^^^^^^^^^ help: change this to: `&[i32]`
error: writing `&String` instead of `&str` involves a new object where a slice will do
- --> tests/ui/ptr_arg.rs:152:66
+ --> tests/ui/ptr_arg.rs:152:64
|
-LL | fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec<u32>, _s: &String) {}
- | ^^^^^^^ help: change this to: `&str`
+LL | fn some_allowed(#[allow(clippy::ptr_arg)] v: &Vec<u32>, s: &String) {}
+ | ^^^^^^^ help: change this to: `&str`
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
--> tests/ui/ptr_arg.rs:182:21
@@ -143,8 +143,8 @@
LL ~ fn foo_vec(vec: &[u8]) {
LL |
LL |
-LL ~ let _ = vec.to_owned().pop();
-LL ~ let _ = vec.to_owned().clone();
+LL ~ let a = vec.to_owned().pop();
+LL ~ let b = vec.to_owned().clone();
|
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
@@ -158,23 +158,23 @@
LL ~ fn foo_path(path: &Path) {
LL |
LL |
-LL ~ let _ = path.to_path_buf().pop();
-LL ~ let _ = path.to_path_buf().clone();
+LL ~ let c = path.to_path_buf().pop();
+LL ~ let d = path.to_path_buf().clone();
|
-error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
+error: writing `&String` instead of `&str` involves a new object where a slice will do
--> tests/ui/ptr_arg.rs:196:21
|
-LL | fn foo_str(str: &PathBuf) {
- | ^^^^^^^^
+LL | fn foo_str(str: &String) {
+ | ^^^^^^^
|
help: change this to
|
-LL ~ fn foo_str(str: &Path) {
+LL ~ fn foo_str(str: &str) {
LL |
LL |
-LL ~ let _ = str.to_path_buf().pop();
-LL ~ let _ = str.to_path_buf().clone();
+LL ~ let e = str.to_owned().pop();
+LL ~ let f = str.to_owned().clone();
|
error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
@@ -231,6 +231,42 @@
LL | fn good(v1: &String, v2: &String) {
| ^^^^^^^ help: change this to: `&str`
+error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
+ --> tests/ui/ptr_arg.rs:363:20
+ |
+LL | fn foo_used(x: &Vec<i32>) {
+ | ^^^^^^^^^ help: change this to: `&[i32]`
+
+error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
+ --> tests/ui/ptr_arg.rs:377:26
+ |
+LL | fn foo_local_used(x: &Vec<i32>) {
+ | ^^^^^^^^^ help: change this to: `&[i32]`
+
+error: writing `&String` instead of `&str` involves a new object where a slice will do
+ --> tests/ui/ptr_arg.rs:386:33
+ |
+LL | fn foofoo(_x: &Vec<i32>, y: &String) {
+ | ^^^^^^^ help: change this to: `&str`
+
+error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
+ --> tests/ui/ptr_arg.rs:407:20
+ |
+LL | fn bar_used(x: &mut Vec<u32>) {
+ | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
+
+error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
+ --> tests/ui/ptr_arg.rs:421:26
+ |
+LL | fn bar_local_used(x: &mut Vec<u32>) {
+ | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
+
+error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do
+ --> tests/ui/ptr_arg.rs:430:37
+ |
+LL | fn barbar(_x: &mut Vec<u32>, y: &mut String) {
+ | ^^^^^^^^^^^ help: change this to: `&mut str`
+
error: eliding a lifetime that's named elsewhere is confusing
--> tests/ui/ptr_arg.rs:314:36
|
@@ -248,5 +284,5 @@
LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &'a str {
| ++
-error: aborting due to 27 previous errors
+error: aborting due to 33 previous errors
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
index 2033f31..71fea614 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
@@ -219,3 +219,11 @@
//~^ ptr_as_ptr
}
}
+
+#[allow(clippy::transmute_null_to_fn)]
+fn issue15283() {
+ unsafe {
+ let _: fn() = std::mem::transmute(std::ptr::null::<u8>());
+ //~^ ptr_as_ptr
+ }
+}
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs
index 224d09b..4d50759 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.rs
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs
@@ -219,3 +219,11 @@ fn full_core_path() -> *const u32 {
//~^ ptr_as_ptr
}
}
+
+#[allow(clippy::transmute_null_to_fn)]
+fn issue15283() {
+ unsafe {
+ let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const u8);
+ //~^ ptr_as_ptr
+ }
+}
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
index 66dae8e..adad159 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
@@ -201,5 +201,11 @@
LL | core::ptr::null() as _
| ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()`
-error: aborting due to 33 previous errors
+error: `as` casting between raw pointers without changing their constness
+ --> tests/ui/ptr_as_ptr.rs:226:43
+ |
+LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const u8);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u8>()`
+
+error: aborting due to 34 previous errors
diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.fixed b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed
index ee716ef..5c6da6d 100644
--- a/src/tools/clippy/tests/ui/range_plus_minus_one.fixed
+++ b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed
@@ -1,5 +1,9 @@
+#![warn(clippy::range_minus_one, clippy::range_plus_one)]
#![allow(unused_parens)]
#![allow(clippy::iter_with_drain)]
+
+use std::ops::{Index, IndexMut, Range, RangeBounds, RangeInclusive};
+
fn f() -> usize {
42
}
@@ -20,8 +24,6 @@
};
}
-#[warn(clippy::range_plus_one)]
-#[warn(clippy::range_minus_one)]
fn main() {
for _ in 0..2 {}
for _ in 0..=2 {}
@@ -45,15 +47,13 @@
//~^ range_plus_one
for _ in 0..=(1 + f()) {}
+ // Those are not linted, as in the general case we cannot be sure that the exact type won't be
+ // important.
let _ = ..11 - 1;
- let _ = ..11;
- //~^ range_minus_one
- let _ = ..11;
- //~^ range_minus_one
- let _ = (1..=11);
- //~^ range_plus_one
- let _ = ((f() + 1)..=f());
- //~^ range_plus_one
+ let _ = ..=11 - 1;
+ let _ = ..=(11 - 1);
+ let _ = (1..11 + 1);
+ let _ = (f() + 1)..(f() + 1);
const ONE: usize = 1;
// integer consts are linted, too
@@ -65,4 +65,118 @@
macro_plus_one!(5);
macro_minus_one!(5);
+
+ // As an instance of `Iterator`
+ (1..=10).for_each(|_| {});
+ //~^ range_plus_one
+
+ // As an instance of `IntoIterator`
+ #[allow(clippy::useless_conversion)]
+ (1..=10).into_iter().for_each(|_| {});
+ //~^ range_plus_one
+
+ // As an instance of `RangeBounds`
+ {
+ let _ = (1..=10).start_bound();
+ //~^ range_plus_one
+ }
+
+ // As a `SliceIndex`
+ let a = [10, 20, 30];
+ let _ = &a[1..=1];
+ //~^ range_plus_one
+
+ // As method call argument
+ vec.drain(2..=3);
+ //~^ range_plus_one
+
+ // As function call argument
+ take_arg(10..=20);
+ //~^ range_plus_one
+
+ // As function call argument inside a block
+ take_arg({ 10..=20 });
+ //~^ range_plus_one
+
+ // Do not lint in case types are unified
+ take_arg(if true { 10..20 } else { 10..20 + 1 });
+
+ // Do not lint, as the same type is used for both parameters
+ take_args(10..20 + 1, 10..21);
+
+ // Do not lint, as the range type is also used indirectly in second parameter
+ take_arg_and_struct(10..20 + 1, S { t: 1..2 });
+
+ // As target of `IndexMut`
+ let mut a = [10, 20, 30];
+ a[0..=2][0] = 1;
+ //~^ range_plus_one
+}
+
+fn take_arg<T: Iterator<Item = u32>>(_: T) {}
+fn take_args<T: Iterator<Item = u32>>(_: T, _: T) {}
+
+struct S<T> {
+ t: T,
+}
+fn take_arg_and_struct<T: Iterator<Item = u32>>(_: T, _: S<T>) {}
+
+fn no_index_by_range_inclusive(a: usize) {
+ struct S;
+
+ impl Index<Range<usize>> for S {
+ type Output = [u32];
+ fn index(&self, _: Range<usize>) -> &Self::Output {
+ &[]
+ }
+ }
+
+ _ = &S[0..a + 1];
+}
+
+fn no_index_mut_with_switched_range(a: usize) {
+ struct S(u32);
+
+ impl Index<Range<usize>> for S {
+ type Output = u32;
+ fn index(&self, _: Range<usize>) -> &Self::Output {
+ &self.0
+ }
+ }
+
+ impl IndexMut<Range<usize>> for S {
+ fn index_mut(&mut self, _: Range<usize>) -> &mut Self::Output {
+ &mut self.0
+ }
+ }
+
+ impl Index<RangeInclusive<usize>> for S {
+ type Output = u32;
+ fn index(&self, _: RangeInclusive<usize>) -> &Self::Output {
+ &self.0
+ }
+ }
+
+ S(2)[0..a + 1] = 3;
+}
+
+fn issue9908() {
+ // Simplified test case
+ let _ = || 0..=1;
+
+ // Original test case
+ let full_length = 1024;
+ let range = {
+ // do some stuff, omit here
+ None
+ };
+
+ let range = range.map(|(s, t)| s..=t).unwrap_or(0..=(full_length - 1));
+
+ assert_eq!(range, 0..=1023);
+}
+
+fn issue9908_2(n: usize) -> usize {
+ (1..n).sum()
+ //~^ range_minus_one
}
diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.rs b/src/tools/clippy/tests/ui/range_plus_minus_one.rs
index f2d5ae2..7172da6 100644
--- a/src/tools/clippy/tests/ui/range_plus_minus_one.rs
+++ b/src/tools/clippy/tests/ui/range_plus_minus_one.rs
@@ -1,5 +1,9 @@
+#![warn(clippy::range_minus_one, clippy::range_plus_one)]
#![allow(unused_parens)]
#![allow(clippy::iter_with_drain)]
+
+use std::ops::{Index, IndexMut, Range, RangeBounds, RangeInclusive};
+
fn f() -> usize {
42
}
@@ -20,8 +24,6 @@ macro_rules! macro_minus_one {
};
}
-#[warn(clippy::range_plus_one)]
-#[warn(clippy::range_minus_one)]
fn main() {
for _ in 0..2 {}
for _ in 0..=2 {}
@@ -45,15 +47,13 @@ fn main() {
//~^ range_plus_one
for _ in 0..=(1 + f()) {}
+ // Those are not linted, as in the general case we cannot be sure that the exact type won't be
+ // important.
let _ = ..11 - 1;
let _ = ..=11 - 1;
- //~^ range_minus_one
let _ = ..=(11 - 1);
- //~^ range_minus_one
let _ = (1..11 + 1);
- //~^ range_plus_one
let _ = (f() + 1)..(f() + 1);
- //~^ range_plus_one
const ONE: usize = 1;
// integer consts are linted, too
@@ -65,4 +65,118 @@ fn main() {
macro_plus_one!(5);
macro_minus_one!(5);
+
+ // As an instance of `Iterator`
+ (1..10 + 1).for_each(|_| {});
+ //~^ range_plus_one
+
+ // As an instance of `IntoIterator`
+ #[allow(clippy::useless_conversion)]
+ (1..10 + 1).into_iter().for_each(|_| {});
+ //~^ range_plus_one
+
+ // As an instance of `RangeBounds`
+ {
+ let _ = (1..10 + 1).start_bound();
+ //~^ range_plus_one
+ }
+
+ // As a `SliceIndex`
+ let a = [10, 20, 30];
+ let _ = &a[1..1 + 1];
+ //~^ range_plus_one
+
+ // As method call argument
+ vec.drain(2..3 + 1);
+ //~^ range_plus_one
+
+ // As function call argument
+ take_arg(10..20 + 1);
+ //~^ range_plus_one
+
+ // As function call argument inside a block
+ take_arg({ 10..20 + 1 });
+ //~^ range_plus_one
+
+ // Do not lint in case types are unified
+ take_arg(if true { 10..20 } else { 10..20 + 1 });
+
+ // Do not lint, as the same type is used for both parameters
+ take_args(10..20 + 1, 10..21);
+
+ // Do not lint, as the range type is also used indirectly in second parameter
+ take_arg_and_struct(10..20 + 1, S { t: 1..2 });
+
+ // As target of `IndexMut`
+ let mut a = [10, 20, 30];
+ a[0..2 + 1][0] = 1;
+ //~^ range_plus_one
+}
+
+fn take_arg<T: Iterator<Item = u32>>(_: T) {}
+fn take_args<T: Iterator<Item = u32>>(_: T, _: T) {}
+
+struct S<T> {
+ t: T,
+}
+fn take_arg_and_struct<T: Iterator<Item = u32>>(_: T, _: S<T>) {}
+
+fn no_index_by_range_inclusive(a: usize) {
+ struct S;
+
+ impl Index<Range<usize>> for S {
+ type Output = [u32];
+ fn index(&self, _: Range<usize>) -> &Self::Output {
+ &[]
+ }
+ }
+
+ _ = &S[0..a + 1];
+}
+
+fn no_index_mut_with_switched_range(a: usize) {
+ struct S(u32);
+
+ impl Index<Range<usize>> for S {
+ type Output = u32;
+ fn index(&self, _: Range<usize>) -> &Self::Output {
+ &self.0
+ }
+ }
+
+ impl IndexMut<Range<usize>> for S {
+ fn index_mut(&mut self, _: Range<usize>) -> &mut Self::Output {
+ &mut self.0
+ }
+ }
+
+ impl Index<RangeInclusive<usize>> for S {
+ type Output = u32;
+ fn index(&self, _: RangeInclusive<usize>) -> &Self::Output {
+ &self.0
+ }
+ }
+
+ S(2)[0..a + 1] = 3;
+}
+
+fn issue9908() {
+ // Simplified test case
+ let _ = || 0..=1;
+
+ // Original test case
+ let full_length = 1024;
+ let range = {
+ // do some stuff, omit here
+ None
+ };
+
+ let range = range.map(|(s, t)| s..=t).unwrap_or(0..=(full_length - 1));
+
+ assert_eq!(range, 0..=1023);
+}
+
+fn issue9908_2(n: usize) -> usize {
+ (1..=n - 1).sum()
+ //~^ range_minus_one
}
diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr
index 9b23a8b..a419d93 100644
--- a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr
+++ b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr
@@ -1,5 +1,5 @@
error: an inclusive range would be more readable
- --> tests/ui/range_plus_minus_one.rs:29:14
+ --> tests/ui/range_plus_minus_one.rs:31:14
|
LL | for _ in 0..3 + 1 {}
| ^^^^^^^^ help: use: `0..=3`
@@ -8,55 +8,85 @@
= help: to override `-D warnings` add `#[allow(clippy::range_plus_one)]`
error: an inclusive range would be more readable
- --> tests/ui/range_plus_minus_one.rs:33:14
+ --> tests/ui/range_plus_minus_one.rs:35:14
|
LL | for _ in 0..1 + 5 {}
| ^^^^^^^^ help: use: `0..=5`
error: an inclusive range would be more readable
- --> tests/ui/range_plus_minus_one.rs:37:14
+ --> tests/ui/range_plus_minus_one.rs:39:14
|
LL | for _ in 1..1 + 1 {}
| ^^^^^^^^ help: use: `1..=1`
error: an inclusive range would be more readable
- --> tests/ui/range_plus_minus_one.rs:44:14
+ --> tests/ui/range_plus_minus_one.rs:46:14
|
LL | for _ in 0..(1 + f()) {}
| ^^^^^^^^^^^^ help: use: `0..=f()`
-error: an exclusive range would be more readable
- --> tests/ui/range_plus_minus_one.rs:49:13
- |
-LL | let _ = ..=11 - 1;
- | ^^^^^^^^^ help: use: `..11`
- |
- = note: `-D clippy::range-minus-one` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::range_minus_one)]`
-
-error: an exclusive range would be more readable
- --> tests/ui/range_plus_minus_one.rs:51:13
- |
-LL | let _ = ..=(11 - 1);
- | ^^^^^^^^^^^ help: use: `..11`
-
-error: an inclusive range would be more readable
- --> tests/ui/range_plus_minus_one.rs:53:13
- |
-LL | let _ = (1..11 + 1);
- | ^^^^^^^^^^^ help: use: `(1..=11)`
-
-error: an inclusive range would be more readable
- --> tests/ui/range_plus_minus_one.rs:55:13
- |
-LL | let _ = (f() + 1)..(f() + 1);
- | ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())`
-
error: an inclusive range would be more readable
--> tests/ui/range_plus_minus_one.rs:60:14
|
LL | for _ in 1..ONE + ONE {}
| ^^^^^^^^^^^^ help: use: `1..=ONE`
-error: aborting due to 9 previous errors
+error: an inclusive range would be more readable
+ --> tests/ui/range_plus_minus_one.rs:70:5
+ |
+LL | (1..10 + 1).for_each(|_| {});
+ | ^^^^^^^^^^^ help: use: `(1..=10)`
+
+error: an inclusive range would be more readable
+ --> tests/ui/range_plus_minus_one.rs:75:5
+ |
+LL | (1..10 + 1).into_iter().for_each(|_| {});
+ | ^^^^^^^^^^^ help: use: `(1..=10)`
+
+error: an inclusive range would be more readable
+ --> tests/ui/range_plus_minus_one.rs:80:17
+ |
+LL | let _ = (1..10 + 1).start_bound();
+ | ^^^^^^^^^^^ help: use: `(1..=10)`
+
+error: an inclusive range would be more readable
+ --> tests/ui/range_plus_minus_one.rs:86:16
+ |
+LL | let _ = &a[1..1 + 1];
+ | ^^^^^^^^ help: use: `1..=1`
+
+error: an inclusive range would be more readable
+ --> tests/ui/range_plus_minus_one.rs:90:15
+ |
+LL | vec.drain(2..3 + 1);
+ | ^^^^^^^^ help: use: `2..=3`
+
+error: an inclusive range would be more readable
+ --> tests/ui/range_plus_minus_one.rs:94:14
+ |
+LL | take_arg(10..20 + 1);
+ | ^^^^^^^^^^ help: use: `10..=20`
+
+error: an inclusive range would be more readable
+ --> tests/ui/range_plus_minus_one.rs:98:16
+ |
+LL | take_arg({ 10..20 + 1 });
+ | ^^^^^^^^^^ help: use: `10..=20`
+
+error: an inclusive range would be more readable
+ --> tests/ui/range_plus_minus_one.rs:112:7
+ |
+LL | a[0..2 + 1][0] = 1;
+ | ^^^^^^^^ help: use: `0..=2`
+
+error: an exclusive range would be more readable
+ --> tests/ui/range_plus_minus_one.rs:180:5
+ |
+LL | (1..=n - 1).sum()
+ | ^^^^^^^^^^^ help: use: `(1..n)`
+ |
+ = note: `-D clippy::range-minus-one` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::range_minus_one)]`
+
+error: aborting due to 14 previous errors
diff --git a/src/tools/clippy/tests/ui/single_match_else_deref_patterns.fixed b/src/tools/clippy/tests/ui/single_match_else_deref_patterns.fixed
new file mode 100644
index 0000000..7a9f8063
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_match_else_deref_patterns.fixed
@@ -0,0 +1,53 @@
+#![feature(deref_patterns)]
+#![allow(
+ incomplete_features,
+ clippy::eq_op,
+ clippy::op_ref,
+ clippy::deref_addrof,
+ clippy::borrow_deref_ref,
+ clippy::needless_if
+)]
+#![deny(clippy::single_match_else)]
+
+fn string() {
+ if *"" == *"" {}
+
+ if *&*&*&*"" == *"" {}
+
+ if ***&&"" == *"" {}
+
+ if *&*&*"" == *"" {}
+
+ if **&&*"" == *"" {}
+}
+
+fn int() {
+ if &&&1 == &&&2 { unreachable!() } else {
+ // ok
+ }
+ //~^^^^^^ single_match_else
+ if &&1 == &&2 { unreachable!() } else {
+ // ok
+ }
+ //~^^^^^^ single_match_else
+ if &&1 == &&2 { unreachable!() } else {
+ // ok
+ }
+ //~^^^^^^ single_match_else
+ if &1 == &2 { unreachable!() } else {
+ // ok
+ }
+ //~^^^^^^ single_match_else
+ if &1 == &2 { unreachable!() } else {
+ // ok
+ }
+ //~^^^^^^ single_match_else
+ if 1 == 2 { unreachable!() } else {
+ // ok
+ }
+ //~^^^^^^ single_match_else
+ if 1 == 2 { unreachable!() } else {
+ // ok
+ }
+ //~^^^^^^ single_match_else
+}
diff --git a/src/tools/clippy/tests/ui/single_match_else_deref_patterns.rs b/src/tools/clippy/tests/ui/single_match_else_deref_patterns.rs
new file mode 100644
index 0000000..ef19c7c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_match_else_deref_patterns.rs
@@ -0,0 +1,94 @@
+#![feature(deref_patterns)]
+#![allow(
+ incomplete_features,
+ clippy::eq_op,
+ clippy::op_ref,
+ clippy::deref_addrof,
+ clippy::borrow_deref_ref,
+ clippy::needless_if
+)]
+#![deny(clippy::single_match_else)]
+
+fn string() {
+ match *"" {
+ //~^ single_match
+ "" => {},
+ _ => {},
+ }
+
+ match *&*&*&*"" {
+ //~^ single_match
+ "" => {},
+ _ => {},
+ }
+
+ match ***&&"" {
+ //~^ single_match
+ "" => {},
+ _ => {},
+ }
+
+ match *&*&*"" {
+ //~^ single_match
+ "" => {},
+ _ => {},
+ }
+
+ match **&&*"" {
+ //~^ single_match
+ "" => {},
+ _ => {},
+ }
+}
+
+fn int() {
+ match &&&1 {
+ &&&2 => unreachable!(),
+ _ => {
+ // ok
+ },
+ }
+ //~^^^^^^ single_match_else
+ match &&&1 {
+ &&2 => unreachable!(),
+ _ => {
+ // ok
+ },
+ }
+ //~^^^^^^ single_match_else
+ match &&1 {
+ &&2 => unreachable!(),
+ _ => {
+ // ok
+ },
+ }
+ //~^^^^^^ single_match_else
+ match &&&1 {
+ &2 => unreachable!(),
+ _ => {
+ // ok
+ },
+ }
+ //~^^^^^^ single_match_else
+ match &&1 {
+ &2 => unreachable!(),
+ _ => {
+ // ok
+ },
+ }
+ //~^^^^^^ single_match_else
+ match &&&1 {
+ 2 => unreachable!(),
+ _ => {
+ // ok
+ },
+ }
+ //~^^^^^^ single_match_else
+ match &&1 {
+ 2 => unreachable!(),
+ _ => {
+ // ok
+ },
+ }
+ //~^^^^^^ single_match_else
+}
diff --git a/src/tools/clippy/tests/ui/single_match_else_deref_patterns.stderr b/src/tools/clippy/tests/ui/single_match_else_deref_patterns.stderr
new file mode 100644
index 0000000..a47df55
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_match_else_deref_patterns.stderr
@@ -0,0 +1,188 @@
+error: you seem to be trying to use `match` for an equality check. Consider using `if`
+ --> tests/ui/single_match_else_deref_patterns.rs:13:5
+ |
+LL | / match *"" {
+LL | |
+LL | | "" => {},
+LL | | _ => {},
+LL | | }
+ | |_____^ help: try: `if *"" == *"" {}`
+ |
+ = note: you might want to preserve the comments from inside the `match`
+ = note: `-D clippy::single-match` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::single_match)]`
+
+error: you seem to be trying to use `match` for an equality check. Consider using `if`
+ --> tests/ui/single_match_else_deref_patterns.rs:19:5
+ |
+LL | / match *&*&*&*"" {
+LL | |
+LL | | "" => {},
+LL | | _ => {},
+LL | | }
+ | |_____^ help: try: `if *&*&*&*"" == *"" {}`
+ |
+ = note: you might want to preserve the comments from inside the `match`
+
+error: you seem to be trying to use `match` for an equality check. Consider using `if`
+ --> tests/ui/single_match_else_deref_patterns.rs:25:5
+ |
+LL | / match ***&&"" {
+LL | |
+LL | | "" => {},
+LL | | _ => {},
+LL | | }
+ | |_____^ help: try: `if ***&&"" == *"" {}`
+ |
+ = note: you might want to preserve the comments from inside the `match`
+
+error: you seem to be trying to use `match` for an equality check. Consider using `if`
+ --> tests/ui/single_match_else_deref_patterns.rs:31:5
+ |
+LL | / match *&*&*"" {
+LL | |
+LL | | "" => {},
+LL | | _ => {},
+LL | | }
+ | |_____^ help: try: `if *&*&*"" == *"" {}`
+ |
+ = note: you might want to preserve the comments from inside the `match`
+
+error: you seem to be trying to use `match` for an equality check. Consider using `if`
+ --> tests/ui/single_match_else_deref_patterns.rs:37:5
+ |
+LL | / match **&&*"" {
+LL | |
+LL | | "" => {},
+LL | | _ => {},
+LL | | }
+ | |_____^ help: try: `if **&&*"" == *"" {}`
+ |
+ = note: you might want to preserve the comments from inside the `match`
+
+error: you seem to be trying to use `match` for an equality check. Consider using `if`
+ --> tests/ui/single_match_else_deref_patterns.rs:45:5
+ |
+LL | / match &&&1 {
+LL | | &&&2 => unreachable!(),
+LL | | _ => {
+... |
+LL | | }
+ | |_____^
+ |
+note: the lint level is defined here
+ --> tests/ui/single_match_else_deref_patterns.rs:10:9
+ |
+LL | #![deny(clippy::single_match_else)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try
+ |
+LL ~ if &&&1 == &&&2 { unreachable!() } else {
+LL + // ok
+LL + }
+ |
+
+error: you seem to be trying to use `match` for an equality check. Consider using `if`
+ --> tests/ui/single_match_else_deref_patterns.rs:52:5
+ |
+LL | / match &&&1 {
+LL | | &&2 => unreachable!(),
+LL | | _ => {
+... |
+LL | | }
+ | |_____^
+ |
+help: try
+ |
+LL ~ if &&1 == &&2 { unreachable!() } else {
+LL + // ok
+LL + }
+ |
+
+error: you seem to be trying to use `match` for an equality check. Consider using `if`
+ --> tests/ui/single_match_else_deref_patterns.rs:59:5
+ |
+LL | / match &&1 {
+LL | | &&2 => unreachable!(),
+LL | | _ => {
+... |
+LL | | }
+ | |_____^
+ |
+help: try
+ |
+LL ~ if &&1 == &&2 { unreachable!() } else {
+LL + // ok
+LL + }
+ |
+
+error: you seem to be trying to use `match` for an equality check. Consider using `if`
+ --> tests/ui/single_match_else_deref_patterns.rs:66:5
+ |
+LL | / match &&&1 {
+LL | | &2 => unreachable!(),
+LL | | _ => {
+... |
+LL | | }
+ | |_____^
+ |
+help: try
+ |
+LL ~ if &1 == &2 { unreachable!() } else {
+LL + // ok
+LL + }
+ |
+
+error: you seem to be trying to use `match` for an equality check. Consider using `if`
+ --> tests/ui/single_match_else_deref_patterns.rs:73:5
+ |
+LL | / match &&1 {
+LL | | &2 => unreachable!(),
+LL | | _ => {
+... |
+LL | | }
+ | |_____^
+ |
+help: try
+ |
+LL ~ if &1 == &2 { unreachable!() } else {
+LL + // ok
+LL + }
+ |
+
+error: you seem to be trying to use `match` for an equality check. Consider using `if`
+ --> tests/ui/single_match_else_deref_patterns.rs:80:5
+ |
+LL | / match &&&1 {
+LL | | 2 => unreachable!(),
+LL | | _ => {
+... |
+LL | | }
+ | |_____^
+ |
+help: try
+ |
+LL ~ if 1 == 2 { unreachable!() } else {
+LL + // ok
+LL + }
+ |
+
+error: you seem to be trying to use `match` for an equality check. Consider using `if`
+ --> tests/ui/single_match_else_deref_patterns.rs:87:5
+ |
+LL | / match &&1 {
+LL | | 2 => unreachable!(),
+LL | | _ => {
+... |
+LL | | }
+ | |_____^
+ |
+help: try
+ |
+LL ~ if 1 == 2 { unreachable!() } else {
+LL + // ok
+LL + }
+ |
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs
index 14371bc..d0022f3 100644
--- a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs
+++ b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs
@@ -82,3 +82,32 @@ pub fn unsafe_block(&self) {
}
fn main() {}
+
+mod issue15120 {
+ macro_rules! uns {
+ ($e:expr) => {
+ unsafe { $e }
+ };
+ }
+
+ #[derive(serde::Deserialize)]
+ struct Foo;
+
+ impl Foo {
+ fn foo(&self) {
+ // Do not lint if `unsafe` comes from the `core::pin::pin!()` macro
+ std::pin::pin!(());
+ }
+ }
+
+ //~v unsafe_derive_deserialize
+ #[derive(serde::Deserialize)]
+ struct Bar;
+
+ impl Bar {
+ fn bar(&self) {
+ // Lint if `unsafe` comes from the another macro
+ _ = uns!(42);
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr
index f2d4429..4b5dd6e 100644
--- a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr
+++ b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr
@@ -36,5 +36,14 @@
= help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html
= note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 4 previous errors
+error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe`
+ --> tests/ui/unsafe_derive_deserialize.rs:104:14
+ |
+LL | #[derive(serde::Deserialize)]
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html
+ = note: this error originates in the derive macro `serde::Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs
index 4334592..7a0be82 100644
--- a/src/tools/clippy/tests/ui/unused_async.rs
+++ b/src/tools/clippy/tests/ui/unused_async.rs
@@ -127,3 +127,13 @@ trait Action {
async fn cancel(self: Arc<Self>) {}
}
}
+
+mod issue15305 {
+ async fn todo_task() -> Result<(), String> {
+ todo!("Implement task");
+ }
+
+ async fn unimplemented_task() -> Result<(), String> {
+ unimplemented!("Implement task");
+ }
+}
diff --git a/src/tools/clippy/tests/ui/unused_trait_names.fixed b/src/tools/clippy/tests/ui/unused_trait_names.fixed
index 17e32dd..6abbed0 100644
--- a/src/tools/clippy/tests/ui/unused_trait_names.fixed
+++ b/src/tools/clippy/tests/ui/unused_trait_names.fixed
@@ -200,11 +200,11 @@
MyStruct.do_things();
}
+// Linting inside macro expansion is no longer supported
mod lint_inside_macro_expansion_bad {
macro_rules! foo {
() => {
- use std::any::Any as _;
- //~^ unused_trait_names
+ use std::any::Any;
fn bar() {
"bar".type_id();
}
diff --git a/src/tools/clippy/tests/ui/unused_trait_names.rs b/src/tools/clippy/tests/ui/unused_trait_names.rs
index 3cf8597..4a06f06 100644
--- a/src/tools/clippy/tests/ui/unused_trait_names.rs
+++ b/src/tools/clippy/tests/ui/unused_trait_names.rs
@@ -200,11 +200,11 @@ fn msrv_1_33() {
MyStruct.do_things();
}
+// Linting inside macro expansion is no longer supported
mod lint_inside_macro_expansion_bad {
macro_rules! foo {
() => {
use std::any::Any;
- //~^ unused_trait_names
fn bar() {
"bar".type_id();
}
diff --git a/src/tools/clippy/tests/ui/unused_trait_names.stderr b/src/tools/clippy/tests/ui/unused_trait_names.stderr
index 3183289..28067e1 100644
--- a/src/tools/clippy/tests/ui/unused_trait_names.stderr
+++ b/src/tools/clippy/tests/ui/unused_trait_names.stderr
@@ -58,16 +58,5 @@
LL | use simple_trait::{MyStruct, MyTrait};
| ^^^^^^^ help: use: `MyTrait as _`
-error: importing trait that is only used anonymously
- --> tests/ui/unused_trait_names.rs:206:27
- |
-LL | use std::any::Any;
- | ^^^ help: use: `Any as _`
-...
-LL | foo!();
- | ------ in this macro invocation
- |
- = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 10 previous errors
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/used_underscore_items.rs b/src/tools/clippy/tests/ui/used_underscore_items.rs
index 7e8289f..aecdd32 100644
--- a/src/tools/clippy/tests/ui/used_underscore_items.rs
+++ b/src/tools/clippy/tests/ui/used_underscore_items.rs
@@ -62,13 +62,13 @@ fn main() {
//~^ used_underscore_items
}
-// should not lint exteranl crate.
+// should not lint external crate.
// user cannot control how others name their items
fn external_item_call() {
let foo_struct3 = external_item::_ExternalStruct {};
foo_struct3._foo();
- external_item::_exernal_foo();
+ external_item::_external_foo();
}
// should not lint foreign functions.
diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed
index 930bc1e..be4fb55 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.fixed
+++ b/src/tools/clippy/tests/ui/useless_attribute.fixed
@@ -146,3 +146,15 @@
#[allow(rustc::non_glob_import_of_type_ir_inherent)]
use some_module::SomeType;
}
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/15316
+pub mod redundant_imports_issue {
+ macro_rules! empty {
+ () => {};
+ }
+
+ #[expect(redundant_imports)]
+ pub(crate) use empty;
+
+ empty!();
+}
diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs
index 50fafd4..5a1bcf9 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.rs
+++ b/src/tools/clippy/tests/ui/useless_attribute.rs
@@ -146,3 +146,15 @@ pub mod some_module {
#[allow(rustc::non_glob_import_of_type_ir_inherent)]
use some_module::SomeType;
}
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/15316
+pub mod redundant_imports_issue {
+ macro_rules! empty {
+ () => {};
+ }
+
+ #[expect(redundant_imports)]
+ pub(crate) use empty;
+
+ empty!();
+}
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index 805baf2..a62b626 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -54,6 +54,7 @@
users_on_vacation = [
"matthiaskrgr",
"Manishearth",
+ "samueltardieu",
]
[assign.owners]
diff --git a/src/tools/clippy/util/gh-pages/index_template.html b/src/tools/clippy/util/gh-pages/index_template.html
index 6f380ec..5d65ea5 100644
--- a/src/tools/clippy/util/gh-pages/index_template.html
+++ b/src/tools/clippy/util/gh-pages/index_template.html
@@ -49,9 +49,7 @@
<script src="theme.js"></script> {# #}
<div class="container"> {# #}
- <div class="page-header"> {# #}
- <h1>Clippy Lints <span id="lint-count" class="badge"></span></h1> {# #}
- </div> {# #}
+ <h1 class="page-header">Clippy Lints <span id="lint-count" class="badge"></span></h1> {# #}
<noscript> {# #}
<div class="alert alert-danger" role="alert"> {# #}
@@ -59,143 +57,141 @@
</div> {# #}
</noscript> {# #}
- <div> {# #}
- <div class="panel panel-default" id="menu-filters"> {# #}
- <div class="panel-body row"> {# #}
- <div id="upper-filters" class="col-12 col-md-5"> {# #}
- <div class="btn-group" id="lint-levels" tabindex="-1"> {# #}
- <button type="button" class="btn btn-default dropdown-toggle"> {# #}
- Lint levels <span class="badge">4</span> <span class="caret"></span> {# #}
- </button> {# #}
- <ul class="dropdown-menu" id="lint-levels-selector"> {# #}
- <li class="checkbox"> {# #}
- <button onclick="toggleElements('levels_filter', true)">All</button> {# #}
- </li> {# #}
- <li class="checkbox"> {# #}
- <button onclick="toggleElements('levels_filter', false)">None</button> {# #}
- </li> {# #}
- <li role="separator" class="divider"></li> {# #}
- </ul> {# #}
- </div> {# #}
- <div class="btn-group" id="lint-groups" tabindex="-1"> {# #}
- <button type="button" class="btn btn-default dropdown-toggle"> {# #}
- Lint groups <span class="badge">9</span> <span class="caret"></span> {# #}
- </button> {# #}
- <ul class="dropdown-menu" id="lint-groups-selector"> {# #}
- <li class="checkbox"> {# #}
- <button onclick="toggleElements('groups_filter', true)">All</button> {# #}
- </li> {# #}
- <li class="checkbox"> {# #}
- <button onclick="resetGroupsToDefault()">Default</button> {# #}
- </li> {# #}
- <li class="checkbox"> {# #}
- <button onclick="toggleElements('groups_filter', false)">None</button> {# #}
- </li> {# #}
- <li role="separator" class="divider"></li> {# #}
- </ul> {# #}
- </div> {# #}
- <div class="btn-group" id="version-filter" tabindex="-1"> {# #}
- <button type="button" class="btn btn-default dropdown-toggle"> {# #}
- Version {#+ #}
- <span id="version-filter-count" class="badge">0</span> {#+ #}
- <span class="caret"></span> {# #}
- </button> {# #}
- <ul id="version-filter-selector" class="dropdown-menu"> {# #}
- <li class="checkbox"> {# #}
- <button onclick="clearVersionFilters()">Clear filters</button> {# #}
- </li> {# #}
- <li role="separator" class="divider"></li> {# #}
- </ul> {# #}
- </div> {# #}
- <div class="btn-group" id="lint-applicabilities" tabindex="-1"> {# #}
- <button type="button" class="btn btn-default dropdown-toggle"> {# #}
- Applicability {#+ #}
- <span class="badge">4</span> {#+ #}
- <span class="caret"></span> {# #}
- </button> {# #}
- <ul class="dropdown-menu" id="lint-applicabilities-selector"> {# #}
- <li class="checkbox"> {# #}
- <button onclick="toggleElements('applicabilities_filter', true)">All</button> {# #}
- </li> {# #}
- <li class="checkbox"> {# #}
- <button onclick="toggleElements('applicabilities_filter', false)">None</button> {# #}
- </li> {# #}
- <li role="separator" class="divider"></li> {# #}
- </ul> {# #}
- </div> {# #}
- </div> {# #}
- <div class="col-12 col-md-5 search-control"> {# #}
- <div class="input-group"> {# #}
- <label class="input-group-addon" id="filter-label" for="search-input">Filter:</label> {# #}
- <input type="text" class="form-control filter-input" placeholder="Keywords or search string (`S` or `/` to focus)" id="search-input" /> {# #}
- <span class="input-group-btn"> {# #}
- <button class="filter-clear btn" type="button" onclick="searchState.clearInput(event)"> {# #}
- Clear {# #}
- </button> {# #}
- </span> {# #}
- </div> {# #}
- </div> {# #}
- <div class="col-12 col-md-2 btn-group expansion-group"> {# #}
- <button title="Collapse All" class="btn btn-default expansion-control" type="button" id="collapse-all"> {# #}
- <span class="glyphicon glyphicon-collapse-up"></span> {# #}
+ <div id="menu-filters"> {# #}
+ <div class="panel-body row"> {# #}
+ <div id="upper-filters" class="col-12 col-md-5"> {# #}
+ <div class="btn-group" id="lint-levels" tabindex="-1"> {# #}
+ <button type="button" class="btn btn-default dropdown-toggle"> {# #}
+ Lint levels <span class="badge">4</span> <span class="caret"></span> {# #}
</button> {# #}
- <button title="Expand All" class="btn btn-default expansion-control" type="button" id="expand-all"> {# #}
- <span class="glyphicon glyphicon-collapse-down"></span> {# #}
+ <ul class="dropdown-menu" id="lint-levels-selector"> {# #}
+ <li class="checkbox"> {# #}
+ <button onclick="toggleElements('levels_filter', true)">All</button> {# #}
+ </li> {# #}
+ <li class="checkbox"> {# #}
+ <button onclick="toggleElements('levels_filter', false)">None</button> {# #}
+ </li> {# #}
+ <li role="separator" class="divider"></li> {# #}
+ </ul> {# #}
+ </div> {# #}
+ <div class="btn-group" id="lint-groups" tabindex="-1"> {# #}
+ <button type="button" class="btn btn-default dropdown-toggle"> {# #}
+ Lint groups <span class="badge">9</span> <span class="caret"></span> {# #}
</button> {# #}
+ <ul class="dropdown-menu" id="lint-groups-selector"> {# #}
+ <li class="checkbox"> {# #}
+ <button onclick="toggleElements('groups_filter', true)">All</button> {# #}
+ </li> {# #}
+ <li class="checkbox"> {# #}
+ <button onclick="resetGroupsToDefault()">Default</button> {# #}
+ </li> {# #}
+ <li class="checkbox"> {# #}
+ <button onclick="toggleElements('groups_filter', false)">None</button> {# #}
+ </li> {# #}
+ <li role="separator" class="divider"></li> {# #}
+ </ul> {# #}
+ </div> {# #}
+ <div class="btn-group" id="version-filter" tabindex="-1"> {# #}
+ <button type="button" class="btn btn-default dropdown-toggle"> {# #}
+ Version {#+ #}
+ <span id="version-filter-count" class="badge">0</span> {#+ #}
+ <span class="caret"></span> {# #}
+ </button> {# #}
+ <ul id="version-filter-selector" class="dropdown-menu"> {# #}
+ <li class="checkbox"> {# #}
+ <button onclick="clearVersionFilters()">Clear filters</button> {# #}
+ </li> {# #}
+ <li role="separator" class="divider"></li> {# #}
+ </ul> {# #}
+ </div> {# #}
+ <div class="btn-group" id="lint-applicabilities" tabindex="-1"> {# #}
+ <button type="button" class="btn btn-default dropdown-toggle"> {# #}
+ Applicability {#+ #}
+ <span class="badge">4</span> {#+ #}
+ <span class="caret"></span> {# #}
+ </button> {# #}
+ <ul class="dropdown-menu" id="lint-applicabilities-selector"> {# #}
+ <li class="checkbox"> {# #}
+ <button onclick="toggleElements('applicabilities_filter', true)">All</button> {# #}
+ </li> {# #}
+ <li class="checkbox"> {# #}
+ <button onclick="toggleElements('applicabilities_filter', false)">None</button> {# #}
+ </li> {# #}
+ <li role="separator" class="divider"></li> {# #}
+ </ul> {# #}
</div> {# #}
</div> {# #}
- </div>
- {% for lint in lints %}
- <article class="panel panel-default" id="{{lint.id}}"> {# #}
- <input id="label-{{lint.id}}" type="checkbox"> {# #}
- <label for="label-{{lint.id}}"> {# #}
- <h2 class="lint-title"> {# #}
- <div class="panel-title-name" id="lint-{{lint.id}}"> {# #}
- {{lint.id +}}
- <a href="#{{lint.id}}" class="anchor label label-default">¶</a> {#+ #}
- <a href="" class="copy-to-clipboard anchor label label-default"> {# #}
- 📋 {# #}
- </a> {# #}
- </div> {# #}
-
- <span class="label label-lint-group label-default label-group-{{lint.group}}">{{lint.group}}</span> {#+ #}
-
- <span class="label label-lint-level label-lint-level-{{lint.level}}">{{lint.level}}</span> {#+ #}
-
- <span class="label label-doc-folding"></span> {# #}
- </h2> {# #}
- </label> {# #}
-
- <div class="list-group lint-docs"> {# #}
- <div class="list-group-item lint-doc-md">{{Self::markdown(lint.docs)}}</div> {# #}
- <div class="lint-additional-info-container">
- {# Applicability #}
- <div> {# #}
- Applicability: {#+ #}
- <span class="label label-default label-applicability">{{ lint.applicability_str() }}</span> {# #}
- <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.Applicability.html#variants">(?)</a> {# #}
- </div>
- {# Clippy version #}
- <div> {# #}
- {% if lint.group == "deprecated" %}Deprecated{% else %} Added{% endif +%} in: {#+ #}
- <span class="label label-default label-version">{{lint.version}}</span> {# #}
- </div>
- {# Open related issues #}
- <div> {# #}
- <a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a> {# #}
- </div>
-
- {# Jump to source #}
- {% if let Some(id_location) = lint.id_location %}
- <div> {# #}
- <a href="https://github.com/rust-lang/rust-clippy/blob/master/{{id_location}}">View Source</a> {# #}
- </div>
- {% endif %}
- </div> {# #}
+ <div class="col-12 col-md-5 search-control"> {# #}
+ <div class="input-group"> {# #}
+ <label class="input-group-addon" id="filter-label" for="search-input">Filter:</label> {# #}
+ <input type="text" class="form-control filter-input" placeholder="Keywords or search string (`S` or `/` to focus)" id="search-input" /> {# #}
+ <span class="input-group-btn"> {# #}
+ <button class="filter-clear btn" type="button" onclick="searchState.clearInput(event)"> {# #}
+ Clear {# #}
+ </button> {# #}
+ </span> {# #}
</div> {# #}
- </article>
- {% endfor %}
- </div> {# #}
+ </div> {# #}
+ <div class="col-12 col-md-2 btn-group expansion-group"> {# #}
+ <button title="Collapse All" class="btn btn-default expansion-control" type="button" id="collapse-all"> {# #}
+ <span class="glyphicon glyphicon-collapse-up"></span> {# #}
+ </button> {# #}
+ <button title="Expand All" class="btn btn-default expansion-control" type="button" id="expand-all"> {# #}
+ <span class="glyphicon glyphicon-collapse-down"></span> {# #}
+ </button> {# #}
+ </div> {# #}
+ </div> {# #}
+ </div>
+ {% for lint in lints %}
+ <article id="{{lint.id}}"> {# #}
+ <input id="label-{{lint.id}}" type="checkbox"> {# #}
+ <label for="label-{{lint.id}}"> {# #}
+ <h2 class="lint-title"> {# #}
+ <div class="panel-title-name" id="lint-{{lint.id}}"> {# #}
+ {{lint.id ~}}
+ <a href="#{{lint.id}}" class="anchor label label-default">¶</a> {#+ #}
+ <a href="" class="copy-to-clipboard anchor label label-default"> {# #}
+ 📋 {# #}
+ </a> {# #}
+ </div> {# #}
+
+ <span class="label label-default lint-group group-{{lint.group}}">{{lint.group}}</span> {#+ #}
+
+ <span class="label lint-level level-{{lint.level}}">{{lint.level}}</span> {#+ #}
+
+ <span class="label doc-folding"></span> {# #}
+ </h2> {# #}
+ </label> {# #}
+
+ <div class="lint-docs"> {# #}
+ <div class="lint-doc-md">{{Self::markdown(lint.docs)}}</div> {# #}
+ <div class="lint-additional-info">
+ {# Applicability #}
+ <div> {# #}
+ Applicability: {#+ #}
+ <span class="label label-default applicability">{{ lint.applicability_str() }}</span> {# #}
+ <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.Applicability.html#variants">(?)</a> {# #}
+ </div>
+ {# Clippy version #}
+ <div> {# #}
+ {% if lint.group == "deprecated" %}Deprecated{% else %} Added{% endif +%} in: {#+ #}
+ <span class="label label-default label-version">{{lint.version}}</span> {# #}
+ </div>
+ {# Open related issues #}
+ <div> {# #}
+ <a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a> {# #}
+ </div>
+
+ {# Jump to source #}
+ {% if let Some(id_location) = lint.id_location %}
+ <div> {# #}
+ <a href="https://github.com/rust-lang/rust-clippy/blob/master/{{id_location}}">View Source</a> {# #}
+ </div>
+ {% endif %}
+ </div> {# #}
+ </div> {# #}
+ </article>
+ {% endfor %}
</div> {# #}
<a {#+ #}
diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js
index ee13f1c..d320496 100644
--- a/src/tools/clippy/util/gh-pages/script.js
+++ b/src/tools/clippy/util/gh-pages/script.js
@@ -208,7 +208,6 @@
allow: true,
warn: true,
deny: true,
- none: true,
};
const APPLICABILITIES_FILTER_DEFAULT = {
Unspecified: true,
@@ -250,10 +249,10 @@
}
return {
elem: elem,
- group: elem.querySelector(".label-lint-group").innerText,
- level: elem.querySelector(".label-lint-level").innerText,
+ group: elem.querySelector(".lint-group").innerText,
+ level: elem.querySelector(".lint-level").innerText,
version: parseInt(version.split(".")[1]),
- applicability: elem.querySelector(".label-applicability").innerText,
+ applicability: elem.querySelector(".applicability").innerText,
filteredOut: false,
searchFilteredOut: false,
};
@@ -594,19 +593,19 @@
addListeners();
highlightLazily();
+function updateLintCount() {
+ const allLints = filters.getAllLints().filter(lint => lint.group != "deprecated");
+ const totalLints = allLints.length;
+
+ const countElement = document.getElementById("lint-count");
+ if (countElement) {
+ countElement.innerText = `Total number: ${totalLints}`;
+ }
+}
+
generateSettings();
generateSearch();
parseURLFilters();
scrollToLintByURL();
filters.filterLints();
updateLintCount();
-
-function updateLintCount() {
- const allLints = filters.getAllLints().filter(lint => lint.group != "deprecated");
- const totalLints = allLints.length;
-
- const countElement = document.getElementById("lint-count");
- if (countElement) {
- countElement.innerText = `Total number: ${totalLints}`;
- }
-}
diff --git a/src/tools/clippy/util/gh-pages/style.css b/src/tools/clippy/util/gh-pages/style.css
index 022ea87..66abf45 100644
--- a/src/tools/clippy/util/gh-pages/style.css
+++ b/src/tools/clippy/util/gh-pages/style.css
@@ -30,17 +30,25 @@
background-color: var(--theme-hover);
}
-div.panel div.panel-body button {
+.container > * {
+ margin-bottom: 20px;
+ border-radius: 4px;
+ background: var(--bg);
+ border: 1px solid var(--theme-popup-border);
+ box-shadow: 0 1px 1px rgba(0,0,0,.05);
+}
+
+div.panel-body button {
background: var(--searchbar-bg);
color: var(--searchbar-fg);
border-color: var(--theme-popup-border);
}
-div.panel div.panel-body button:hover {
+div.panel-body button:hover {
box-shadow: 0 0 3px var(--searchbar-shadow-color);
}
-div.panel div.panel-body button.open {
+div.panel-body button.open {
filter: brightness(90%);
}
@@ -48,8 +56,6 @@
background-color: #777;
}
-.panel-heading { cursor: pointer; }
-
.lint-title {
cursor: pointer;
margin-top: 0;
@@ -70,8 +76,8 @@
.panel-title-name { flex: 1; min-width: 400px;}
-.panel .panel-title-name .anchor { display: none; }
-.panel:hover .panel-title-name .anchor { display: inline;}
+.panel-title-name .anchor { display: none; }
+article:hover .panel-title-name .anchor { display: inline;}
.search-control {
margin-top: 15px;
@@ -111,40 +117,48 @@
padding-bottom: 0.3em;
}
-.label-lint-group {
- min-width: 8em;
-}
-.label-lint-level {
+.lint-level {
min-width: 4em;
}
-
-.label-lint-level-allow {
+.level-allow {
background-color: #5cb85c;
}
-.label-lint-level-warn {
+.level-warn {
background-color: #f0ad4e;
}
-.label-lint-level-deny {
+.level-deny {
background-color: #d9534f;
}
-.label-lint-level-none {
+.level-none {
background-color: #777777;
opacity: 0.5;
}
-.label-group-deprecated {
+.lint-group {
+ min-width: 8em;
+}
+.group-deprecated {
opacity: 0.5;
}
-.label-doc-folding {
+.doc-folding {
color: #000;
background-color: #fff;
border: 1px solid var(--theme-popup-border);
}
-.label-doc-folding:hover {
+.doc-folding:hover {
background-color: #e6e6e6;
}
+.lint-doc-md {
+ position: relative;
+ display: block;
+ padding: 10px 15px;
+ margin-bottom: -1px;
+ background: 0%;
+ border-bottom: 1px solid var(--theme-popup-border);
+ border-top: 1px solid var(--theme-popup-border);
+}
.lint-doc-md > h3 {
border-top: 1px solid var(--theme-popup-border);
padding: 10px 15px;
@@ -157,32 +171,32 @@
}
@media (max-width:749px) {
- .lint-additional-info-container {
+ .lint-additional-info {
display: flex;
flex-flow: column;
}
- .lint-additional-info-container > div + div {
+ .lint-additional-info > div + div {
border-top: 1px solid var(--theme-popup-border);
}
}
@media (min-width:750px) {
- .lint-additional-info-container {
+ .lint-additional-info {
display: flex;
flex-flow: row;
}
- .lint-additional-info-container > div + div {
+ .lint-additional-info > div + div {
border-left: 1px solid var(--theme-popup-border);
}
}
-.lint-additional-info-container > div {
+.lint-additional-info > div {
display: inline-flex;
min-width: 200px;
flex-grow: 1;
padding: 9px 5px 5px 15px;
}
-.label-applicability {
+.applicability {
background-color: #777777;
margin: auto 5px;
}
@@ -332,21 +346,12 @@
border: 1px solid var(--theme-popup-border);
}
.page-header {
- border-color: var(--theme-popup-border);
+ border: 0;
+ border-bottom: 1px solid var(--theme-popup-border);
+ padding-bottom: 19px;
+ border-radius: 0;
}
-.panel-default .panel-heading {
- background: var(--theme-hover);
- color: var(--fg);
- border: 1px solid var(--theme-popup-border);
-}
-.panel-default .panel-heading:hover {
- filter: brightness(90%);
-}
-.list-group-item {
- background: 0%;
- border: 1px solid var(--theme-popup-border);
-}
-.panel, pre, hr {
+pre, hr {
background: var(--bg);
border: 1px solid var(--theme-popup-border);
}
@@ -442,14 +447,15 @@
article > input[type="checkbox"] {
display: none;
}
-article > input[type="checkbox"] + label .label-doc-folding::before {
+article > input[type="checkbox"] + label .doc-folding::before {
content: "+";
}
-article > input[type="checkbox"]:checked + label .label-doc-folding::before {
+article > input[type="checkbox"]:checked + label .doc-folding::before {
content: "−";
}
.lint-docs {
display: none;
+ margin-bottom: 0;
}
article > input[type="checkbox"]:checked ~ .lint-docs {
display: block;
diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs
index 1397c87..54511f4 100644
--- a/src/tools/compiletest/src/directives.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -12,6 +12,9 @@
use crate::common::{CodegenBackend, Config, Debugger, FailMode, PassMode, RunFailMode, TestMode};
use crate::debuggers::{extract_cdb_version, extract_gdb_version};
use crate::directives::auxiliary::{AuxProps, parse_and_update_aux};
+use crate::directives::directive_names::{
+ KNOWN_DIRECTIVE_NAMES, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
+};
use crate::directives::needs::CachedNeedsConditions;
use crate::errors::ErrorKind;
use crate::executor::{CollectedTestDesc, ShouldPanic};
@@ -20,6 +23,7 @@
pub(crate) mod auxiliary;
mod cfg;
+mod directive_names;
mod needs;
#[cfg(test)]
mod tests;
@@ -59,9 +63,9 @@ pub fn from_reader<R: Read>(config: &Config, testfile: &Utf8Path, rdr: R) -> Sel
&mut poisoned,
testfile,
rdr,
- &mut |DirectiveLine { raw_directive: ln, .. }| {
- parse_and_update_aux(config, ln, &mut props.aux);
- config.parse_and_update_revisions(testfile, ln, &mut props.revisions);
+ &mut |DirectiveLine { line_number, raw_directive: ln, .. }| {
+ parse_and_update_aux(config, ln, testfile, line_number, &mut props.aux);
+ config.parse_and_update_revisions(testfile, line_number, ln, &mut props.revisions);
},
);
@@ -351,7 +355,7 @@ fn load_from(&mut self, testfile: &Utf8Path, test_revision: Option<&str>, config
&mut poisoned,
testfile,
file,
- &mut |directive @ DirectiveLine { raw_directive: ln, .. }| {
+ &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| {
if !directive.applies_to_test_revision(test_revision) {
return;
}
@@ -361,17 +365,28 @@ fn load_from(&mut self, testfile: &Utf8Path, test_revision: Option<&str>, config
config.push_name_value_directive(
ln,
ERROR_PATTERN,
+ testfile,
+ line_number,
&mut self.error_patterns,
|r| r,
);
config.push_name_value_directive(
ln,
REGEX_ERROR_PATTERN,
+ testfile,
+ line_number,
&mut self.regex_error_patterns,
|r| r,
);
- config.push_name_value_directive(ln, DOC_FLAGS, &mut self.doc_flags, |r| r);
+ config.push_name_value_directive(
+ ln,
+ DOC_FLAGS,
+ testfile,
+ line_number,
+ &mut self.doc_flags,
+ |r| r,
+ );
fn split_flags(flags: &str) -> Vec<String> {
// Individual flags can be single-quoted to preserve spaces; see
@@ -386,7 +401,9 @@ fn split_flags(flags: &str) -> Vec<String> {
.collect::<Vec<_>>()
}
- if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) {
+ if let Some(flags) =
+ config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile, line_number)
+ {
let flags = split_flags(&flags);
for flag in &flags {
if flag == "--edition" || flag.starts_with("--edition=") {
@@ -395,25 +412,40 @@ fn split_flags(flags: &str) -> Vec<String> {
}
self.compile_flags.extend(flags);
}
- if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() {
+ if config
+ .parse_name_value_directive(
+ ln,
+ INCORRECT_COMPILER_FLAGS,
+ testfile,
+ line_number,
+ )
+ .is_some()
+ {
panic!("`compiler-flags` directive should be spelled `compile-flags`");
}
- if let Some(edition) = config.parse_edition(ln) {
+ if let Some(edition) = config.parse_edition(ln, testfile, line_number) {
// The edition is added at the start, since flags from //@compile-flags must
// be passed to rustc last.
self.compile_flags.insert(0, format!("--edition={}", edition.trim()));
has_edition = true;
}
- config.parse_and_update_revisions(testfile, ln, &mut self.revisions);
+ config.parse_and_update_revisions(
+ testfile,
+ line_number,
+ ln,
+ &mut self.revisions,
+ );
- if let Some(flags) = config.parse_name_value_directive(ln, RUN_FLAGS) {
+ if let Some(flags) =
+ config.parse_name_value_directive(ln, RUN_FLAGS, testfile, line_number)
+ {
self.run_flags.extend(split_flags(&flags));
}
if self.pp_exact.is_none() {
- self.pp_exact = config.parse_pp_exact(ln, testfile);
+ self.pp_exact = config.parse_pp_exact(ln, testfile, line_number);
}
config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice);
@@ -435,7 +467,9 @@ fn split_flags(flags: &str) -> Vec<String> {
);
config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut self.no_prefer_dynamic);
- if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE) {
+ if let Some(m) =
+ config.parse_name_value_directive(ln, PRETTY_MODE, testfile, line_number)
+ {
self.pretty_mode = m;
}
@@ -446,35 +480,45 @@ fn split_flags(flags: &str) -> Vec<String> {
);
// Call a helper method to deal with aux-related directives.
- parse_and_update_aux(config, ln, &mut self.aux);
+ parse_and_update_aux(config, ln, testfile, line_number, &mut self.aux);
config.push_name_value_directive(
ln,
EXEC_ENV,
+ testfile,
+ line_number,
&mut self.exec_env,
Config::parse_env,
);
config.push_name_value_directive(
ln,
UNSET_EXEC_ENV,
+ testfile,
+ line_number,
&mut self.unset_exec_env,
|r| r.trim().to_owned(),
);
config.push_name_value_directive(
ln,
RUSTC_ENV,
+ testfile,
+ line_number,
&mut self.rustc_env,
Config::parse_env,
);
config.push_name_value_directive(
ln,
UNSET_RUSTC_ENV,
+ testfile,
+ line_number,
&mut self.unset_rustc_env,
|r| r.trim().to_owned(),
);
config.push_name_value_directive(
ln,
FORBID_OUTPUT,
+ testfile,
+ line_number,
&mut self.forbid_output,
|r| r,
);
@@ -510,7 +554,7 @@ fn split_flags(flags: &str) -> Vec<String> {
}
if let Some(code) = config
- .parse_name_value_directive(ln, FAILURE_STATUS)
+ .parse_name_value_directive(ln, FAILURE_STATUS, testfile, line_number)
.and_then(|code| code.trim().parse::<i32>().ok())
{
self.failure_status = Some(code);
@@ -531,6 +575,8 @@ fn split_flags(flags: &str) -> Vec<String> {
config.set_name_value_directive(
ln,
ASSEMBLY_OUTPUT,
+ testfile,
+ line_number,
&mut self.assembly_output,
|r| r.trim().to_string(),
);
@@ -543,7 +589,9 @@ fn split_flags(flags: &str) -> Vec<String> {
// Unlike the other `name_value_directive`s this needs to be handled manually,
// because it sets a `bool` flag.
- if let Some(known_bug) = config.parse_name_value_directive(ln, KNOWN_BUG) {
+ if let Some(known_bug) =
+ config.parse_name_value_directive(ln, KNOWN_BUG, testfile, line_number)
+ {
let known_bug = known_bug.trim();
if known_bug == "unknown"
|| known_bug.split(',').all(|issue_ref| {
@@ -571,16 +619,25 @@ fn split_flags(flags: &str) -> Vec<String> {
config.set_name_value_directive(
ln,
TEST_MIR_PASS,
+ testfile,
+ line_number,
&mut self.mir_unit_test,
|s| s.trim().to_string(),
);
config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base);
- if let Some(flags) = config.parse_name_value_directive(ln, LLVM_COV_FLAGS) {
+ if let Some(flags) =
+ config.parse_name_value_directive(ln, LLVM_COV_FLAGS, testfile, line_number)
+ {
self.llvm_cov_flags.extend(split_flags(&flags));
}
- if let Some(flags) = config.parse_name_value_directive(ln, FILECHECK_FLAGS) {
+ if let Some(flags) = config.parse_name_value_directive(
+ ln,
+ FILECHECK_FLAGS,
+ testfile,
+ line_number,
+ ) {
self.filecheck_flags.extend(split_flags(&flags));
}
@@ -588,9 +645,12 @@ fn split_flags(flags: &str) -> Vec<String> {
self.update_add_core_stubs(ln, config);
- if let Some(err_kind) =
- config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS)
- {
+ if let Some(err_kind) = config.parse_name_value_directive(
+ ln,
+ DONT_REQUIRE_ANNOTATIONS,
+ testfile,
+ line_number,
+ ) {
self.dont_require_annotations
.insert(ErrorKind::expect_from_user_str(err_kind.trim()));
}
@@ -769,294 +829,6 @@ fn line_directive<'line>(
Some(DirectiveLine { line_number, revision, raw_directive })
}
-/// This was originally generated by collecting directives from ui tests and then extracting their
-/// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is
-/// a best-effort approximation for diagnostics. Add new directives to this list when needed.
-const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
- // tidy-alphabetical-start
- "add-core-stubs",
- "assembly-output",
- "aux-bin",
- "aux-build",
- "aux-codegen-backend",
- "aux-crate",
- "build-aux-docs",
- "build-fail",
- "build-pass",
- "check-fail",
- "check-pass",
- "check-run-results",
- "check-stdout",
- "check-test-line-numbers-match",
- "compile-flags",
- "doc-flags",
- "dont-check-compiler-stderr",
- "dont-check-compiler-stdout",
- "dont-check-failure-status",
- "dont-require-annotations",
- "edition",
- "error-pattern",
- "exact-llvm-major-version",
- "exec-env",
- "failure-status",
- "filecheck-flags",
- "forbid-output",
- "force-host",
- "ignore-16bit",
- "ignore-32bit",
- "ignore-64bit",
- "ignore-aarch64",
- "ignore-aarch64-pc-windows-msvc",
- "ignore-aarch64-unknown-linux-gnu",
- "ignore-aix",
- "ignore-android",
- "ignore-apple",
- "ignore-arm",
- "ignore-arm-unknown-linux-gnueabi",
- "ignore-arm-unknown-linux-gnueabihf",
- "ignore-arm-unknown-linux-musleabi",
- "ignore-arm-unknown-linux-musleabihf",
- "ignore-auxiliary",
- "ignore-avr",
- "ignore-backends",
- "ignore-beta",
- "ignore-cdb",
- "ignore-compare-mode-next-solver",
- "ignore-compare-mode-polonius",
- "ignore-coverage-map",
- "ignore-coverage-run",
- "ignore-cross-compile",
- "ignore-eabi",
- "ignore-elf",
- "ignore-emscripten",
- "ignore-endian-big",
- "ignore-enzyme",
- "ignore-freebsd",
- "ignore-fuchsia",
- "ignore-gdb",
- "ignore-gdb-version",
- "ignore-gnu",
- "ignore-haiku",
- "ignore-horizon",
- "ignore-i686-pc-windows-gnu",
- "ignore-i686-pc-windows-msvc",
- "ignore-illumos",
- "ignore-ios",
- "ignore-linux",
- "ignore-lldb",
- "ignore-llvm-version",
- "ignore-loongarch32",
- "ignore-loongarch64",
- "ignore-macabi",
- "ignore-macos",
- "ignore-msp430",
- "ignore-msvc",
- "ignore-musl",
- "ignore-netbsd",
- "ignore-nightly",
- "ignore-none",
- "ignore-nto",
- "ignore-nvptx64",
- "ignore-nvptx64-nvidia-cuda",
- "ignore-openbsd",
- "ignore-pass",
- "ignore-powerpc",
- "ignore-remote",
- "ignore-riscv64",
- "ignore-rustc-debug-assertions",
- "ignore-rustc_abi-x86-sse2",
- "ignore-s390x",
- "ignore-sgx",
- "ignore-sparc64",
- "ignore-spirv",
- "ignore-stable",
- "ignore-stage1",
- "ignore-stage2",
- "ignore-std-debug-assertions",
- "ignore-test",
- "ignore-thumb",
- "ignore-thumbv8m.base-none-eabi",
- "ignore-thumbv8m.main-none-eabi",
- "ignore-tvos",
- "ignore-unix",
- "ignore-unknown",
- "ignore-uwp",
- "ignore-visionos",
- "ignore-vxworks",
- "ignore-wasi",
- "ignore-wasm",
- "ignore-wasm32",
- "ignore-wasm32-bare",
- "ignore-wasm64",
- "ignore-watchos",
- "ignore-windows",
- "ignore-windows-gnu",
- "ignore-windows-msvc",
- "ignore-x32",
- "ignore-x86",
- "ignore-x86_64",
- "ignore-x86_64-apple-darwin",
- "ignore-x86_64-pc-windows-gnu",
- "ignore-x86_64-unknown-linux-gnu",
- "incremental",
- "known-bug",
- "llvm-cov-flags",
- "max-llvm-major-version",
- "min-cdb-version",
- "min-gdb-version",
- "min-lldb-version",
- "min-llvm-version",
- "min-system-llvm-version",
- "needs-asm-support",
- "needs-backends",
- "needs-crate-type",
- "needs-deterministic-layouts",
- "needs-dlltool",
- "needs-dynamic-linking",
- "needs-enzyme",
- "needs-force-clang-based-tests",
- "needs-git-hash",
- "needs-llvm-components",
- "needs-llvm-zstd",
- "needs-profiler-runtime",
- "needs-relocation-model-pic",
- "needs-run-enabled",
- "needs-rust-lld",
- "needs-rustc-debug-assertions",
- "needs-sanitizer-address",
- "needs-sanitizer-cfi",
- "needs-sanitizer-dataflow",
- "needs-sanitizer-hwaddress",
- "needs-sanitizer-kcfi",
- "needs-sanitizer-leak",
- "needs-sanitizer-memory",
- "needs-sanitizer-memtag",
- "needs-sanitizer-safestack",
- "needs-sanitizer-shadow-call-stack",
- "needs-sanitizer-support",
- "needs-sanitizer-thread",
- "needs-std-debug-assertions",
- "needs-subprocess",
- "needs-symlink",
- "needs-target-has-atomic",
- "needs-target-std",
- "needs-threads",
- "needs-unwind",
- "needs-wasmtime",
- "needs-xray",
- "no-auto-check-cfg",
- "no-prefer-dynamic",
- "normalize-stderr",
- "normalize-stderr-32bit",
- "normalize-stderr-64bit",
- "normalize-stdout",
- "only-16bit",
- "only-32bit",
- "only-64bit",
- "only-aarch64",
- "only-aarch64-apple-darwin",
- "only-aarch64-unknown-linux-gnu",
- "only-apple",
- "only-arm",
- "only-avr",
- "only-beta",
- "only-bpf",
- "only-cdb",
- "only-dist",
- "only-elf",
- "only-emscripten",
- "only-gnu",
- "only-i686-pc-windows-gnu",
- "only-i686-pc-windows-msvc",
- "only-i686-unknown-linux-gnu",
- "only-ios",
- "only-linux",
- "only-loongarch32",
- "only-loongarch64",
- "only-loongarch64-unknown-linux-gnu",
- "only-macos",
- "only-mips",
- "only-mips64",
- "only-msp430",
- "only-msvc",
- "only-musl",
- "only-nightly",
- "only-nvptx64",
- "only-powerpc",
- "only-riscv64",
- "only-rustc_abi-x86-sse2",
- "only-s390x",
- "only-sparc",
- "only-sparc64",
- "only-stable",
- "only-thumb",
- "only-tvos",
- "only-unix",
- "only-visionos",
- "only-wasm32",
- "only-wasm32-bare",
- "only-wasm32-wasip1",
- "only-watchos",
- "only-windows",
- "only-windows-gnu",
- "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",
- "only-x86_64-unknown-linux-gnu",
- "pp-exact",
- "pretty-compare-only",
- "pretty-mode",
- "proc-macro",
- "reference",
- "regex-error-pattern",
- "remap-src-base",
- "revisions",
- "run-crash",
- "run-fail",
- "run-fail-or-crash",
- "run-flags",
- "run-pass",
- "run-rustfix",
- "rustc-env",
- "rustfix-only-machine-applicable",
- "should-fail",
- "should-ice",
- "stderr-per-bitwidth",
- "test-mir-pass",
- "unique-doc-out-dir",
- "unset-exec-env",
- "unset-rustc-env",
- // Used by the tidy check `unknown_revision`.
- "unused-revision-names",
- // tidy-alphabetical-end
-];
-
-const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[
- "count",
- "!count",
- "files",
- "!files",
- "has",
- "!has",
- "has-dir",
- "!has-dir",
- "hasraw",
- "!hasraw",
- "matches",
- "!matches",
- "matchesraw",
- "!matchesraw",
- "snapshot",
- "!snapshot",
-];
-
-const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] =
- &["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"];
-
/// The (partly) broken-down contents of a line containing a test directive,
/// which [`iter_directives`] passes to its callback function.
///
@@ -1204,6 +976,7 @@ impl Config {
fn parse_and_update_revisions(
&self,
testfile: &Utf8Path,
+ line_number: usize,
line: &str,
existing: &mut Vec<String>,
) {
@@ -1217,7 +990,8 @@ fn parse_and_update_revisions(
const FILECHECK_FORBIDDEN_REVISION_NAMES: [&str; 9] =
["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"];
- if let Some(raw) = self.parse_name_value_directive(line, "revisions") {
+ if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile, line_number)
+ {
if self.mode == TestMode::RunMake {
panic!("`run-make` tests do not support revisions: {}", testfile);
}
@@ -1262,8 +1036,13 @@ fn parse_env(nv: String) -> (String, String) {
(name.to_owned(), value.to_owned())
}
- fn parse_pp_exact(&self, line: &str, testfile: &Utf8Path) -> Option<Utf8PathBuf> {
- if let Some(s) = self.parse_name_value_directive(line, "pp-exact") {
+ fn parse_pp_exact(
+ &self,
+ line: &str,
+ testfile: &Utf8Path,
+ line_number: usize,
+ ) -> Option<Utf8PathBuf> {
+ if let Some(s) = self.parse_name_value_directive(line, "pp-exact", testfile, line_number) {
Some(Utf8PathBuf::from(&s))
} else if self.parse_name_directive(line, "pp-exact") {
testfile.file_name().map(Utf8PathBuf::from)
@@ -1304,19 +1083,31 @@ fn parse_negative_name_directive(&self, line: &str, directive: &str) -> bool {
line.starts_with("no-") && self.parse_name_directive(&line[3..], directive)
}
- pub fn parse_name_value_directive(&self, line: &str, directive: &str) -> Option<String> {
+ pub fn parse_name_value_directive(
+ &self,
+ line: &str,
+ directive: &str,
+ testfile: &Utf8Path,
+ line_number: usize,
+ ) -> Option<String> {
let colon = directive.len();
if line.starts_with(directive) && line.as_bytes().get(colon) == Some(&b':') {
let value = line[(colon + 1)..].to_owned();
debug!("{}: {}", directive, value);
- Some(expand_variables(value, self))
+ let value = expand_variables(value, self);
+ if value.is_empty() {
+ error!("{testfile}:{line_number}: empty value for directive `{directive}`");
+ help!("expected syntax is: `{directive}: value`");
+ panic!("empty directive value detected");
+ }
+ Some(value)
} else {
None
}
}
- fn parse_edition(&self, line: &str) -> Option<String> {
- self.parse_name_value_directive(line, "edition")
+ fn parse_edition(&self, line: &str, testfile: &Utf8Path, line_number: usize) -> Option<String> {
+ self.parse_name_value_directive(line, "edition", testfile, line_number)
}
fn set_name_directive(&self, line: &str, directive: &str, value: &mut bool) {
@@ -1338,11 +1129,14 @@ fn set_name_value_directive<T>(
&self,
line: &str,
directive: &str,
+ testfile: &Utf8Path,
+ line_number: usize,
value: &mut Option<T>,
parse: impl FnOnce(String) -> T,
) {
if value.is_none() {
- *value = self.parse_name_value_directive(line, directive).map(parse);
+ *value =
+ self.parse_name_value_directive(line, directive, testfile, line_number).map(parse);
}
}
@@ -1350,10 +1144,14 @@ fn push_name_value_directive<T>(
&self,
line: &str,
directive: &str,
+ testfile: &Utf8Path,
+ line_number: usize,
values: &mut Vec<T>,
parse: impl FnOnce(String) -> T,
) {
- if let Some(value) = self.parse_name_value_directive(line, directive).map(parse) {
+ if let Some(value) =
+ self.parse_name_value_directive(line, directive, testfile, line_number).map(parse)
+ {
values.push(value);
}
}
@@ -1670,9 +1468,9 @@ macro_rules! decision {
decision!(cfg::handle_ignore(config, ln));
decision!(cfg::handle_only(config, ln));
decision!(needs::handle_needs(&cache.needs, config, ln));
- decision!(ignore_llvm(config, path, ln));
- decision!(ignore_backends(config, path, ln));
- decision!(needs_backends(config, path, ln));
+ decision!(ignore_llvm(config, path, ln, line_number));
+ decision!(ignore_backends(config, path, ln, line_number));
+ decision!(needs_backends(config, path, ln, line_number));
decision!(ignore_cdb(config, ln));
decision!(ignore_gdb(config, ln));
decision!(ignore_lldb(config, ln));
@@ -1799,8 +1597,15 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
IgnoreDecision::Continue
}
-fn ignore_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
- if let Some(backends_to_ignore) = config.parse_name_value_directive(line, "ignore-backends") {
+fn ignore_backends(
+ config: &Config,
+ path: &Utf8Path,
+ line: &str,
+ line_number: usize,
+) -> IgnoreDecision {
+ if let Some(backends_to_ignore) =
+ config.parse_name_value_directive(line, "ignore-backends", path, line_number)
+ {
for backend in backends_to_ignore.split_whitespace().map(|backend| {
match CodegenBackend::try_from(backend) {
Ok(backend) => backend,
@@ -1819,8 +1624,15 @@ fn ignore_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecisi
IgnoreDecision::Continue
}
-fn needs_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
- if let Some(needed_backends) = config.parse_name_value_directive(line, "needs-backends") {
+fn needs_backends(
+ config: &Config,
+ path: &Utf8Path,
+ line: &str,
+ line_number: usize,
+) -> IgnoreDecision {
+ if let Some(needed_backends) =
+ config.parse_name_value_directive(line, "needs-backends", path, line_number)
+ {
if !needed_backends
.split_whitespace()
.map(|backend| match CodegenBackend::try_from(backend) {
@@ -1842,9 +1654,9 @@ fn needs_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecisio
IgnoreDecision::Continue
}
-fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
+fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) -> IgnoreDecision {
if let Some(needed_components) =
- config.parse_name_value_directive(line, "needs-llvm-components")
+ config.parse_name_value_directive(line, "needs-llvm-components", path, line_number)
{
let components: HashSet<_> = config.llvm_components.split_whitespace().collect();
if let Some(missing_component) = needed_components
@@ -1865,7 +1677,9 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
if let Some(actual_version) = &config.llvm_version {
// Note that these `min` versions will check for not just major versions.
- if let Some(version_string) = config.parse_name_value_directive(line, "min-llvm-version") {
+ if let Some(version_string) =
+ config.parse_name_value_directive(line, "min-llvm-version", path, line_number)
+ {
let min_version = extract_llvm_version(&version_string);
// Ignore if actual version is smaller than the minimum required version.
if *actual_version < min_version {
@@ -1876,7 +1690,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
};
}
} else if let Some(version_string) =
- config.parse_name_value_directive(line, "max-llvm-major-version")
+ config.parse_name_value_directive(line, "max-llvm-major-version", path, line_number)
{
let max_version = extract_llvm_version(&version_string);
// Ignore if actual major version is larger than the maximum required major version.
@@ -1890,7 +1704,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
};
}
} else if let Some(version_string) =
- config.parse_name_value_directive(line, "min-system-llvm-version")
+ config.parse_name_value_directive(line, "min-system-llvm-version", path, line_number)
{
let min_version = extract_llvm_version(&version_string);
// Ignore if using system LLVM and actual version
@@ -1903,7 +1717,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
};
}
} else if let Some(version_range) =
- config.parse_name_value_directive(line, "ignore-llvm-version")
+ config.parse_name_value_directive(line, "ignore-llvm-version", path, line_number)
{
// Syntax is: "ignore-llvm-version: <version1> [- <version2>]"
let (v_min, v_max) =
@@ -1929,7 +1743,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
}
}
} else if let Some(version_string) =
- config.parse_name_value_directive(line, "exact-llvm-major-version")
+ config.parse_name_value_directive(line, "exact-llvm-major-version", path, line_number)
{
// Syntax is "exact-llvm-major-version: <version>"
let version = extract_llvm_version(&version_string);
diff --git a/src/tools/compiletest/src/directives/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs
index cdb75f6..7c1ed2e 100644
--- a/src/tools/compiletest/src/directives/auxiliary.rs
+++ b/src/tools/compiletest/src/directives/auxiliary.rs
@@ -3,6 +3,8 @@
use std::iter;
+use camino::Utf8Path;
+
use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
use crate::common::Config;
@@ -41,17 +43,42 @@ pub(crate) fn all_aux_path_strings(&self) -> impl Iterator<Item = &str> {
/// If the given test directive line contains an `aux-*` directive, parse it
/// and update [`AuxProps`] accordingly.
-pub(super) fn parse_and_update_aux(config: &Config, ln: &str, aux: &mut AuxProps) {
+pub(super) fn parse_and_update_aux(
+ config: &Config,
+ ln: &str,
+ testfile: &Utf8Path,
+ line_number: usize,
+ aux: &mut AuxProps,
+) {
if !(ln.starts_with("aux-") || ln.starts_with("proc-macro")) {
return;
}
- config.push_name_value_directive(ln, AUX_BUILD, &mut aux.builds, |r| r.trim().to_string());
- config.push_name_value_directive(ln, AUX_BIN, &mut aux.bins, |r| r.trim().to_string());
- config.push_name_value_directive(ln, AUX_CRATE, &mut aux.crates, parse_aux_crate);
- config
- .push_name_value_directive(ln, PROC_MACRO, &mut aux.proc_macros, |r| r.trim().to_string());
- if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) {
+ config.push_name_value_directive(ln, AUX_BUILD, testfile, line_number, &mut aux.builds, |r| {
+ r.trim().to_string()
+ });
+ config.push_name_value_directive(ln, AUX_BIN, testfile, line_number, &mut aux.bins, |r| {
+ r.trim().to_string()
+ });
+ config.push_name_value_directive(
+ ln,
+ AUX_CRATE,
+ testfile,
+ line_number,
+ &mut aux.crates,
+ parse_aux_crate,
+ );
+ config.push_name_value_directive(
+ ln,
+ PROC_MACRO,
+ testfile,
+ line_number,
+ &mut aux.proc_macros,
+ |r| r.trim().to_string(),
+ );
+ if let Some(r) =
+ config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND, testfile, line_number)
+ {
aux.codegen_backend = Some(r.trim().to_owned());
}
}
diff --git a/src/tools/compiletest/src/directives/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs
index 35f6a9e..802a1d6 100644
--- a/src/tools/compiletest/src/directives/cfg.rs
+++ b/src/tools/compiletest/src/directives/cfg.rs
@@ -285,6 +285,11 @@ macro_rules! condition {
if name == "gdb-version" {
outcome = MatchOutcome::External;
}
+
+ // Don't error out for ignore-backends,as it is handled elsewhere.
+ if name == "backends" {
+ outcome = MatchOutcome::External;
+ }
}
ParsedNameDirective {
diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs
new file mode 100644
index 0000000..7fc76a4
--- /dev/null
+++ b/src/tools/compiletest/src/directives/directive_names.rs
@@ -0,0 +1,289 @@
+/// This was originally generated by collecting directives from ui tests and then extracting their
+/// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is
+/// a best-effort approximation for diagnostics. Add new directives to this list when needed.
+pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
+ // tidy-alphabetical-start
+ "add-core-stubs",
+ "assembly-output",
+ "aux-bin",
+ "aux-build",
+ "aux-codegen-backend",
+ "aux-crate",
+ "build-aux-docs",
+ "build-fail",
+ "build-pass",
+ "check-fail",
+ "check-pass",
+ "check-run-results",
+ "check-stdout",
+ "check-test-line-numbers-match",
+ "compile-flags",
+ "doc-flags",
+ "dont-check-compiler-stderr",
+ "dont-check-compiler-stdout",
+ "dont-check-failure-status",
+ "dont-require-annotations",
+ "edition",
+ "error-pattern",
+ "exact-llvm-major-version",
+ "exec-env",
+ "failure-status",
+ "filecheck-flags",
+ "forbid-output",
+ "force-host",
+ "ignore-16bit",
+ "ignore-32bit",
+ "ignore-64bit",
+ "ignore-aarch64",
+ "ignore-aarch64-pc-windows-msvc",
+ "ignore-aarch64-unknown-linux-gnu",
+ "ignore-aix",
+ "ignore-android",
+ "ignore-apple",
+ "ignore-arm",
+ "ignore-arm-unknown-linux-gnueabi",
+ "ignore-arm-unknown-linux-gnueabihf",
+ "ignore-arm-unknown-linux-musleabi",
+ "ignore-arm-unknown-linux-musleabihf",
+ "ignore-auxiliary",
+ "ignore-avr",
+ "ignore-backends",
+ "ignore-beta",
+ "ignore-cdb",
+ "ignore-compare-mode-next-solver",
+ "ignore-compare-mode-polonius",
+ "ignore-coverage-map",
+ "ignore-coverage-run",
+ "ignore-cross-compile",
+ "ignore-eabi",
+ "ignore-elf",
+ "ignore-emscripten",
+ "ignore-endian-big",
+ "ignore-enzyme",
+ "ignore-freebsd",
+ "ignore-fuchsia",
+ "ignore-gdb",
+ "ignore-gdb-version",
+ "ignore-gnu",
+ "ignore-haiku",
+ "ignore-horizon",
+ "ignore-i686-pc-windows-gnu",
+ "ignore-i686-pc-windows-msvc",
+ "ignore-illumos",
+ "ignore-ios",
+ "ignore-linux",
+ "ignore-lldb",
+ "ignore-llvm-version",
+ "ignore-loongarch32",
+ "ignore-loongarch64",
+ "ignore-macabi",
+ "ignore-macos",
+ "ignore-msp430",
+ "ignore-msvc",
+ "ignore-musl",
+ "ignore-netbsd",
+ "ignore-nightly",
+ "ignore-none",
+ "ignore-nto",
+ "ignore-nvptx64",
+ "ignore-nvptx64-nvidia-cuda",
+ "ignore-openbsd",
+ "ignore-pass",
+ "ignore-powerpc",
+ "ignore-powerpc64",
+ "ignore-remote",
+ "ignore-riscv64",
+ "ignore-rustc-debug-assertions",
+ "ignore-rustc_abi-x86-sse2",
+ "ignore-s390x",
+ "ignore-sgx",
+ "ignore-sparc64",
+ "ignore-spirv",
+ "ignore-stable",
+ "ignore-stage1",
+ "ignore-stage2",
+ "ignore-std-debug-assertions",
+ "ignore-test",
+ "ignore-thumb",
+ "ignore-thumbv8m.base-none-eabi",
+ "ignore-thumbv8m.main-none-eabi",
+ "ignore-tvos",
+ "ignore-unix",
+ "ignore-unknown",
+ "ignore-uwp",
+ "ignore-visionos",
+ "ignore-vxworks",
+ "ignore-wasi",
+ "ignore-wasm",
+ "ignore-wasm32",
+ "ignore-wasm32-bare",
+ "ignore-wasm64",
+ "ignore-watchos",
+ "ignore-windows",
+ "ignore-windows-gnu",
+ "ignore-windows-msvc",
+ "ignore-x32",
+ "ignore-x86",
+ "ignore-x86_64",
+ "ignore-x86_64-apple-darwin",
+ "ignore-x86_64-pc-windows-gnu",
+ "ignore-x86_64-unknown-linux-gnu",
+ "incremental",
+ "known-bug",
+ "llvm-cov-flags",
+ "max-llvm-major-version",
+ "min-cdb-version",
+ "min-gdb-version",
+ "min-lldb-version",
+ "min-llvm-version",
+ "min-system-llvm-version",
+ "needs-asm-support",
+ "needs-backends",
+ "needs-crate-type",
+ "needs-deterministic-layouts",
+ "needs-dlltool",
+ "needs-dynamic-linking",
+ "needs-enzyme",
+ "needs-force-clang-based-tests",
+ "needs-git-hash",
+ "needs-llvm-components",
+ "needs-llvm-zstd",
+ "needs-profiler-runtime",
+ "needs-relocation-model-pic",
+ "needs-run-enabled",
+ "needs-rust-lld",
+ "needs-rustc-debug-assertions",
+ "needs-sanitizer-address",
+ "needs-sanitizer-cfi",
+ "needs-sanitizer-dataflow",
+ "needs-sanitizer-hwaddress",
+ "needs-sanitizer-kcfi",
+ "needs-sanitizer-leak",
+ "needs-sanitizer-memory",
+ "needs-sanitizer-memtag",
+ "needs-sanitizer-safestack",
+ "needs-sanitizer-shadow-call-stack",
+ "needs-sanitizer-support",
+ "needs-sanitizer-thread",
+ "needs-std-debug-assertions",
+ "needs-subprocess",
+ "needs-symlink",
+ "needs-target-has-atomic",
+ "needs-target-std",
+ "needs-threads",
+ "needs-unwind",
+ "needs-wasmtime",
+ "needs-xray",
+ "no-auto-check-cfg",
+ "no-prefer-dynamic",
+ "normalize-stderr",
+ "normalize-stderr-32bit",
+ "normalize-stderr-64bit",
+ "normalize-stdout",
+ "only-16bit",
+ "only-32bit",
+ "only-64bit",
+ "only-aarch64",
+ "only-aarch64-apple-darwin",
+ "only-aarch64-unknown-linux-gnu",
+ "only-apple",
+ "only-arm",
+ "only-avr",
+ "only-beta",
+ "only-bpf",
+ "only-cdb",
+ "only-dist",
+ "only-elf",
+ "only-emscripten",
+ "only-gnu",
+ "only-i686-pc-windows-gnu",
+ "only-i686-pc-windows-msvc",
+ "only-i686-unknown-linux-gnu",
+ "only-ios",
+ "only-linux",
+ "only-loongarch32",
+ "only-loongarch64",
+ "only-loongarch64-unknown-linux-gnu",
+ "only-macos",
+ "only-mips",
+ "only-mips64",
+ "only-msp430",
+ "only-msvc",
+ "only-musl",
+ "only-nightly",
+ "only-nvptx64",
+ "only-powerpc",
+ "only-riscv64",
+ "only-rustc_abi-x86-sse2",
+ "only-s390x",
+ "only-sparc",
+ "only-sparc64",
+ "only-stable",
+ "only-thumb",
+ "only-tvos",
+ "only-uefi",
+ "only-unix",
+ "only-visionos",
+ "only-wasm32",
+ "only-wasm32-bare",
+ "only-wasm32-wasip1",
+ "only-watchos",
+ "only-windows",
+ "only-windows-gnu",
+ "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",
+ "only-x86_64-unknown-linux-gnu",
+ "pp-exact",
+ "pretty-compare-only",
+ "pretty-mode",
+ "proc-macro",
+ "reference",
+ "regex-error-pattern",
+ "remap-src-base",
+ "revisions",
+ "run-crash",
+ "run-fail",
+ "run-fail-or-crash",
+ "run-flags",
+ "run-pass",
+ "run-rustfix",
+ "rustc-env",
+ "rustfix-only-machine-applicable",
+ "should-fail",
+ "should-ice",
+ "stderr-per-bitwidth",
+ "test-mir-pass",
+ "unique-doc-out-dir",
+ "unset-exec-env",
+ "unset-rustc-env",
+ // Used by the tidy check `unknown_revision`.
+ "unused-revision-names",
+ // tidy-alphabetical-end
+];
+
+pub(crate) const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[
+ "count",
+ "!count",
+ "files",
+ "!files",
+ "has",
+ "!has",
+ "has-dir",
+ "!has-dir",
+ "hasraw",
+ "!hasraw",
+ "matches",
+ "!matches",
+ "matchesraw",
+ "!matchesraw",
+ "snapshot",
+ "!snapshot",
+];
+
+pub(crate) const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] =
+ &["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"];
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
index a4103c5..ba82412 100644
--- a/src/tools/compiletest/src/runtest/debugger.rs
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -47,10 +47,14 @@ pub fn parse_from(
continue;
};
- if let Some(command) = config.parse_name_value_directive(&line, &command_directive) {
+ if let Some(command) =
+ config.parse_name_value_directive(&line, &command_directive, file, line_no)
+ {
commands.push(command);
}
- if let Some(pattern) = config.parse_name_value_directive(&line, &check_directive) {
+ if let Some(pattern) =
+ config.parse_name_value_directive(&line, &check_directive, file, line_no)
+ {
check_lines.push((line_no, pattern));
}
}
diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml
index e420a450..bcb3165 100644
--- a/src/tools/generate-copyright/Cargo.toml
+++ b/src/tools/generate-copyright/Cargo.toml
@@ -9,7 +9,7 @@
[dependencies]
anyhow = "1.0.65"
askama = "0.14.0"
-cargo_metadata = "0.18.1"
+cargo_metadata = "0.21"
serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.85"
thiserror = "1"
diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs
index 3fae26b..87cd85c 100644
--- a/src/tools/generate-copyright/src/cargo_metadata.rs
+++ b/src/tools/generate-copyright/src/cargo_metadata.rs
@@ -92,7 +92,8 @@ pub fn get_metadata(
continue;
}
// otherwise it's an out-of-tree dependency
- let package_id = Package { name: package.name, version: package.version.to_string() };
+ let package_id =
+ Package { name: package.name.to_string(), version: package.version.to_string() };
output.insert(
package_id,
PackageMetadata {
diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml
index 7123d43..fb5bff3 100644
--- a/src/tools/linkchecker/Cargo.toml
+++ b/src/tools/linkchecker/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "linkchecker"
version = "0.1.0"
-edition = "2021"
+edition = "2024"
[[bin]]
name = "linkchecker"
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index 84cba3f..1dc4572 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -17,12 +17,13 @@
//! should catch the majority of "broken link" cases.
use std::cell::{Cell, RefCell};
+use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
-use std::io::ErrorKind;
+use std::fs;
+use std::iter::once;
use std::path::{Component, Path, PathBuf};
use std::rc::Rc;
use std::time::Instant;
-use std::{env, fs};
use html5ever::tendril::ByteTendril;
use html5ever::tokenizer::{
@@ -110,10 +111,25 @@ macro_rules! t {
};
}
+struct Cli {
+ docs: PathBuf,
+ link_targets_dirs: Vec<PathBuf>,
+}
+
fn main() {
- let docs = env::args_os().nth(1).expect("doc path should be first argument");
- let docs = env::current_dir().unwrap().join(docs);
- let mut checker = Checker { root: docs.clone(), cache: HashMap::new() };
+ let cli = match parse_cli() {
+ Ok(cli) => cli,
+ Err(err) => {
+ eprintln!("error: {err}");
+ usage_and_exit(1);
+ }
+ };
+
+ let mut checker = Checker {
+ root: cli.docs.clone(),
+ link_targets_dirs: cli.link_targets_dirs,
+ cache: HashMap::new(),
+ };
let mut report = Report {
errors: 0,
start: Instant::now(),
@@ -125,7 +141,7 @@ fn main() {
intra_doc_exceptions: 0,
has_broken_urls: false,
};
- checker.walk(&docs, &mut report);
+ checker.walk(&cli.docs, &mut report);
report.report();
if report.errors != 0 {
println!("found some broken links");
@@ -133,8 +149,50 @@ fn main() {
}
}
+fn parse_cli() -> Result<Cli, String> {
+ fn to_absolute_path(arg: &str) -> Result<PathBuf, String> {
+ std::path::absolute(arg).map_err(|e| format!("could not convert to absolute {arg}: {e}"))
+ }
+
+ let mut verbatim = false;
+ let mut docs = None;
+ let mut link_targets_dirs = Vec::new();
+
+ let mut args = std::env::args().skip(1);
+ while let Some(arg) = args.next() {
+ if !verbatim && arg == "--" {
+ verbatim = true;
+ } else if !verbatim && (arg == "-h" || arg == "--help") {
+ usage_and_exit(0)
+ } else if !verbatim && arg == "--link-targets-dir" {
+ link_targets_dirs.push(to_absolute_path(
+ &args.next().ok_or("missing value for --link-targets-dir")?,
+ )?);
+ } else if !verbatim && let Some(value) = arg.strip_prefix("--link-targets-dir=") {
+ link_targets_dirs.push(to_absolute_path(value)?);
+ } else if !verbatim && arg.starts_with('-') {
+ return Err(format!("unknown flag: {arg}"));
+ } else if docs.is_none() {
+ docs = Some(arg);
+ } else {
+ return Err("too many positional arguments".into());
+ }
+ }
+
+ Ok(Cli {
+ docs: to_absolute_path(&docs.ok_or("missing first positional argument")?)?,
+ link_targets_dirs,
+ })
+}
+
+fn usage_and_exit(code: i32) -> ! {
+ eprintln!("usage: linkchecker PATH [--link-targets-dir=PATH ...]");
+ std::process::exit(code)
+}
+
struct Checker {
root: PathBuf,
+ link_targets_dirs: Vec<PathBuf>,
cache: Cache,
}
@@ -420,37 +478,34 @@ fn check_intra_doc_links(
/// Load a file from disk, or from the cache if available.
fn load_file(&mut self, file: &Path, report: &mut Report) -> (String, &FileEntry) {
- // https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
- #[cfg(windows)]
- const ERROR_INVALID_NAME: i32 = 123;
-
let pretty_path =
file.strip_prefix(&self.root).unwrap_or(file).to_str().unwrap().to_string();
- let entry =
- self.cache.entry(pretty_path.clone()).or_insert_with(|| match fs::metadata(file) {
+ for base in once(&self.root).chain(self.link_targets_dirs.iter()) {
+ let entry = self.cache.entry(pretty_path.clone());
+ if let Entry::Occupied(e) = &entry
+ && !matches!(e.get(), FileEntry::Missing)
+ {
+ break;
+ }
+
+ let file = base.join(&pretty_path);
+ entry.insert_entry(match fs::metadata(&file) {
Ok(metadata) if metadata.is_dir() => FileEntry::Dir,
Ok(_) => {
if file.extension().and_then(|s| s.to_str()) != Some("html") {
FileEntry::OtherFile
} else {
report.html_files += 1;
- load_html_file(file, report)
+ load_html_file(&file, report)
}
}
- Err(e) if e.kind() == ErrorKind::NotFound => FileEntry::Missing,
- Err(e) => {
- // If a broken intra-doc link contains `::`, on windows, it will cause `ERROR_INVALID_NAME` rather than `NotFound`.
- // Explicitly check for that so that the broken link can be allowed in `LINKCHECK_EXCEPTIONS`.
- #[cfg(windows)]
- if e.raw_os_error() == Some(ERROR_INVALID_NAME)
- && file.as_os_str().to_str().map_or(false, |s| s.contains("::"))
- {
- return FileEntry::Missing;
- }
- panic!("unexpected read error for {}: {}", file.display(), e);
- }
+ Err(e) if is_not_found_error(&file, &e) => FileEntry::Missing,
+ Err(e) => panic!("unexpected read error for {}: {}", file.display(), e),
});
+ }
+
+ let entry = self.cache.get(&pretty_path).unwrap();
(pretty_path, entry)
}
}
@@ -629,3 +684,16 @@ fn parse_ids(ids: &mut HashSet<String>, file: &str, source: &str, report: &mut R
ids.insert(encoded);
}
}
+
+fn is_not_found_error(path: &Path, error: &std::io::Error) -> bool {
+ // https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
+ const WINDOWS_ERROR_INVALID_NAME: i32 = 123;
+
+ error.kind() == std::io::ErrorKind::NotFound
+ // If a broken intra-doc link contains `::`, on windows, it will cause `ERROR_INVALID_NAME`
+ // rather than `NotFound`. Explicitly check for that so that the broken link can be allowed
+ // in `LINKCHECK_EXCEPTIONS`.
+ || (cfg!(windows)
+ && error.raw_os_error() == Some(WINDOWS_ERROR_INVALID_NAME)
+ && path.as_os_str().to_str().map_or(false, |s| s.contains("::")))
+}
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 11c0f08..c47f969 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -45,11 +45,17 @@
os: macos-latest
- host_target: i686-pc-windows-msvc
os: windows-latest
+ - host_target: aarch64-pc-windows-msvc
+ os: windows-11-arm
runs-on: ${{ matrix.os }}
env:
HOST_TARGET: ${{ matrix.host_target }}
steps:
- uses: actions/checkout@v4
+ - name: apt update
+ if: ${{ startsWith(matrix.os, 'ubuntu') }}
+ # The runners seem to have outdated apt repos sometimes
+ run: sudo apt update
- name: install qemu
if: ${{ matrix.qemu }}
run: sudo apt install qemu-user qemu-user-binfmt
@@ -63,6 +69,12 @@
sudo apt update
# Install needed packages
sudo apt install $(echo "libatomic1: zlib1g-dev:" | sed 's/:/:${{ matrix.multiarch }}/g')
+ - name: Install rustup on Windows ARM
+ if: ${{ matrix.os == 'windows-11-arm' }}
+ run: |
+ curl -LOs https://static.rust-lang.org/rustup/dist/aarch64-pc-windows-msvc/rustup-init.exe
+ ./rustup-init.exe -y --no-modify-path
+ echo "$USERPROFILE/.cargo/bin" >> "$GITHUB_PATH"
- uses: ./.github/workflows/setup
with:
toolchain_flags: "--host ${{ matrix.host_target }}"
@@ -147,35 +159,48 @@
- uses: actions/checkout@v4
with:
fetch-depth: 256 # get a bit more of the history
- - name: install josh-proxy
- run: cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04
+ - name: install josh-sync
+ run: cargo +stable install --locked --git https://github.com/rust-lang/josh-sync
- name: setup bot git name and email
run: |
git config --global user.name 'The Miri Cronjob Bot'
git config --global user.email 'miri@cron.bot'
- name: Install nightly toolchain
run: rustup toolchain install nightly --profile minimal
- - name: get changes from rustc
- run: ./miri rustc-pull
- name: Install rustup-toolchain-install-master
run: cargo install -f rustup-toolchain-install-master
- - name: format changes (if any)
- run: |
- ./miri toolchain
- ./miri fmt --check || (./miri fmt && git commit -am "fmt")
- name: Push changes to a branch and create PR
run: |
- # `git diff --exit-code` "succeeds" if the diff is empty.
- if git diff --exit-code HEAD^; then echo "Nothing changed in rustc, skipping PR"; exit 0; fi
- # The diff is non-empty, create a PR.
+ # Make it easier to see what happens.
+ set -x
+ # Temporarily disable early exit to examine the status code of rustc-josh-sync
+ set +e
+ rustc-josh-sync pull
+ exitcode=$?
+ set -e
+
+ # If there were no changes to pull, rustc-josh-sync returns status code 2.
+ # In that case, skip the rest of the job.
+ if [ $exitcode -eq 2 ]; then
+ echo "Nothing changed in rustc, skipping PR"
+ exit 0
+ elif [ $exitcode -ne 0 ]; then
+ # If return code was not 0 or 2, rustc-josh-sync actually failed
+ echo "error: rustc-josh-sync failed"
+ exit ${exitcode}
+ fi
+
+ # Format changes
+ ./miri toolchain
+ ./miri fmt --check || (./miri fmt && git commit -am "fmt")
+
+ # Create a PR
BRANCH="rustup-$(date -u +%Y-%m-%d)"
git switch -c $BRANCH
git push -u origin $BRANCH
gh pr create -B master --title 'Automatic Rustup' --body 'Please close and re-open this PR to trigger CI, then enable auto-merge.'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }}
- ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }}
cron-fail-notify:
name: cronjob failure notification
@@ -198,7 +223,7 @@
It would appear that the [Miri cron job build]('"https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"') failed.
This likely means that rustc changed the miri directory and
- we now need to do a [`./miri rustc-pull`](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#importing-changes-from-the-rustc-repo).
+ we now need to do a [`rustc-josh-sync pull`](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#importing-changes-from-the-rustc-repo).
Would you mind investigating this issue?
diff --git a/src/tools/miri/.gitignore b/src/tools/miri/.gitignore
index ed2d0ba..4a238dc 100644
--- a/src/tools/miri/.gitignore
+++ b/src/tools/miri/.gitignore
@@ -1,5 +1,4 @@
target
-/doc
tex/*/out
*.dot
*.out
diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md
index 637c0dd..7d78fdd 100644
--- a/src/tools/miri/CONTRIBUTING.md
+++ b/src/tools/miri/CONTRIBUTING.md
@@ -297,14 +297,14 @@
## Advanced topic: Syncing with the rustc repo
-We use the [`josh` proxy](https://github.com/josh-project/josh) to transmit changes between the
+We use the [`josh-sync`](https://github.com/rust-lang/josh-sync) tool to transmit changes between the
rustc and Miri repositories. You can install it as follows:
```sh
-cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04
+cargo install --locked --git https://github.com/rust-lang/josh-sync
```
-Josh will automatically be started and stopped by `./miri`.
+The commands below will automatically install and manage the [Josh](https://github.com/josh-project/josh) proxy that performs the actual work.
### Importing changes from the rustc repo
@@ -312,10 +312,12 @@
We assume we start on an up-to-date master branch in the Miri repo.
+1) First, create a branch for the pull, e.g. `git checkout -b rustup`
+2) Then run the following:
```sh
# Fetch and merge rustc side of the history. Takes ca 5 min the first time.
# This will also update the `rustc-version` file.
-./miri rustc-pull
+rustc-josh-sync pull
# Update local toolchain and apply formatting.
./miri toolchain && ./miri fmt
git commit -am "rustup"
@@ -328,12 +330,12 @@
### Exporting changes to the rustc repo
-We will use the josh proxy to push to your fork of rustc. Run the following in the Miri repo,
+We will use the `josh-sync` tool to push to your fork of rustc. Run the following in the Miri repo,
assuming we are on an up-to-date master branch:
```sh
# Push the Miri changes to your rustc fork (substitute your github handle for YOUR_NAME).
-./miri rustc-push YOUR_NAME miri
+rustc-josh-sync push miri YOUR_NAME
```
This will create a new branch called `miri` in your fork, and the output should include a link that
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index 0af4181..b46f0f8 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -166,10 +166,12 @@
[[package]]
name = "cc"
-version = "1.2.30"
+version = "1.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7"
+checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
dependencies = [
+ "jobserver",
+ "libc",
"shlex",
]
@@ -215,6 +217,52 @@
]
[[package]]
+name = "clap"
+version = "4.5.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9"
+dependencies = [
+ "clap_builder",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d"
+dependencies = [
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
+
+[[package]]
+name = "cmake"
+version = "0.1.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "codespan-reporting"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
+dependencies = [
+ "serde",
+ "termcolor",
+ "unicode-width 0.2.1",
+]
+
+[[package]]
name = "color-eyre"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -314,6 +362,68 @@
]
[[package]]
+name = "cxx"
+version = "1.0.161"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3523cc02ad831111491dd64b27ad999f1ae189986728e477604e61b81f828df"
+dependencies = [
+ "cc",
+ "cxxbridge-cmd",
+ "cxxbridge-flags",
+ "cxxbridge-macro",
+ "foldhash",
+ "link-cplusplus",
+]
+
+[[package]]
+name = "cxx-build"
+version = "1.0.161"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "212b754247a6f07b10fa626628c157593f0abf640a3dd04cce2760eca970f909"
+dependencies = [
+ "cc",
+ "codespan-reporting",
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "scratch",
+ "syn",
+]
+
+[[package]]
+name = "cxxbridge-cmd"
+version = "1.0.161"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f426a20413ec2e742520ba6837c9324b55ffac24ead47491a6e29f933c5b135a"
+dependencies = [
+ "clap",
+ "codespan-reporting",
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "cxxbridge-flags"
+version = "1.0.161"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a258b6069020b4e5da6415df94a50ee4f586a6c38b037a180e940a43d06a070d"
+
+[[package]]
+name = "cxxbridge-macro"
+version = "1.0.161"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8dec184b52be5008d6eaf7e62fc1802caf1ad1227d11b3b7df2c409c7ffc3f4"
+dependencies = [
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
+[[package]]
name = "directories"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -335,12 +445,29 @@
]
[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "encode_unicode"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
name = "errno"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -373,6 +500,21 @@
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
+name = "foldhash"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -383,6 +525,17 @@
]
[[package]]
+name = "genmc-sys"
+version = "0.1.0"
+dependencies = [
+ "cc",
+ "cmake",
+ "cxx",
+ "cxx-build",
+ "git2",
+]
+
+[[package]]
name = "getrandom"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -412,12 +565,150 @@
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
+name = "git2"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110"
+dependencies = [
+ "bitflags",
+ "libc",
+ "libgit2-sys",
+ "log",
+ "openssl-probe",
+ "openssl-sys",
+ "url",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.15.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
+
+[[package]]
+name = "icu_collections"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
+
+[[package]]
+name = "icu_properties"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "potential_utf",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
+
+[[package]]
+name = "icu_provider"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "idna"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
name = "indenter"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]]
+name = "indexmap"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
name = "indicatif"
version = "0.17.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -464,6 +755,16 @@
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
+name = "jobserver"
+version = "0.1.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
+dependencies = [
+ "getrandom 0.3.3",
+ "libc",
+]
+
+[[package]]
name = "js-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -511,6 +812,19 @@
]
[[package]]
+name = "libgit2-sys"
+version = "0.18.2+1.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222"
+dependencies = [
+ "cc",
+ "libc",
+ "libz-sys",
+ "openssl-sys",
+ "pkg-config",
+]
+
+[[package]]
name = "libloading"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -531,12 +845,39 @@
]
[[package]]
+name = "libz-sys"
+version = "1.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "link-cplusplus"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212"
+dependencies = [
+ "cc",
+]
+
+[[package]]
name = "linux-raw-sys"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
+name = "litemap"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
+
+[[package]]
name = "lock_api"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -612,6 +953,7 @@
"chrono-tz",
"colored 3.0.0",
"directories",
+ "genmc-sys",
"getrandom 0.3.3",
"ipc-channel",
"libc",
@@ -673,6 +1015,24 @@
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
+name = "openssl-probe"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -723,6 +1083,12 @@
]
[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
name = "perf-event-open-sys"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -756,12 +1122,27 @@
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
+name = "pkg-config"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+
+[[package]]
name = "portable-atomic"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
[[package]]
+name = "potential_utf"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -947,6 +1328,12 @@
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
+name = "scratch"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52"
+
+[[package]]
name = "semver"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1026,6 +1413,18 @@
]
[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
name = "syn"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1037,6 +1436,17 @@
]
[[package]]
+name = "synstructure"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "tempfile"
version = "3.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1050,6 +1460,15 @@
]
[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1109,6 +1528,16 @@
]
[[package]]
+name = "tinystr"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
name = "tracing"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1200,6 +1629,23 @@
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
[[package]]
+name = "url"
+version = "2.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
name = "uuid"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1217,6 +1663,12 @@
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1306,6 +1758,15 @@
]
[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
name = "windows"
version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1525,6 +1986,36 @@
]
[[package]]
+name = "writeable"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
+
+[[package]]
+name = "yoke"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
name = "zerocopy"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1543,3 +2034,57 @@
"quote",
"syn",
]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "zerotrie"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index d293af5..91dadf7 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -48,6 +48,10 @@
ipc-channel = { version = "0.20.0", optional = true }
capstone = { version = "0.13", optional = true }
+# FIXME(genmc,macos): Add `target_os = "macos"` once https://github.com/dtolnay/cxx/issues/1535 is fixed.
+[target.'cfg(all(target_os = "linux", target_pointer_width = "64", target_endian = "little"))'.dependencies]
+genmc-sys = { path = "./genmc-sys/", version = "0.1.0", optional = true }
+
[dev-dependencies]
ui_test = "0.30.2"
colored = "3"
@@ -66,7 +70,7 @@
[features]
default = ["stack-cache", "native-lib"]
-genmc = []
+genmc = ["dep:genmc-sys"] # this enables a GPL dependency!
stack-cache = []
stack-cache-consistency-check = ["stack-cache"]
tracing = ["serde_json"]
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index b72b974..efb9053 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -1,9 +1,9 @@
//! Implements the various phases of `cargo miri run/test`.
use std::env;
-use std::fs::{self, File};
+use std::fs::File;
use std::io::BufReader;
-use std::path::{Path, PathBuf};
+use std::path::{self, Path, PathBuf};
use std::process::Command;
use rustc_version::VersionMeta;
@@ -222,12 +222,12 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
// that to be the Miri driver, but acting as rustc, in host mode.
//
// In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc
- // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that
+ // or TARGET_RUNNER invocations, so we make it absolute to make it exceedingly unlikely that
// there would be a collision with other invocations of cargo-miri (as rustdoc or as runner). We
// explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the
// bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host
// builds.
- cmd.env("RUSTC", fs::canonicalize(find_miri()).unwrap());
+ cmd.env("RUSTC", path::absolute(find_miri()).unwrap());
// In case we get invoked as RUSTC without the wrapper, let's be a host rustc. This makes no
// sense for cross-interpretation situations, but without the wrapper, this will use the host
// sysroot, so asking it to behave like a target build makes even less sense.
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 5767d17..b66530e 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -142,7 +142,6 @@
# Host
GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
# Extra tier 1
- MANY_SEEDS=64 TEST_TARGET=i686-unknown-linux-gnu run_tests
MANY_SEEDS=64 TEST_TARGET=x86_64-apple-darwin run_tests
MANY_SEEDS=64 TEST_TARGET=x86_64-pc-windows-gnu run_tests
;;
@@ -161,8 +160,6 @@
aarch64-unknown-linux-gnu)
# Host
GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
- # Extra tier 1 candidate
- MANY_SEEDS=64 TEST_TARGET=aarch64-pc-windows-msvc run_tests
# Extra tier 2
MANY_SEEDS=16 TEST_TARGET=arm-unknown-linux-gnueabi run_tests # 32bit ARM
MANY_SEEDS=16 TEST_TARGET=aarch64-pc-windows-gnullvm run_tests # gnullvm ABI
@@ -189,13 +186,20 @@
;;
i686-pc-windows-msvc)
# Host
- # Without GC_STRESS as this is the slowest runner.
+ # Without GC_STRESS as this is a very slow runner.
MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 run_tests
# Extra tier 1
# We really want to ensure a Linux target works on a Windows host,
# and a 64bit target works on a 32bit host.
TEST_TARGET=x86_64-unknown-linux-gnu run_tests
;;
+ aarch64-pc-windows-msvc)
+ # Host
+ # Without GC_STRESS as this is a very slow runner.
+ MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
+ # Extra tier 1
+ MANY_SEEDS=64 TEST_TARGET=i686-unknown-linux-gnu run_tests
+ ;;
*)
echo "FATAL: unknown host target: $HOST_TARGET"
exit 1
diff --git a/src/tools/miri/doc/genmc.md b/src/tools/miri/doc/genmc.md
new file mode 100644
index 0000000..5aabe90
--- /dev/null
+++ b/src/tools/miri/doc/genmc.md
@@ -0,0 +1,62 @@
+# **(WIP)** Documentation for Miri-GenMC
+
+[GenMC](https://github.com/MPI-SWS/genmc) is a stateless model checker for exploring concurrent executions of a program.
+Miri-GenMC integrates that model checker into Miri.
+
+**NOTE: Currently, no actual GenMC functionality is part of Miri, this is still WIP.**
+
+<!-- FIXME(genmc): add explanation. -->
+
+## Usage
+
+**IMPORTANT: The license of GenMC and thus the `genmc-sys` crate in the Miri repo is currently "GPL-3.0-or-later", so a binary produced with the `genmc` feature is subject to the requirements of the GPL. As long as that remains the case, the `genmc` feature of Miri is OFF-BY-DEFAULT and must be OFF for all Miri releases.**
+
+For testing/developing Miri-GenMC (while keeping in mind the licensing issues):
+- clone the Miri repo.
+- build Miri-GenMC with `./miri build --features=genmc`.
+- OR: install Miri-GenMC in the current system with `./miri install --features=genmc`
+
+Basic usage:
+```shell
+MIRIFLAGS="-Zmiri-genmc" cargo miri run
+```
+
+<!-- FIXME(genmc): explain options. -->
+
+<!-- FIXME(genmc): explain Miri-GenMC specific functions. -->
+
+## Tips
+
+<!-- FIXME(genmc): add tips for using Miri-GenMC more efficiently. -->
+
+## Limitations
+
+Some or all of these limitations might get removed in the future:
+
+- Borrow tracking is currently incompatible (stacked/tree borrows).
+- Only Linux is supported for now.
+- No support for 32-bit or big-endian targets.
+- No cross-target interpretation.
+
+<!-- FIXME(genmc): document remaining limitations -->
+
+## Development
+
+GenMC is written in C++, which complicates development a bit.
+The prerequisites for building Miri-GenMC are:
+- A compiler with C++23 support.
+- LLVM developments headers and clang.
+ <!-- FIXME(genmc,llvm): remove once LLVM dependency is no longer required. -->
+
+The actual code for GenMC is not contained in the Miri repo itself, but in a [separate GenMC repo](https://github.com/MPI-SWS/genmc) (with its own maintainers).
+These sources need to be available to build Miri-GenMC.
+The process for obtaining them is as follows:
+- By default, a fixed commit of GenMC is downloaded to `genmc-sys/genmc-src` and built automatically.
+ (The commit is determined by `GENMC_COMMIT` in `genmc-sys/build.rs`.)
+- If you want to overwrite that, set the `GENMC_SRC_PATH` environment variable to a path that contains the GenMC sources.
+ If you place this directory inside the Miri folder, it is recommended to call it `genmc-src` as that tells `./miri fmt` to avoid
+ formatting the Rust files inside that folder.
+
+<!-- FIXME(genmc): explain how submitting code to GenMC should be handled. -->
+
+<!-- FIXME(genmc): explain development. -->
diff --git a/src/tools/miri/etc/rust_analyzer_helix.toml b/src/tools/miri/etc/rust_analyzer_helix.toml
index 91e4070..c46b246 100644
--- a/src/tools/miri/etc/rust_analyzer_helix.toml
+++ b/src/tools/miri/etc/rust_analyzer_helix.toml
@@ -5,6 +5,7 @@
linkedProjects = [
"Cargo.toml",
"cargo-miri/Cargo.toml",
+ "genmc-sys/Cargo.toml",
"miri-script/Cargo.toml",
]
diff --git a/src/tools/miri/etc/rust_analyzer_vscode.json b/src/tools/miri/etc/rust_analyzer_vscode.json
index 6917c6a..8e647f5 100644
--- a/src/tools/miri/etc/rust_analyzer_vscode.json
+++ b/src/tools/miri/etc/rust_analyzer_vscode.json
@@ -3,6 +3,7 @@
"rust-analyzer.linkedProjects": [
"Cargo.toml",
"cargo-miri/Cargo.toml",
+ "genmc-sys/Cargo.toml",
"miri-script/Cargo.toml",
],
"rust-analyzer.check.invocationStrategy": "once",
diff --git a/src/tools/miri/genmc-sys/.gitignore b/src/tools/miri/genmc-sys/.gitignore
new file mode 100644
index 0000000..276a053
--- /dev/null
+++ b/src/tools/miri/genmc-sys/.gitignore
@@ -0,0 +1 @@
+genmc-src*/
diff --git a/src/tools/miri/genmc-sys/Cargo.toml b/src/tools/miri/genmc-sys/Cargo.toml
new file mode 100644
index 0000000..737ab90
--- /dev/null
+++ b/src/tools/miri/genmc-sys/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+authors = ["Miri Team"]
+# The parts in this repo are MIT OR Apache-2.0, but we are linking in
+# code from https://github.com/MPI-SWS/genmc which is GPL-3.0-or-later.
+license = "(MIT OR Apache-2.0) AND GPL-3.0-or-later"
+name = "genmc-sys"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+cxx = { version = "1.0.160", features = ["c++20"] }
+
+[build-dependencies]
+cc = "1.2.16"
+cmake = "0.1.54"
+git2 = { version = "0.20.2", default-features = false, features = ["https"] }
+cxx-build = { version = "1.0.160", features = ["parallel"] }
diff --git a/src/tools/miri/genmc-sys/build.rs b/src/tools/miri/genmc-sys/build.rs
new file mode 100644
index 0000000..479a3bd
--- /dev/null
+++ b/src/tools/miri/genmc-sys/build.rs
@@ -0,0 +1,269 @@
+use std::path::{Path, PathBuf};
+use std::str::FromStr;
+
+// Build script for running Miri with GenMC.
+// Check out doc/genmc.md for more info.
+
+/// Path where the downloaded GenMC repository will be stored (relative to the `genmc-sys` directory).
+/// Note that this directory is *not* cleaned up automatically by `cargo clean`.
+const GENMC_DOWNLOAD_PATH: &str = "./genmc-src/";
+
+/// Name of the library of the GenMC model checker.
+const GENMC_MODEL_CHECKER: &str = "genmc_lib";
+
+/// Path where the `cxx_bridge!` macro is used to define the Rust-C++ interface.
+const RUST_CXX_BRIDGE_FILE_PATH: &str = "src/lib.rs";
+
+/// The profile with which to build GenMC.
+const GENMC_CMAKE_PROFILE: &str = "RelWithDebInfo";
+
+mod downloading {
+ use std::path::PathBuf;
+ use std::str::FromStr;
+
+ use git2::{Commit, Oid, Remote, Repository, StatusOptions};
+
+ use super::GENMC_DOWNLOAD_PATH;
+
+ /// The GenMC repository the we get our commit from.
+ pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/MPI-SWS/genmc.git";
+ /// The GenMC commit we depend on. It must be available on the specified GenMC repository.
+ pub(crate) const GENMC_COMMIT: &str = "3438dd2c1202cd4a47ed7881d099abf23e4167ab";
+
+ pub(crate) fn download_genmc() -> PathBuf {
+ let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH);
+ let commit_oid = Oid::from_str(GENMC_COMMIT).expect("Commit should be valid.");
+
+ match Repository::open(&genmc_download_path) {
+ Ok(repo) => {
+ assert_repo_unmodified(&repo);
+ let commit = update_local_repo(&repo, commit_oid);
+ checkout_commit(&repo, &commit);
+ }
+ Err(_) => {
+ let repo = clone_remote_repo(&genmc_download_path);
+ let Ok(commit) = repo.find_commit(commit_oid) else {
+ panic!(
+ "Cloned GenMC repository does not contain required commit '{GENMC_COMMIT}'"
+ );
+ };
+ checkout_commit(&repo, &commit);
+ }
+ };
+
+ genmc_download_path
+ }
+
+ fn get_remote(repo: &Repository) -> Remote<'_> {
+ let remote = repo.find_remote("origin").unwrap_or_else(|e| {
+ panic!(
+ "Could not load commit ({GENMC_COMMIT}) from remote repository '{GENMC_GITHUB_URL}'. Error: {e}"
+ );
+ });
+
+ // Ensure that the correct remote URL is set.
+ let remote_url = remote.url();
+ if let Some(remote_url) = remote_url
+ && remote_url == GENMC_GITHUB_URL
+ {
+ return remote;
+ }
+
+ // Update remote URL.
+ println!(
+ "cargo::warning=GenMC repository remote URL has changed from '{remote_url:?}' to '{GENMC_GITHUB_URL}'"
+ );
+ repo.remote_set_url("origin", GENMC_GITHUB_URL)
+ .expect("cannot rename url of remote 'origin'");
+
+ // Reacquire the `Remote`, since `remote_set_url` doesn't update Remote objects already in memory.
+ repo.find_remote("origin").unwrap()
+ }
+
+ // Check if the required commit exists already, otherwise try fetching it.
+ fn update_local_repo(repo: &Repository, commit_oid: Oid) -> Commit<'_> {
+ repo.find_commit(commit_oid).unwrap_or_else(|_find_error| {
+ println!("GenMC repository at path '{GENMC_DOWNLOAD_PATH}' does not contain commit '{GENMC_COMMIT}'.");
+ // The commit is not in the checkout. Try `git fetch` and hope that we find the commit then.
+ let mut remote = get_remote(repo);
+ remote.fetch(&[GENMC_COMMIT], None, None).expect("Failed to fetch from remote.");
+
+ repo.find_commit(commit_oid)
+ .expect("Remote repository should contain expected commit")
+ })
+ }
+
+ fn clone_remote_repo(genmc_download_path: &PathBuf) -> Repository {
+ Repository::clone(GENMC_GITHUB_URL, &genmc_download_path).unwrap_or_else(|e| {
+ panic!("Cannot clone GenMC repo from '{GENMC_GITHUB_URL}': {e:?}");
+ })
+ }
+
+ /// Set the state of the repo to a specific commit
+ fn checkout_commit(repo: &Repository, commit: &Commit<'_>) {
+ repo.checkout_tree(commit.as_object(), None).expect("Failed to checkout");
+ repo.set_head_detached(commit.id()).expect("Failed to set HEAD");
+ println!("Successfully set checked out commit {commit:?}");
+ }
+
+ /// Check that the downloaded repository is unmodified.
+ /// If it is modified, explain that it shouldn't be, and hint at how to do local development with GenMC.
+ /// We don't overwrite any changes made to the directory, to prevent data loss.
+ fn assert_repo_unmodified(repo: &Repository) {
+ let statuses = repo
+ .statuses(Some(
+ StatusOptions::new()
+ .include_untracked(true)
+ .include_ignored(false)
+ .include_unmodified(false),
+ ))
+ .expect("should be able to get repository status");
+ if statuses.is_empty() {
+ return;
+ }
+
+ panic!(
+ "Downloaded GenMC repository at path '{GENMC_DOWNLOAD_PATH}' has been modified. Please undo any changes made, or delete the '{GENMC_DOWNLOAD_PATH}' directory to have it downloaded again.\n\
+ HINT: For local development, set the environment variable 'GENMC_SRC_PATH' to the path of a GenMC repository."
+ );
+ }
+}
+
+// FIXME(genmc,llvm): Remove once the LLVM dependency of the GenMC model checker is removed.
+/// The linked LLVM version is in the generated `config.h`` file, which we parse and use to link to LLVM.
+/// Returns c++ compiler definitions required for building with/including LLVM, and the include path for LLVM headers.
+fn link_to_llvm(config_file: &Path) -> (String, String) {
+ /// Search a string for a line matching `//@VARIABLE_NAME: VARIABLE CONTENT`
+ fn extract_value<'a>(input: &'a str, name: &str) -> Option<&'a str> {
+ input
+ .lines()
+ .find_map(|line| line.strip_prefix("//@")?.strip_prefix(name)?.strip_prefix(": "))
+ }
+
+ let file_content = std::fs::read_to_string(&config_file).unwrap_or_else(|err| {
+ panic!("GenMC config file ({}) should exist, but got errror {err:?}", config_file.display())
+ });
+
+ let llvm_definitions = extract_value(&file_content, "LLVM_DEFINITIONS")
+ .expect("Config file should contain LLVM_DEFINITIONS");
+ let llvm_include_dirs = extract_value(&file_content, "LLVM_INCLUDE_DIRS")
+ .expect("Config file should contain LLVM_INCLUDE_DIRS");
+ let llvm_library_dir = extract_value(&file_content, "LLVM_LIBRARY_DIR")
+ .expect("Config file should contain LLVM_LIBRARY_DIR");
+ let llvm_config_path = extract_value(&file_content, "LLVM_CONFIG_PATH")
+ .expect("Config file should contain LLVM_CONFIG_PATH");
+
+ // Add linker search path.
+ let lib_dir = PathBuf::from_str(llvm_library_dir).unwrap();
+ println!("cargo::rustc-link-search=native={}", lib_dir.display());
+
+ // Add libraries to link.
+ let output = std::process::Command::new(llvm_config_path)
+ .arg("--libs") // Print the libraries to link to (space-separated list)
+ .output()
+ .expect("failed to execute llvm-config");
+ let llvm_link_libs =
+ String::try_from(output.stdout).expect("llvm-config output should be a valid string");
+
+ for link_lib in llvm_link_libs.trim().split(" ") {
+ let link_lib =
+ link_lib.strip_prefix("-l").expect("Linker parameter should start with \"-l\"");
+ println!("cargo::rustc-link-lib=dylib={link_lib}");
+ }
+
+ (llvm_definitions.to_string(), llvm_include_dirs.to_string())
+}
+
+/// Build the GenMC model checker library and the Rust-C++ interop library with cxx.rs
+fn compile_cpp_dependencies(genmc_path: &Path) {
+ // Part 1:
+ // Compile the GenMC library using cmake.
+
+ let cmakelists_path = genmc_path.join("CMakeLists.txt");
+
+ // FIXME(genmc,cargo): Switch to using `CARGO_CFG_DEBUG_ASSERTIONS` once https://github.com/rust-lang/cargo/issues/15760 is completed.
+ // Enable/disable additional debug checks, prints and options for GenMC, based on the Rust profile (debug/release)
+ let enable_genmc_debug = matches!(std::env::var("PROFILE").as_deref().unwrap(), "debug");
+
+ let mut config = cmake::Config::new(cmakelists_path);
+ config.profile(GENMC_CMAKE_PROFILE);
+ config.define("GENMC_DEBUG", if enable_genmc_debug { "ON" } else { "OFF" });
+
+ // The actual compilation happens here:
+ let genmc_install_dir = config.build();
+
+ // Add the model checker library to be linked and tell rustc where to find it:
+ let cmake_lib_dir = genmc_install_dir.join("lib").join("genmc");
+ println!("cargo::rustc-link-search=native={}", cmake_lib_dir.display());
+ println!("cargo::rustc-link-lib=static={GENMC_MODEL_CHECKER}");
+
+ // FIXME(genmc,llvm): Remove once the LLVM dependency of the GenMC model checker is removed.
+ let config_file = genmc_install_dir.join("include").join("genmc").join("config.h");
+ let (llvm_definitions, llvm_include_dirs) = link_to_llvm(&config_file);
+
+ // Part 2:
+ // Compile the cxx_bridge (the link between the Rust and C++ code).
+
+ let genmc_include_dir = genmc_install_dir.join("include").join("genmc");
+
+ // FIXME(genmc,llvm): remove once LLVM dependency is removed.
+ // These definitions are parsed into a cmake list and then printed to the config.h file, so they are ';' separated.
+ let definitions = llvm_definitions.split(";");
+
+ let mut bridge = cxx_build::bridge("src/lib.rs");
+ // FIXME(genmc,cmake): Remove once the GenMC debug setting is available in the config.h file.
+ if enable_genmc_debug {
+ bridge.define("ENABLE_GENMC_DEBUG", None);
+ }
+ for definition in definitions {
+ bridge.flag(definition);
+ }
+ bridge
+ .opt_level(2)
+ .debug(true) // Same settings that GenMC uses (default for cmake `RelWithDebInfo`)
+ .warnings(false) // NOTE: enabling this produces a lot of warnings.
+ .std("c++23")
+ .include(genmc_include_dir)
+ .include(llvm_include_dirs)
+ .include("./src_cpp")
+ .file("./src_cpp/MiriInterface.hpp")
+ .file("./src_cpp/MiriInterface.cpp")
+ .compile("genmc_interop");
+
+ // Link the Rust-C++ interface library generated by cxx_build:
+ println!("cargo::rustc-link-lib=static=genmc_interop");
+}
+
+fn main() {
+ // Make sure we don't accidentally distribute a binary with GPL code.
+ if option_env!("RUSTC_STAGE").is_some() {
+ panic!(
+ "genmc should not be enabled in the rustc workspace since it includes a GPL dependency"
+ );
+ }
+
+ // Select which path to use for the GenMC repo:
+ let genmc_path = if let Ok(genmc_src_path) = std::env::var("GENMC_SRC_PATH") {
+ let genmc_src_path =
+ PathBuf::from_str(&genmc_src_path).expect("GENMC_SRC_PATH should contain a valid path");
+ assert!(
+ genmc_src_path.exists(),
+ "GENMC_SRC_PATH={} does not exist!",
+ genmc_src_path.display()
+ );
+ genmc_src_path
+ } else {
+ downloading::download_genmc()
+ };
+
+ // Build all required components:
+ compile_cpp_dependencies(&genmc_path);
+
+ // Only rebuild if anything changes:
+ // Note that we don't add the downloaded GenMC repo, since that should never be modified
+ // manually. Adding that path here would also trigger an unnecessary rebuild after the repo is
+ // cloned (since cargo detects that as a file modification).
+ println!("cargo::rerun-if-changed={RUST_CXX_BRIDGE_FILE_PATH}");
+ println!("cargo::rerun-if-changed=./src");
+ println!("cargo::rerun-if-changed=./src_cpp");
+}
diff --git a/src/tools/miri/genmc-sys/src/lib.rs b/src/tools/miri/genmc-sys/src/lib.rs
new file mode 100644
index 0000000..ab46d72
--- /dev/null
+++ b/src/tools/miri/genmc-sys/src/lib.rs
@@ -0,0 +1,30 @@
+pub use self::ffi::*;
+
+impl Default for GenmcParams {
+ fn default() -> Self {
+ Self {
+ print_random_schedule_seed: false,
+ do_symmetry_reduction: false,
+ // FIXME(GenMC): Add defaults for remaining parameters
+ }
+ }
+}
+
+#[cxx::bridge]
+mod ffi {
+ /// Parameters that will be given to GenMC for setting up the model checker.
+ /// (The fields of this struct are visible to both Rust and C++)
+ #[derive(Clone, Debug)]
+ struct GenmcParams {
+ pub print_random_schedule_seed: bool,
+ pub do_symmetry_reduction: bool,
+ // FIXME(GenMC): Add remaining parameters.
+ }
+ unsafe extern "C++" {
+ include!("MiriInterface.hpp");
+
+ type MiriGenMCShim;
+
+ fn createGenmcHandle(config: &GenmcParams) -> UniquePtr<MiriGenMCShim>;
+ }
+}
diff --git a/src/tools/miri/genmc-sys/src_cpp/MiriInterface.cpp b/src/tools/miri/genmc-sys/src_cpp/MiriInterface.cpp
new file mode 100644
index 0000000..0827bb3
--- /dev/null
+++ b/src/tools/miri/genmc-sys/src_cpp/MiriInterface.cpp
@@ -0,0 +1,50 @@
+#include "MiriInterface.hpp"
+
+#include "genmc-sys/src/lib.rs.h"
+
+auto MiriGenMCShim::createHandle(const GenmcParams &config)
+ -> std::unique_ptr<MiriGenMCShim>
+{
+ auto conf = std::make_shared<Config>();
+
+ // Miri needs all threads to be replayed, even fully completed ones.
+ conf->replayCompletedThreads = true;
+
+ // We only support the RC11 memory model for Rust.
+ conf->model = ModelType::RC11;
+
+ conf->printRandomScheduleSeed = config.print_random_schedule_seed;
+
+ // FIXME(genmc): disable any options we don't support currently:
+ conf->ipr = false;
+ conf->disableBAM = true;
+ conf->instructionCaching = false;
+
+ ERROR_ON(config.do_symmetry_reduction, "Symmetry reduction is currently unsupported in GenMC mode.");
+ conf->symmetryReduction = config.do_symmetry_reduction;
+
+ // FIXME(genmc): Should there be a way to change this option from Miri?
+ conf->schedulePolicy = SchedulePolicy::WF;
+
+ // FIXME(genmc): implement estimation mode:
+ conf->estimate = false;
+ conf->estimationMax = 1000;
+ const auto mode = conf->estimate ? GenMCDriver::Mode(GenMCDriver::EstimationMode{})
+ : GenMCDriver::Mode(GenMCDriver::VerificationMode{});
+
+ // Running Miri-GenMC without race detection is not supported.
+ // Disabling this option also changes the behavior of the replay scheduler to only schedule at atomic operations, which is required with Miri.
+ // This happens because Miri can generate multiple GenMC events for a single MIR terminator. Without this option,
+ // the scheduler might incorrectly schedule an atomic MIR terminator because the first event it creates is a non-atomic (e.g., `StorageLive`).
+ conf->disableRaceDetection = false;
+
+ // Miri can already check for unfreed memory. Also, GenMC cannot distinguish between memory
+ // that is allowed to leak and memory that is not.
+ conf->warnUnfreedMemory = false;
+
+ // FIXME(genmc): check config:
+ // checkConfigOptions(*conf);
+
+ auto driver = std::make_unique<MiriGenMCShim>(std::move(conf), mode);
+ return driver;
+}
diff --git a/src/tools/miri/genmc-sys/src_cpp/MiriInterface.hpp b/src/tools/miri/genmc-sys/src_cpp/MiriInterface.hpp
new file mode 100644
index 0000000..e55522e
--- /dev/null
+++ b/src/tools/miri/genmc-sys/src_cpp/MiriInterface.hpp
@@ -0,0 +1,44 @@
+#ifndef GENMC_MIRI_INTERFACE_HPP
+#define GENMC_MIRI_INTERFACE_HPP
+
+#include "rust/cxx.h"
+
+#include "config.h"
+
+#include "Config/Config.hpp"
+#include "Verification/GenMCDriver.hpp"
+
+#include <iostream>
+
+/**** Types available to Miri ****/
+
+// Config struct defined on the Rust side and translated to C++ by cxx.rs:
+struct GenmcParams;
+
+struct MiriGenMCShim : private GenMCDriver
+{
+
+public:
+ MiriGenMCShim(std::shared_ptr<const Config> conf, Mode mode /* = VerificationMode{} */)
+ : GenMCDriver(std::move(conf), nullptr, mode)
+ {
+ std::cerr << "C++: GenMC handle created!" << std::endl;
+ }
+
+ virtual ~MiriGenMCShim()
+ {
+ std::cerr << "C++: GenMC handle destroyed!" << std::endl;
+ }
+
+ static std::unique_ptr<MiriGenMCShim> createHandle(const GenmcParams &config);
+};
+
+/**** Functions available to Miri ****/
+
+// NOTE: CXX doesn't support exposing static methods to Rust currently, so we expose this function instead.
+static inline auto createGenmcHandle(const GenmcParams &config) -> std::unique_ptr<MiriGenMCShim>
+{
+ return MiriGenMCShim::createHandle(config);
+}
+
+#endif /* GENMC_MIRI_INTERFACE_HPP */
diff --git a/src/tools/miri/josh-sync.toml b/src/tools/miri/josh-sync.toml
new file mode 100644
index 0000000..86208b3
--- /dev/null
+++ b/src/tools/miri/josh-sync.toml
@@ -0,0 +1,2 @@
+repo = "miri"
+filter = ":rev(75dd959a3a40eb5b4574f8d2e23aa6efbeb33573:prefix=src/tools/miri):/src/tools/miri"
diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock
index a049bfc..044a678 100644
--- a/src/tools/miri/miri-script/Cargo.lock
+++ b/src/tools/miri/miri-script/Cargo.lock
@@ -117,27 +117,6 @@
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
-name = "directories"
-version = "6.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
-dependencies = [
- "dirs-sys",
-]
-
-[[package]]
-name = "dirs-sys"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
-dependencies = [
- "libc",
- "option-ext",
- "redox_users",
- "windows-sys 0.60.2",
-]
-
-[[package]]
name = "dunce"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -167,17 +146,6 @@
[[package]]
name = "getrandom"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi 0.11.1+wasi-snapshot-preview1",
-]
-
-[[package]]
-name = "getrandom"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
@@ -185,7 +153,7 @@
"cfg-if",
"libc",
"r-efi",
- "wasi 0.14.2+wasi-0.2.4",
+ "wasi",
]
[[package]]
@@ -222,16 +190,6 @@
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
-name = "libredox"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638"
-dependencies = [
- "bitflags",
- "libc",
-]
-
-[[package]]
name = "linux-raw-sys"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -249,7 +207,6 @@
dependencies = [
"anyhow",
"clap",
- "directories",
"dunce",
"itertools",
"path_macro",
@@ -276,12 +233,6 @@
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
[[package]]
-name = "option-ext"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
-
-[[package]]
name = "path_macro"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -312,17 +263,6 @@
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
-name = "redox_users"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
-dependencies = [
- "getrandom 0.2.16",
- "libredox",
- "thiserror",
-]
-
-[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -427,33 +367,13 @@
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
dependencies = [
"fastrand",
- "getrandom 0.3.3",
+ "getrandom",
"once_cell",
"rustix",
"windows-sys 0.59.0",
]
[[package]]
-name = "thiserror"
-version = "2.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
-dependencies = [
- "thiserror-impl",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "2.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -477,12 +397,6 @@
[[package]]
name = "wasi"
-version = "0.11.1+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
-
-[[package]]
-name = "wasi"
version = "0.14.2+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml
index b3f82cd..3985888 100644
--- a/src/tools/miri/miri-script/Cargo.toml
+++ b/src/tools/miri/miri-script/Cargo.toml
@@ -22,7 +22,6 @@
xshell = "0.2.6"
rustc_version = "0.4"
dunce = "1.0.4"
-directories = "6"
serde = "1"
serde_json = "1"
serde_derive = "1"
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 9aaad9c..ee09b9b 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -2,11 +2,9 @@
use std::ffi::{OsStr, OsString};
use std::fmt::Write as _;
use std::fs::{self, File};
-use std::io::{self, BufRead, BufReader, BufWriter, Write as _};
-use std::ops::Not;
+use std::io::{self, BufRead, BufReader, BufWriter};
use std::path::PathBuf;
-use std::time::Duration;
-use std::{env, net, process};
+use std::{env, process};
use anyhow::{Context, Result, anyhow, bail};
use path_macro::path;
@@ -18,11 +16,6 @@
use crate::Command;
use crate::util::*;
-/// Used for rustc syncs.
-const JOSH_FILTER: &str =
- ":rev(75dd959a3a40eb5b4574f8d2e23aa6efbeb33573:prefix=src/tools/miri):/src/tools/miri";
-const JOSH_PORT: u16 = 42042;
-
impl MiriEnv {
/// Prepares the environment: builds miri and cargo-miri and a sysroot.
/// Returns the location of the sysroot.
@@ -99,66 +92,6 @@ fn auto_actions() -> Result<()> {
Ok(())
}
- fn start_josh() -> Result<impl Drop> {
- // Determine cache directory.
- let local_dir = {
- let user_dirs =
- directories::ProjectDirs::from("org", "rust-lang", "miri-josh").unwrap();
- user_dirs.cache_dir().to_owned()
- };
-
- // Start josh, silencing its output.
- let mut cmd = process::Command::new("josh-proxy");
- cmd.arg("--local").arg(local_dir);
- cmd.arg("--remote").arg("https://github.com");
- cmd.arg("--port").arg(JOSH_PORT.to_string());
- cmd.arg("--no-background");
- cmd.stdout(process::Stdio::null());
- cmd.stderr(process::Stdio::null());
- let josh = cmd.spawn().context("failed to start josh-proxy, make sure it is installed")?;
-
- // Create a wrapper that stops it on drop.
- struct Josh(process::Child);
- impl Drop for Josh {
- fn drop(&mut self) {
- #[cfg(unix)]
- {
- // Try to gracefully shut it down.
- process::Command::new("kill")
- .args(["-s", "INT", &self.0.id().to_string()])
- .output()
- .expect("failed to SIGINT josh-proxy");
- // Sadly there is no "wait with timeout"... so we just give it some time to finish.
- std::thread::sleep(Duration::from_millis(100));
- // Now hopefully it is gone.
- if self.0.try_wait().expect("failed to wait for josh-proxy").is_some() {
- return;
- }
- }
- // If that didn't work (or we're not on Unix), kill it hard.
- eprintln!(
- "I have to kill josh-proxy the hard way, let's hope this does not break anything."
- );
- self.0.kill().expect("failed to SIGKILL josh-proxy");
- }
- }
-
- // Wait until the port is open. We try every 10ms until 1s passed.
- for _ in 0..100 {
- // This will generally fail immediately when the port is still closed.
- let josh_ready = net::TcpStream::connect_timeout(
- &net::SocketAddr::from(([127, 0, 0, 1], JOSH_PORT)),
- Duration::from_millis(1),
- );
- if josh_ready.is_ok() {
- return Ok(Josh(josh));
- }
- // Not ready yet.
- std::thread::sleep(Duration::from_millis(10));
- }
- bail!("Even after waiting for 1s, josh-proxy is still not available.")
- }
-
pub fn exec(self) -> Result<()> {
// First, and crucially only once, run the auto-actions -- but not for all commands.
match &self {
@@ -170,11 +103,7 @@ pub fn exec(self) -> Result<()> {
| Command::Fmt { .. }
| Command::Doc { .. }
| Command::Clippy { .. } => Self::auto_actions()?,
- | Command::Toolchain { .. }
- | Command::Bench { .. }
- | Command::RustcPull { .. }
- | Command::RustcPush { .. }
- | Command::Squash => {}
+ | Command::Toolchain { .. } | Command::Bench { .. } | Command::Squash => {}
}
// Then run the actual command.
match self {
@@ -191,8 +120,6 @@ pub fn exec(self) -> Result<()> {
Command::Bench { target, no_install, save_baseline, load_baseline, benches } =>
Self::bench(target, no_install, save_baseline, load_baseline, benches),
Command::Toolchain { flags } => Self::toolchain(flags),
- Command::RustcPull { commit } => Self::rustc_pull(commit.clone()),
- Command::RustcPush { github_user, branch } => Self::rustc_push(github_user, branch),
Command::Squash => Self::squash(),
}
}
@@ -233,156 +160,6 @@ fn toolchain(flags: Vec<String>) -> Result<()> {
Ok(())
}
- fn rustc_pull(commit: Option<String>) -> Result<()> {
- let sh = Shell::new()?;
- sh.change_dir(miri_dir()?);
- let commit = commit.map(Result::Ok).unwrap_or_else(|| {
- let rust_repo_head =
- cmd!(sh, "git ls-remote https://github.com/rust-lang/rust/ HEAD").read()?;
- rust_repo_head
- .split_whitespace()
- .next()
- .map(|front| front.trim().to_owned())
- .ok_or_else(|| anyhow!("Could not obtain Rust repo HEAD from remote."))
- })?;
- // Make sure the repo is clean.
- if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() {
- bail!("working directory must be clean before running `./miri rustc-pull`");
- }
- // Make sure josh is running.
- let josh = Self::start_josh()?;
- let josh_url =
- format!("http://localhost:{JOSH_PORT}/rust-lang/rust.git@{commit}{JOSH_FILTER}.git");
-
- // Update rust-version file. As a separate commit, since making it part of
- // the merge has confused the heck out of josh in the past.
- // We pass `--no-verify` to avoid running git hooks like `./miri fmt` that could in turn
- // trigger auto-actions.
- // We do this before the merge so that if there are merge conflicts, we have
- // the right rust-version file while resolving them.
- sh.write_file("rust-version", format!("{commit}\n"))?;
- const PREPARING_COMMIT_MESSAGE: &str = "Preparing for merge from rustc";
- cmd!(sh, "git commit rust-version --no-verify -m {PREPARING_COMMIT_MESSAGE}")
- .run()
- .context("FAILED to commit rust-version file, something went wrong")?;
-
- // Fetch given rustc commit.
- cmd!(sh, "git fetch {josh_url}")
- .run()
- .inspect_err(|_| {
- // Try to un-do the previous `git commit`, to leave the repo in the state we found it.
- cmd!(sh, "git reset --hard HEAD^")
- .run()
- .expect("FAILED to clean up again after failed `git fetch`, sorry for that");
- })
- .context("FAILED to fetch new commits, something went wrong (committing the rust-version file has been undone)")?;
-
- // This should not add any new root commits. So count those before and after merging.
- let num_roots = || -> Result<u32> {
- Ok(cmd!(sh, "git rev-list HEAD --max-parents=0 --count")
- .read()
- .context("failed to determine the number of root commits")?
- .parse::<u32>()?)
- };
- let num_roots_before = num_roots()?;
-
- // Merge the fetched commit.
- const MERGE_COMMIT_MESSAGE: &str = "Merge from rustc";
- cmd!(sh, "git merge FETCH_HEAD --no-verify --no-ff -m {MERGE_COMMIT_MESSAGE}")
- .run()
- .context("FAILED to merge new commits, something went wrong")?;
-
- // Check that the number of roots did not increase.
- if num_roots()? != num_roots_before {
- bail!("Josh created a new root commit. This is probably not the history you want.");
- }
-
- drop(josh);
- Ok(())
- }
-
- fn rustc_push(github_user: String, branch: String) -> Result<()> {
- let sh = Shell::new()?;
- sh.change_dir(miri_dir()?);
- let base = sh.read_file("rust-version")?.trim().to_owned();
- // Make sure the repo is clean.
- if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() {
- bail!("working directory must be clean before running `./miri rustc-push`");
- }
- // Make sure josh is running.
- let josh = Self::start_josh()?;
- let josh_url =
- format!("http://localhost:{JOSH_PORT}/{github_user}/rust.git{JOSH_FILTER}.git");
-
- // Find a repo we can do our preparation in.
- if let Ok(rustc_git) = env::var("RUSTC_GIT") {
- // If rustc_git is `Some`, we'll use an existing fork for the branch updates.
- sh.change_dir(rustc_git);
- } else {
- // Otherwise, do this in the local Miri repo.
- println!(
- "This will pull a copy of the rust-lang/rust history into this Miri checkout, growing it by about 1GB."
- );
- print!(
- "To avoid that, abort now and set the `RUSTC_GIT` environment variable to an existing rustc checkout. Proceed? [y/N] "
- );
- std::io::stdout().flush()?;
- let mut answer = String::new();
- std::io::stdin().read_line(&mut answer)?;
- if answer.trim().to_lowercase() != "y" {
- std::process::exit(1);
- }
- };
- // Prepare the branch. Pushing works much better if we use as base exactly
- // the commit that we pulled from last time, so we use the `rust-version`
- // file to find out which commit that would be.
- println!("Preparing {github_user}/rust (base: {base})...");
- if cmd!(sh, "git fetch https://github.com/{github_user}/rust {branch}")
- .ignore_stderr()
- .read()
- .is_ok()
- {
- println!(
- "The branch '{branch}' seems to already exist in 'https://github.com/{github_user}/rust'. Please delete it and try again."
- );
- std::process::exit(1);
- }
- cmd!(sh, "git fetch https://github.com/rust-lang/rust {base}").run()?;
- cmd!(sh, "git push https://github.com/{github_user}/rust {base}:refs/heads/{branch}")
- .ignore_stdout()
- .ignore_stderr() // silence the "create GitHub PR" message
- .run()?;
- println!();
-
- // Do the actual push.
- sh.change_dir(miri_dir()?);
- println!("Pushing miri changes...");
- cmd!(sh, "git push {josh_url} HEAD:{branch}").run()?;
- println!();
-
- // Do a round-trip check to make sure the push worked as expected.
- cmd!(sh, "git fetch {josh_url} {branch}").ignore_stderr().read()?;
- let head = cmd!(sh, "git rev-parse HEAD").read()?;
- let fetch_head = cmd!(sh, "git rev-parse FETCH_HEAD").read()?;
- if head != fetch_head {
- bail!(
- "Josh created a non-roundtrip push! Do NOT merge this into rustc!\n\
- Expected {head}, got {fetch_head}."
- );
- }
- println!(
- "Confirmed that the push round-trips back to Miri properly. Please create a rustc PR:"
- );
- println!(
- // Open PR with `subtree update` title to silence the `no-merges` triagebot check
- // See https://github.com/rust-lang/rust/pull/114157
- " https://github.com/rust-lang/rust/compare/{github_user}:{branch}?quick_pull=1&title=Miri+subtree+update&body=r?+@ghost"
- );
-
- drop(josh);
- Ok(())
- }
-
fn squash() -> Result<()> {
let sh = Shell::new()?;
sh.change_dir(miri_dir()?);
@@ -757,8 +534,8 @@ fn fmt(flags: Vec<String>) -> Result<()> {
if ty.is_file() {
name.ends_with(".rs")
} else {
- // dir or symlink. skip `target` and `.git`.
- &name != "target" && &name != ".git"
+ // dir or symlink. skip `target`, `.git` and `genmc-src*`
+ &name != "target" && &name != ".git" && !name.starts_with("genmc-src")
}
})
.filter_ok(|item| item.file_type().is_file())
diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs
index e41df66..761ec59 100644
--- a/src/tools/miri/miri-script/src/main.rs
+++ b/src/tools/miri/miri-script/src/main.rs
@@ -142,25 +142,6 @@ pub enum Command {
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
flags: Vec<String>,
},
- /// Pull and merge Miri changes from the rustc repo.
- ///
- /// The fetched commit is stored in the `rust-version` file, so the next `./miri toolchain` will
- /// install the rustc that just got pulled.
- RustcPull {
- /// The commit to fetch (default: latest rustc commit).
- commit: Option<String>,
- },
- /// Push Miri changes back to the rustc repo.
- ///
- /// This will pull a copy of the rustc history into the Miri repo, unless you set the RUSTC_GIT
- /// env var to an existing clone of the rustc repo.
- RustcPush {
- /// The Github user that owns the rustc fork to which we should push.
- github_user: String,
- /// The branch to push to.
- #[arg(default_value = "miri-sync")]
- branch: String,
- },
/// Squash the commits of the current feature branch into one.
Squash,
}
@@ -184,8 +165,7 @@ fn add_remainder(&mut self, remainder: Vec<String>) -> Result<()> {
flags.extend(remainder);
Ok(())
}
- Self::Bench { .. } | Self::RustcPull { .. } | Self::RustcPush { .. } | Self::Squash =>
- bail!("unexpected \"--\" found in arguments"),
+ Self::Bench { .. } | Self::Squash => bail!("unexpected \"--\" found in arguments"),
}
}
}
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index d734ec3..2178caf 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-6707bf0f59485cf054ac1095725df43220e4be20
+733dab558992d902d6d17576de1da768094e2cf3
diff --git a/src/tools/miri/src/bin/log/setup.rs b/src/tools/miri/src/bin/log/setup.rs
index da0ba52..a9392d0 100644
--- a/src/tools/miri/src/bin/log/setup.rs
+++ b/src/tools/miri/src/bin/log/setup.rs
@@ -60,7 +60,7 @@ fn init_logger_once(early_dcx: &EarlyDiagCtxt) {
#[cfg(not(feature = "tracing"))]
{
crate::fatal_error!(
- "fatal error: cannot enable MIRI_TRACING since Miri was not built with the \"tracing\" feature"
+ "Cannot enable MIRI_TRACING since Miri was not built with the \"tracing\" feature"
);
}
diff --git a/src/tools/miri/src/bin/log/tracing_chrome.rs b/src/tools/miri/src/bin/log/tracing_chrome.rs
index 5a96633..3379816 100644
--- a/src/tools/miri/src/bin/log/tracing_chrome.rs
+++ b/src/tools/miri/src/bin/log/tracing_chrome.rs
@@ -12,6 +12,7 @@
//! ```rust
//! tracing::info_span!("my_span", tracing_separate_thread = tracing::field::Empty, /* ... */)
//! ```
+//! - use i64 instead of u64 for the "id" in [ChromeLayer::get_root_id] to be compatible with Perfetto
//!
//! Depending on the tracing-chrome crate from crates.io is unfortunately not possible, since it
//! depends on `tracing_core` which conflicts with rustc_private's `tracing_core` (meaning it would
@@ -285,9 +286,9 @@ struct Callsite {
}
enum Message {
- Enter(f64, Callsite, Option<u64>),
+ Enter(f64, Callsite, Option<i64>),
Event(f64, Callsite),
- Exit(f64, Callsite, Option<u64>),
+ Exit(f64, Callsite, Option<i64>),
NewThread(usize, String),
Flush,
Drop,
@@ -519,14 +520,17 @@ fn get_callsite(&self, data: EventOrSpan<S>) -> Callsite {
}
}
- fn get_root_id(&self, span: SpanRef<S>) -> Option<u64> {
+ fn get_root_id(&self, span: SpanRef<S>) -> Option<i64> {
+ // Returns `Option<i64>` instead of `Option<u64>` because apparently Perfetto gives an
+ // error if an id does not fit in a 64-bit signed integer in 2's complement. We cast the
+ // span id from `u64` to `i64` with wraparound, since negative values are fine.
match self.trace_style {
TraceStyle::Threaded => {
if span.fields().field("tracing_separate_thread").is_some() {
// assign an independent "id" to spans with argument "tracing_separate_thread",
// so they appear a separate trace line in trace visualization tools, see
// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.jh64i9l3vwa1
- Some(span.id().into_u64())
+ Some(span.id().into_u64().cast_signed()) // the comment above explains the cast
} else {
None
}
@@ -539,6 +543,7 @@ fn get_root_id(&self, span: SpanRef<S>) -> Option<u64> {
.unwrap_or(span)
.id()
.into_u64()
+ .cast_signed() // the comment above explains the cast
),
}
}
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 89fa980..ae1b25f 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -67,8 +67,6 @@
struct MiriCompilerCalls {
miri_config: Option<MiriConfig>,
many_seeds: Option<ManySeedsConfig>,
- /// Settings for using GenMC with Miri.
- genmc_config: Option<GenmcConfig>,
}
struct ManySeedsConfig {
@@ -77,12 +75,8 @@ struct ManySeedsConfig {
}
impl MiriCompilerCalls {
- fn new(
- miri_config: MiriConfig,
- many_seeds: Option<ManySeedsConfig>,
- genmc_config: Option<GenmcConfig>,
- ) -> Self {
- Self { miri_config: Some(miri_config), many_seeds, genmc_config }
+ fn new(miri_config: MiriConfig, many_seeds: Option<ManySeedsConfig>) -> Self {
+ Self { miri_config: Some(miri_config), many_seeds }
}
}
@@ -192,8 +186,8 @@ fn after_analysis<'tcx>(
optimizations is usually marginal at best.");
}
- if let Some(genmc_config) = &self.genmc_config {
- let _genmc_ctx = Rc::new(GenmcCtx::new(&config, genmc_config));
+ if let Some(_genmc_config) = &config.genmc_config {
+ let _genmc_ctx = Rc::new(GenmcCtx::new(&config));
todo!("GenMC mode not yet implemented");
};
@@ -487,7 +481,6 @@ fn main() {
let mut many_seeds_keep_going = false;
let mut miri_config = MiriConfig::default();
miri_config.env = env_snapshot;
- let mut genmc_config = None;
let mut rustc_args = vec![];
let mut after_dashdash = false;
@@ -603,9 +596,9 @@ fn main() {
} else if arg == "-Zmiri-many-seeds-keep-going" {
many_seeds_keep_going = true;
} else if let Some(trimmed_arg) = arg.strip_prefix("-Zmiri-genmc") {
- // FIXME(GenMC): Currently, GenMC mode is incompatible with aliasing model checking.
- miri_config.borrow_tracker = None;
- GenmcConfig::parse_arg(&mut genmc_config, trimmed_arg);
+ if let Err(msg) = GenmcConfig::parse_arg(&mut miri_config.genmc_config, trimmed_arg) {
+ fatal_error!("{msg}");
+ }
} else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") {
miri_config.forwarded_env_vars.push(param.to_owned());
} else if let Some(param) = arg.strip_prefix("-Zmiri-env-set=") {
@@ -740,13 +733,18 @@ fn main() {
many_seeds.map(|seeds| ManySeedsConfig { seeds, keep_going: many_seeds_keep_going });
// Validate settings for data race detection and GenMC mode.
- assert_eq!(genmc_config.is_some(), miri_config.genmc_mode);
- if genmc_config.is_some() {
+ if miri_config.genmc_config.is_some() {
if !miri_config.data_race_detector {
fatal_error!("Cannot disable data race detection in GenMC mode (currently)");
} else if !miri_config.weak_memory_emulation {
fatal_error!("Cannot disable weak memory emulation in GenMC mode");
}
+ if miri_config.borrow_tracker.is_some() {
+ eprintln!(
+ "warning: borrow tracking has been disabled, it is not (yet) supported in GenMC mode."
+ );
+ miri_config.borrow_tracker = None;
+ }
} else if miri_config.weak_memory_emulation && !miri_config.data_race_detector {
fatal_error!(
"Weak memory emulation cannot be enabled when the data race detector is disabled"
@@ -765,8 +763,5 @@ fn main() {
);
}
}
- run_compiler_and_exit(
- &rustc_args,
- &mut MiriCompilerCalls::new(miri_config, many_seeds, genmc_config),
- )
+ run_compiler_and_exit(&rustc_args, &mut MiriCompilerCalls::new(miri_config, many_seeds))
}
diff --git a/src/tools/miri/src/concurrency/genmc/config.rs b/src/tools/miri/src/concurrency/genmc/config.rs
index f91211a..c56adab 100644
--- a/src/tools/miri/src/concurrency/genmc/config.rs
+++ b/src/tools/miri/src/concurrency/genmc/config.rs
@@ -1,19 +1,35 @@
-use crate::MiriConfig;
+use super::GenmcParams;
+/// Configuration for GenMC mode.
+/// The `params` field is shared with the C++ side.
+/// The remaining options are kept on the Rust side.
#[derive(Debug, Default, Clone)]
pub struct GenmcConfig {
- // TODO: add fields
+ pub(super) params: GenmcParams,
+ do_estimation: bool,
+ // FIXME(GenMC): add remaining options.
}
impl GenmcConfig {
/// Function for parsing command line options for GenMC mode.
- /// All GenMC arguments start with the string "-Zmiri-genmc".
///
- /// `trimmed_arg` should be the argument to be parsed, with the suffix "-Zmiri-genmc" removed
- pub fn parse_arg(genmc_config: &mut Option<GenmcConfig>, trimmed_arg: &str) {
+ /// All GenMC arguments start with the string "-Zmiri-genmc".
+ /// Passing any GenMC argument will enable GenMC mode.
+ ///
+ /// `trimmed_arg` should be the argument to be parsed, with the suffix "-Zmiri-genmc" removed.
+ pub fn parse_arg(
+ genmc_config: &mut Option<GenmcConfig>,
+ trimmed_arg: &str,
+ ) -> Result<(), String> {
+ // FIXME(genmc): Ensure host == target somewhere.
+
if genmc_config.is_none() {
*genmc_config = Some(Default::default());
}
- todo!("implement parsing of GenMC options")
+ if trimmed_arg.is_empty() {
+ return Ok(()); // this corresponds to "-Zmiri-genmc"
+ }
+ // FIXME(GenMC): implement remaining parameters.
+ todo!();
}
}
diff --git a/src/tools/miri/src/concurrency/genmc/dummy.rs b/src/tools/miri/src/concurrency/genmc/dummy.rs
index 3d0558f..79d27c4 100644
--- a/src/tools/miri/src/concurrency/genmc/dummy.rs
+++ b/src/tools/miri/src/concurrency/genmc/dummy.rs
@@ -16,7 +16,7 @@ pub struct GenmcCtx {}
pub struct GenmcConfig {}
impl GenmcCtx {
- pub fn new(_miri_config: &MiriConfig, _genmc_config: &GenmcConfig) -> Self {
+ pub fn new(_miri_config: &MiriConfig) -> Self {
unreachable!()
}
@@ -227,10 +227,15 @@ fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
}
impl GenmcConfig {
- pub fn parse_arg(_genmc_config: &mut Option<GenmcConfig>, trimmed_arg: &str) {
- unimplemented!(
- "GenMC feature im Miri is disabled, cannot handle argument: \"-Zmiri-genmc{trimmed_arg}\""
- );
+ pub fn parse_arg(
+ _genmc_config: &mut Option<GenmcConfig>,
+ trimmed_arg: &str,
+ ) -> Result<(), String> {
+ if cfg!(feature = "genmc") {
+ Err(format!("GenMC is disabled in this build of Miri"))
+ } else {
+ Err(format!("GenMC is not supported on this target"))
+ }
}
pub fn should_print_graph(&self, _rep: usize) -> bool {
diff --git a/src/tools/miri/src/concurrency/genmc/mod.rs b/src/tools/miri/src/concurrency/genmc/mod.rs
index 0dfd4b9..3617775 100644
--- a/src/tools/miri/src/concurrency/genmc/mod.rs
+++ b/src/tools/miri/src/concurrency/genmc/mod.rs
@@ -2,6 +2,7 @@
use std::cell::Cell;
+use genmc_sys::{GenmcParams, createGenmcHandle};
use rustc_abi::{Align, Size};
use rustc_const_eval::interpret::{InterpCx, InterpResult, interp_ok};
use rustc_middle::mir;
@@ -24,9 +25,19 @@ pub struct GenmcCtx {
impl GenmcCtx {
/// Create a new `GenmcCtx` from a given config.
- pub fn new(miri_config: &MiriConfig, genmc_config: &GenmcConfig) -> Self {
- assert!(miri_config.genmc_mode);
- todo!()
+ pub fn new(miri_config: &MiriConfig) -> Self {
+ let genmc_config = miri_config.genmc_config.as_ref().unwrap();
+
+ let handle = createGenmcHandle(&genmc_config.params);
+ assert!(!handle.is_null());
+
+ eprintln!("Miri: GenMC handle creation successful!");
+
+ drop(handle);
+ eprintln!("Miri: Dropping GenMC handle successful!");
+
+ // FIXME(GenMC): implement
+ std::process::exit(0);
}
pub fn get_stuck_execution_count(&self) -> usize {
diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs
index c2ea8a0..435615e 100644
--- a/src/tools/miri/src/concurrency/mod.rs
+++ b/src/tools/miri/src/concurrency/mod.rs
@@ -8,7 +8,17 @@
pub mod weak_memory;
// Import either the real genmc adapter or a dummy module.
-#[cfg_attr(not(feature = "genmc"), path = "genmc/dummy.rs")]
+// On unsupported platforms, we always include the dummy module, even if the `genmc` feature is enabled.
+// FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed.
+#[cfg_attr(
+ not(all(
+ feature = "genmc",
+ target_os = "linux",
+ target_pointer_width = "64",
+ target_endian = "little"
+ )),
+ path = "genmc/dummy.rs"
+)]
mod genmc;
pub use self::data_race_handler::{AllocDataRaceHandler, GlobalDataRaceHandler};
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 878afdf..fe1ef86 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -375,7 +375,7 @@ fn add_lossy(&self, duration: Duration) -> Self {
}
/// The clock to use for the timeout you are asking for.
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, PartialEq)]
pub enum TimeoutClock {
Monotonic,
RealTime,
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 3c80e60..4c531a8 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -125,8 +125,8 @@ pub struct MiriConfig {
pub data_race_detector: bool,
/// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled.
pub weak_memory_emulation: bool,
- /// Determine if we are running in GenMC mode. In this mode, Miri will explore multiple concurrent executions of the given program.
- pub genmc_mode: bool,
+ /// Determine if we are running in GenMC mode and with which settings. In GenMC mode, Miri will explore multiple concurrent executions of the given program.
+ pub genmc_config: Option<GenmcConfig>,
/// Track when an outdated (weak memory) load happens.
pub track_outdated_loads: bool,
/// Rate of spurious failures for compare_exchange_weak atomic operations,
@@ -192,7 +192,7 @@ fn default() -> MiriConfig {
track_alloc_accesses: false,
data_race_detector: true,
weak_memory_emulation: true,
- genmc_mode: false,
+ genmc_config: None,
track_outdated_loads: false,
cmpxchg_weak_failure_rate: 0.8, // 80%
measureme_out: None,
@@ -334,8 +334,8 @@ pub fn create_ecx<'tcx>(
helpers::try_resolve_path(tcx, &["core", "ascii", "escape_default"], Namespace::ValueNS);
if !matches!(sentinel, Some(s) if tcx.is_mir_available(s.def.def_id())) {
tcx.dcx().fatal(
- "the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing. \
- Use `cargo miri setup` to prepare a sysroot that is suitable for Miri."
+ "the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing.\n\
+ Note that directly invoking the `miri` binary is not supported; please use `cargo miri` instead."
);
}
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index ccfff7f..ab7e357 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -3,7 +3,7 @@
use std::{cmp, iter};
use rand::RngCore;
-use rustc_abi::{Align, CanonAbi, ExternAbi, FieldIdx, FieldsShape, Size, Variants};
+use rustc_abi::{Align, ExternAbi, FieldIdx, FieldsShape, Size, Variants};
use rustc_apfloat::Float;
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_hir::Safety;
@@ -14,11 +14,10 @@
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::ty::layout::{LayoutOf, MaybeResult, TyAndLayout};
-use rustc_middle::ty::{self, Binder, FloatTy, FnSig, IntTy, Ty, TyCtxt, UintTy};
+use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, UintTy};
use rustc_session::config::CrateType;
use rustc_span::{Span, Symbol};
use rustc_symbol_mangling::mangle_internal_symbol;
-use rustc_target::callconv::FnAbi;
use crate::*;
@@ -437,7 +436,7 @@ fn gen_random(&mut self, ptr: Pointer, len: u64) -> InterpResult<'tcx> {
/// For now, arguments must be scalars (so that the caller does not have to know the layout).
///
/// If you do not provide a return place, a dangling zero-sized place will be created
- /// for your convenience.
+ /// for your convenience. This is only valid if the return type is `()`.
fn call_function(
&mut self,
f: ty::Instance<'tcx>,
@@ -452,7 +451,7 @@ fn call_function(
let mir = this.load_mir(f.def, None)?;
let dest = match dest {
Some(dest) => dest.clone(),
- None => MPlaceTy::fake_alloc_zst(this.layout_of(mir.return_ty())?),
+ None => MPlaceTy::fake_alloc_zst(this.machine.layouts.unit),
};
// Construct a function pointer type representing the caller perspective.
@@ -465,6 +464,7 @@ fn call_function(
);
let caller_fn_abi = this.fn_abi_of_fn_ptr(ty::Binder::dummy(sig), ty::List::empty())?;
+ // This will also show proper errors if there is any ABI mismatch.
this.init_stack_frame(
f,
mir,
@@ -929,21 +929,6 @@ fn read_wchar_t_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec<u32>> {
self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi)
}
- /// Check that the calling convention is what we expect.
- fn check_callconv<'a>(
- &self,
- fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
- exp_abi: CanonAbi,
- ) -> InterpResult<'a, ()> {
- if fn_abi.conv != exp_abi {
- throw_ub_format!(
- r#"calling a function with calling convention "{exp_abi}" using caller calling convention "{}""#,
- fn_abi.conv
- );
- }
- interp_ok(())
- }
-
fn frame_in_std(&self) -> bool {
let this = self.eval_context_ref();
let frame = this.frame();
@@ -967,161 +952,6 @@ fn frame_in_std(&self) -> bool {
crate_name == "std" || crate_name == "std_miri_test"
}
- fn check_abi_and_shim_symbol_clash(
- &mut self,
- abi: &FnAbi<'tcx, Ty<'tcx>>,
- exp_abi: CanonAbi,
- link_name: Symbol,
- ) -> InterpResult<'tcx, ()> {
- self.check_callconv(abi, exp_abi)?;
- if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
- // If compiler-builtins is providing the symbol, then don't treat it as a clash.
- // We'll use our built-in implementation in `emulate_foreign_item_inner` for increased
- // performance. Note that this means we won't catch any undefined behavior in
- // compiler-builtins when running other crates, but Miri can still be run on
- // compiler-builtins itself (or any crate that uses it as a normal dependency)
- if self.eval_context_ref().tcx.is_compiler_builtins(instance.def_id().krate) {
- return interp_ok(());
- }
-
- throw_machine_stop!(TerminationInfo::SymbolShimClashing {
- link_name,
- span: body.span.data(),
- })
- }
- interp_ok(())
- }
-
- fn check_shim<'a, const N: usize>(
- &mut self,
- abi: &FnAbi<'tcx, Ty<'tcx>>,
- exp_abi: CanonAbi,
- link_name: Symbol,
- args: &'a [OpTy<'tcx>],
- ) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
- self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?;
-
- if abi.c_variadic {
- throw_ub_format!(
- "calling a non-variadic function with a variadic caller-side signature"
- );
- }
- if let Ok(ops) = args.try_into() {
- return interp_ok(ops);
- }
- throw_ub_format!(
- "incorrect number of arguments for `{link_name}`: got {}, expected {}",
- args.len(),
- N
- )
- }
-
- /// Check that the given `caller_fn_abi` matches the expected ABI described by
- /// `callee_abi`, `callee_input_tys`, `callee_output_ty`, and then returns the list of
- /// arguments.
- fn check_shim_abi<'a, const N: usize>(
- &mut self,
- link_name: Symbol,
- caller_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
- callee_abi: ExternAbi,
- callee_input_tys: [Ty<'tcx>; N],
- callee_output_ty: Ty<'tcx>,
- caller_args: &'a [OpTy<'tcx>],
- ) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
- let this = self.eval_context_mut();
- let mut inputs_and_output = callee_input_tys.to_vec();
- inputs_and_output.push(callee_output_ty);
- let fn_sig_binder = Binder::dummy(FnSig {
- inputs_and_output: this.machine.tcx.mk_type_list(&inputs_and_output),
- c_variadic: false,
- // This does not matter for the ABI.
- safety: Safety::Safe,
- abi: callee_abi,
- });
- let callee_fn_abi = this.fn_abi_of_fn_ptr(fn_sig_binder, Default::default())?;
-
- this.check_abi_and_shim_symbol_clash(caller_fn_abi, callee_fn_abi.conv, link_name)?;
-
- if caller_fn_abi.c_variadic {
- throw_ub_format!(
- "ABI mismatch: calling a non-variadic function with a variadic caller-side signature"
- );
- }
-
- if callee_fn_abi.fixed_count != caller_fn_abi.fixed_count {
- throw_ub_format!(
- "ABI mismatch: expected {} arguments, found {} arguments ",
- callee_fn_abi.fixed_count,
- caller_fn_abi.fixed_count
- );
- }
-
- if callee_fn_abi.can_unwind && !caller_fn_abi.can_unwind {
- throw_ub_format!(
- "ABI mismatch: callee may unwind, but caller-side signature prohibits unwinding",
- );
- }
-
- if !this.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
- throw_ub!(AbiMismatchReturn {
- caller_ty: caller_fn_abi.ret.layout.ty,
- callee_ty: callee_fn_abi.ret.layout.ty
- });
- }
-
- if let Some(index) = caller_fn_abi
- .args
- .iter()
- .zip(callee_fn_abi.args.iter())
- .map(|(caller_arg, callee_arg)| this.check_argument_compat(caller_arg, callee_arg))
- .collect::<InterpResult<'tcx, Vec<bool>>>()?
- .into_iter()
- .position(|b| !b)
- {
- throw_ub!(AbiMismatchArgument {
- caller_ty: caller_fn_abi.args[index].layout.ty,
- callee_ty: callee_fn_abi.args[index].layout.ty
- });
- }
-
- if let Ok(ops) = caller_args.try_into() {
- return interp_ok(ops);
- }
- unreachable!()
- }
-
- /// Check shim for variadic function.
- /// Returns a tuple that consisting of an array of fixed args, and a slice of varargs.
- fn check_shim_variadic<'a, const N: usize>(
- &mut self,
- abi: &FnAbi<'tcx, Ty<'tcx>>,
- exp_abi: CanonAbi,
- link_name: Symbol,
- args: &'a [OpTy<'tcx>],
- ) -> InterpResult<'tcx, (&'a [OpTy<'tcx>; N], &'a [OpTy<'tcx>])>
- where
- &'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>,
- {
- self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?;
-
- if !abi.c_variadic {
- throw_ub_format!(
- "calling a variadic function with a non-variadic caller-side signature"
- );
- }
- if abi.fixed_count != u32::try_from(N).unwrap() {
- throw_ub_format!(
- "incorrect number of fixed arguments for variadic function `{}`: got {}, expected {N}",
- link_name.as_str(),
- abi.fixed_count
- )
- }
- if let Some(args) = args.split_first_chunk() {
- return interp_ok(args);
- }
- panic!("mismatch between signature and `args` slice");
- }
-
/// Mark a machine allocation that was just created as immutable.
fn mark_immutable(&mut self, mplace: &MPlaceTy<'tcx>) {
let this = self.eval_context_mut();
@@ -1257,8 +1087,21 @@ fn lookup_link_section(
"failed to evaluate static in required link_section: {def_id:?}\n{err:?}"
)
});
- let val = this.read_immediate(&const_val)?;
- array.push(val);
+ match const_val.layout.ty.kind() {
+ ty::FnPtr(..) => {
+ array.push(this.read_immediate(&const_val)?);
+ }
+ ty::Array(elem_ty, _) if matches!(elem_ty.kind(), ty::FnPtr(..)) => {
+ let mut elems = this.project_array_fields(&const_val)?;
+ while let Some((_idx, elem)) = elems.next(this)? {
+ array.push(this.read_immediate(&elem)?);
+ }
+ }
+ _ =>
+ throw_unsup_format!(
+ "only function pointers and arrays of function pointers are supported in well-known linker sections"
+ ),
+ }
}
interp_ok(())
})?;
@@ -1317,39 +1160,6 @@ pub fn is_user_relevant(&self, frame: &Frame<'tcx, Provenance>) -> bool {
}
}
-/// Check that the number of args is what we expect.
-pub fn check_intrinsic_arg_count<'a, 'tcx, const N: usize>(
- args: &'a [OpTy<'tcx>],
-) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]>
-where
- &'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>,
-{
- if let Ok(ops) = args.try_into() {
- return interp_ok(ops);
- }
- throw_ub_format!(
- "incorrect number of arguments for intrinsic: got {}, expected {}",
- args.len(),
- N
- )
-}
-
-/// Check that the number of varargs is at least the minimum what we expect.
-/// Fixed args should not be included.
-pub fn check_min_vararg_count<'a, 'tcx, const N: usize>(
- name: &'a str,
- args: &'a [OpTy<'tcx>],
-) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
- if let Some((ops, _)) = args.split_first_chunk() {
- return interp_ok(ops);
- }
- throw_ub_format!(
- "not enough variadic arguments for `{name}`: got {}, expected at least {}",
- args.len(),
- N
- )
-}
-
pub fn isolation_abort_error<'tcx>(name: &str) -> InterpResult<'tcx> {
throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
"{name} not available when isolation is enabled",
@@ -1465,7 +1275,7 @@ pub struct MaybeEnteredTraceSpan {
#[macro_export]
macro_rules! enter_trace_span {
($name:ident :: $subname:ident $($tt:tt)*) => {{
- enter_trace_span!(stringify!($name), $name = %stringify!(subname) $($tt)*)
+ enter_trace_span!(stringify!($name), $name = %stringify!($subname) $($tt)*)
}};
($($tt:tt)*) => {
diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs
index 0a59a70..bcc3e9e 100644
--- a/src/tools/miri/src/intrinsics/atomic.rs
+++ b/src/tools/miri/src/intrinsics/atomic.rs
@@ -2,7 +2,7 @@
use rustc_middle::ty::AtomicOrdering;
use rustc_middle::{mir, ty};
-use self::helpers::check_intrinsic_arg_count;
+use super::check_intrinsic_arg_count;
use crate::*;
pub enum AtomicOp {
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index 4efa7dd..b5e8146 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -14,11 +14,28 @@
use rustc_span::{Symbol, sym};
use self::atomic::EvalContextExt as _;
-use self::helpers::{ToHost, ToSoft, check_intrinsic_arg_count};
+use self::helpers::{ToHost, ToSoft};
use self::simd::EvalContextExt as _;
use crate::math::{IeeeExt, apply_random_float_error_ulp};
use crate::*;
+/// Check that the number of args is what we expect.
+fn check_intrinsic_arg_count<'a, 'tcx, const N: usize>(
+ args: &'a [OpTy<'tcx>],
+) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]>
+where
+ &'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>,
+{
+ if let Ok(ops) = args.try_into() {
+ return interp_ok(ops);
+ }
+ throw_ub_format!(
+ "incorrect number of arguments for intrinsic: got {}, expected {}",
+ args.len(),
+ N
+ )
+}
+
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn call_intrinsic(
@@ -114,7 +131,8 @@ fn emulate_intrinsic_by_name(
));
}
"catch_unwind" => {
- this.handle_catch_unwind(args, dest, ret)?;
+ let [try_fn, data, catch_fn] = check_intrinsic_arg_count(args)?;
+ this.handle_catch_unwind(try_fn, data, catch_fn, dest, ret)?;
// This pushed a stack frame, don't jump to `ret`.
return interp_ok(EmulateItemResult::AlreadyJumped);
}
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index e63992a..b26516c 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -6,9 +6,8 @@
use rustc_middle::{mir, ty};
use rustc_span::{Symbol, sym};
-use crate::helpers::{
- ToHost, ToSoft, bool_to_simd_element, check_intrinsic_arg_count, simd_element_to_bool,
-};
+use super::check_intrinsic_arg_count;
+use crate::helpers::{ToHost, ToSoft, bool_to_simd_element, simd_element_to_bool};
use crate::*;
#[derive(Copy, Clone)]
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index ae70257..507d4f7 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -7,6 +7,7 @@
#![feature(never_type)]
#![feature(try_blocks)]
#![feature(io_error_more)]
+#![feature(if_let_guard)]
#![feature(variant_count)]
#![feature(yeet_expr)]
#![feature(nonzero_ops)]
@@ -158,6 +159,7 @@ pub mod native_lib {
pub use crate::shims::io_error::{EvalContextExt as _, IoError, LibcError};
pub use crate::shims::os_str::EvalContextExt as _;
pub use crate::shims::panic::EvalContextExt as _;
+pub use crate::shims::sig::EvalContextExt as _;
pub use crate::shims::time::EvalContextExt as _;
pub use crate::shims::tls::TlsData;
pub use crate::shims::unwind::{CatchUnwindData, EvalContextExt as _};
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 7271d3f..8f0814a 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -76,13 +76,8 @@ pub struct FrameExtra<'tcx> {
impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Omitting `timing`, it does not support `Debug`.
- let FrameExtra {
- borrow_tracker,
- catch_unwind,
- timing: _,
- is_user_relevant,
- data_race,
- } = self;
+ let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant, data_race } =
+ self;
f.debug_struct("FrameData")
.field("borrow_tracker", borrow_tracker)
.field("catch_unwind", catch_unwind)
@@ -607,6 +602,9 @@ pub struct MiriMachine<'tcx> {
}
impl<'tcx> MiriMachine<'tcx> {
+ /// Create a new MiriMachine.
+ ///
+ /// Invariant: `genmc_ctx.is_some() == config.genmc_config.is_some()`
pub(crate) fn new(
config: &MiriConfig,
layout_cx: LayoutCx<'tcx>,
@@ -630,7 +628,7 @@ pub(crate) fn new(
});
let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
let borrow_tracker = config.borrow_tracker.map(|bt| bt.instantiate_global_state(config));
- let data_race = if config.genmc_mode {
+ let data_race = if config.genmc_config.is_some() {
// `genmc_ctx` persists across executions, so we don't create a new one here.
GlobalDataRaceHandler::Genmc(genmc_ctx.unwrap())
} else if config.data_race_detector {
diff --git a/src/tools/miri/src/shims/aarch64.rs b/src/tools/miri/src/shims/aarch64.rs
index 44ad508..6e422b4 100644
--- a/src/tools/miri/src/shims/aarch64.rs
+++ b/src/tools/miri/src/shims/aarch64.rs
@@ -20,7 +20,7 @@ fn emulate_aarch64_intrinsic(
let unprefixed_name = link_name.as_str().strip_prefix("llvm.aarch64.").unwrap();
match unprefixed_name {
"isb" => {
- let [arg] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [arg] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let arg = this.read_scalar(arg)?.to_i32()?;
match arg {
// SY ("full system scope")
@@ -38,7 +38,8 @@ fn emulate_aarch64_intrinsic(
// `left` input, the second half of the output from the `right` input.
// https://developer.arm.com/architectures/instruction-sets/intrinsics/vpmaxq_u8
"neon.umaxp.v16i8" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 18d6091..bd3914b 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -15,7 +15,7 @@ fn handle_miri_backtrace_size(
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
- let [flags] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [flags] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let flags = this.read_scalar(flags)?.to_u64()?;
if flags != 0 {
@@ -37,7 +37,7 @@ fn handle_miri_get_backtrace(
let ptr_ty = this.machine.layouts.mut_raw_ptr.ty;
let ptr_layout = this.layout_of(ptr_ty)?;
- let [flags, buf] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [flags, buf] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let flags = this.read_scalar(flags)?.to_u64()?;
let buf_place = this.deref_pointer_as(buf, ptr_layout)?;
@@ -117,7 +117,7 @@ fn handle_miri_resolve_frame(
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
- let [ptr, flags] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [ptr, flags] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let flags = this.read_scalar(flags)?.to_u64()?;
@@ -195,7 +195,7 @@ fn handle_miri_resolve_frame_names(
let this = self.eval_context_mut();
let [ptr, flags, name_ptr, filename_ptr] =
- this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let flags = this.read_scalar(flags)?.to_u64()?;
if flags != 0 {
diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs
index 606d1ff..0d4642c 100644
--- a/src/tools/miri/src/shims/files.rs
+++ b/src/tools/miri/src/shims/files.rs
@@ -1,7 +1,7 @@
use std::any::Any;
use std::collections::BTreeMap;
use std::fs::{File, Metadata};
-use std::io::{IsTerminal, Seek, SeekFrom, Write};
+use std::io::{ErrorKind, IsTerminal, Seek, SeekFrom, Write};
use std::marker::CoercePointee;
use std::ops::Deref;
use std::rc::{Rc, Weak};
@@ -167,6 +167,11 @@ fn write<'tcx>(
throw_unsup_format!("cannot write to {}", self.name());
}
+ /// Determines whether this FD non-deterministically has its reads and writes shortened.
+ fn nondet_short_accesses(&self) -> bool {
+ true
+ }
+
/// Seeks to the given offset (which can be relative to the beginning, end, or current position).
/// Returns the new position from the start of the stream.
fn seek<'tcx>(
@@ -334,6 +339,15 @@ fn write<'tcx>(
) -> InterpResult<'tcx> {
assert!(communicate_allowed, "isolation should have prevented even opening a file");
+ if !self.writable {
+ // Linux hosts return EBADF here which we can't translate via the platform-independent
+ // code since it does not map to any `io::ErrorKind` -- so if we don't do anything
+ // special, we'd throw an "unsupported error code" here. Windows returns something that
+ // gets translated to `PermissionDenied`. That seems like a good value so let's just use
+ // this everywhere, even if it means behavior on Unix targets does not match the real
+ // thing.
+ return finish.call(ecx, Err(ErrorKind::PermissionDenied.into()));
+ }
let result = ecx.write_to_host(&self.file, len, ptr)?;
finish.call(ecx, result)
}
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 94cda57..21545b6 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -288,16 +288,17 @@ fn emulate_foreign_item_inner(
match link_name.as_str() {
// Miri-specific extern functions
"miri_start_unwind" => {
- let [payload] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [payload] =
+ this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
this.handle_miri_start_unwind(payload)?;
return interp_ok(EmulateItemResult::NeedsUnwind);
}
"miri_run_provenance_gc" => {
- let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
this.run_provenance_gc();
}
"miri_get_alloc_id" => {
- let [ptr] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [ptr] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr, 0).map_err_kind(|_e| {
err_machine_stop!(TerminationInfo::Abort(format!(
@@ -307,7 +308,8 @@ fn emulate_foreign_item_inner(
this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?;
}
"miri_print_borrow_state" => {
- let [id, show_unnamed] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [id, show_unnamed] =
+ this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let id = this.read_scalar(id)?.to_u64()?;
let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?;
if let Some(id) = std::num::NonZero::new(id).map(AllocId)
@@ -322,7 +324,7 @@ fn emulate_foreign_item_inner(
// This associates a name to a tag. Very useful for debugging, and also makes
// tests more strict.
let [ptr, nth_parent, name] =
- this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let nth_parent = this.read_scalar(nth_parent)?.to_u8()?;
let name = this.read_immediate(name)?;
@@ -335,7 +337,7 @@ fn emulate_foreign_item_inner(
this.give_pointer_debug_name(ptr, nth_parent, &name)?;
}
"miri_static_root" => {
- let [ptr] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [ptr] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr, 0)?;
if offset != Size::ZERO {
@@ -346,7 +348,8 @@ fn emulate_foreign_item_inner(
this.machine.static_roots.push(alloc_id);
}
"miri_host_to_target_path" => {
- let [ptr, out, out_size] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [ptr, out, out_size] =
+ this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let out = this.read_pointer(out)?;
let out_size = this.read_scalar(out_size)?.to_target_usize(this)?;
@@ -382,7 +385,7 @@ fn emulate_foreign_item_inner(
// Writes some bytes to the interpreter's stdout/stderr. See the
// README for details.
"miri_write_to_stdout" | "miri_write_to_stderr" => {
- let [msg] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [msg] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let msg = this.read_immediate(msg)?;
let msg = this.read_byte_slice(&msg)?;
// Note: we're ignoring errors writing to host stdout/stderr.
@@ -396,7 +399,8 @@ fn emulate_foreign_item_inner(
"miri_promise_symbolic_alignment" => {
use rustc_abi::AlignFromBytesError;
- let [ptr, align] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [ptr, align] =
+ this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let align = this.read_target_usize(align)?;
if !align.is_power_of_two() {
@@ -437,12 +441,12 @@ fn emulate_foreign_item_inner(
// Aborting the process.
"exit" => {
- let [code] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [code] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let code = this.read_scalar(code)?.to_i32()?;
throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
}
"abort" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
throw_machine_stop!(TerminationInfo::Abort(
"the program aborted execution".to_owned()
))
@@ -450,7 +454,7 @@ fn emulate_foreign_item_inner(
// Standard C allocation
"malloc" => {
- let [size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [size] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let size = this.read_target_usize(size)?;
if size <= this.max_size_of_val().bytes() {
let res = this.malloc(size, AllocInit::Uninit)?;
@@ -464,7 +468,8 @@ fn emulate_foreign_item_inner(
}
}
"calloc" => {
- let [items, elem_size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [items, elem_size] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let items = this.read_target_usize(items)?;
let elem_size = this.read_target_usize(elem_size)?;
if let Some(size) = this.compute_size_in_bytes(Size::from_bytes(elem_size), items) {
@@ -479,12 +484,13 @@ fn emulate_foreign_item_inner(
}
}
"free" => {
- let [ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
this.free(ptr)?;
}
"realloc" => {
- let [old_ptr, new_size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [old_ptr, new_size] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let old_ptr = this.read_pointer(old_ptr)?;
let new_size = this.read_target_usize(new_size)?;
if new_size <= this.max_size_of_val().bytes() {
@@ -504,7 +510,8 @@ fn emulate_foreign_item_inner(
let default = |ecx: &mut MiriInterpCx<'tcx>| {
// Only call `check_shim` when `#[global_allocator]` isn't used. When that
// macro is used, we act like no shim exists, so that the exported function can run.
- let [size, align] = ecx.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [size, align] =
+ ecx.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let size = ecx.read_target_usize(size)?;
let align = ecx.read_target_usize(align)?;
@@ -537,7 +544,8 @@ fn emulate_foreign_item_inner(
return this.emulate_allocator(|this| {
// See the comment for `__rust_alloc` why `check_shim` is only called in the
// default case.
- let [size, align] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [size, align] =
+ this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let size = this.read_target_usize(size)?;
let align = this.read_target_usize(align)?;
@@ -559,7 +567,7 @@ fn emulate_foreign_item_inner(
// See the comment for `__rust_alloc` why `check_shim` is only called in the
// default case.
let [ptr, old_size, align] =
- ecx.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ ecx.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let ptr = ecx.read_pointer(ptr)?;
let old_size = ecx.read_target_usize(old_size)?;
let align = ecx.read_target_usize(align)?;
@@ -590,7 +598,7 @@ fn emulate_foreign_item_inner(
// See the comment for `__rust_alloc` why `check_shim` is only called in the
// default case.
let [ptr, old_size, align, new_size] =
- this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let old_size = this.read_target_usize(old_size)?;
let align = this.read_target_usize(align)?;
@@ -613,20 +621,21 @@ fn emulate_foreign_item_inner(
}
name if name == this.mangle_internal_symbol("__rust_no_alloc_shim_is_unstable_v2") => {
// This is a no-op shim that only exists to prevent making the allocator shims instantly stable.
- let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
}
name if name
== this.mangle_internal_symbol("__rust_alloc_error_handler_should_panic_v2") =>
{
// Gets the value of the `oom` option.
- let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
let val = this.tcx.sess.opts.unstable_opts.oom.should_panic();
this.write_int(val, dest)?;
}
// C memory handling functions
"memcmp" => {
- let [left, right, n] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, n] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let left = this.read_pointer(left)?;
let right = this.read_pointer(right)?;
let n = Size::from_bytes(this.read_target_usize(n)?);
@@ -650,7 +659,8 @@ fn emulate_foreign_item_inner(
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"memrchr" => {
- let [ptr, val, num] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr, val, num] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let val = this.read_scalar(val)?.to_i32()?;
let num = this.read_target_usize(num)?;
@@ -676,7 +686,8 @@ fn emulate_foreign_item_inner(
}
}
"memchr" => {
- let [ptr, val, num] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr, val, num] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let val = this.read_scalar(val)?.to_i32()?;
let num = this.read_target_usize(num)?;
@@ -699,7 +710,7 @@ fn emulate_foreign_item_inner(
}
}
"strlen" => {
- let [ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
// This reads at least 1 byte, so we are already enforcing that this is a valid pointer.
let n = this.read_c_str(ptr)?.len();
@@ -709,7 +720,7 @@ fn emulate_foreign_item_inner(
)?;
}
"wcslen" => {
- let [ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
// This reads at least 1 byte, so we are already enforcing that this is a valid pointer.
let n = this.read_wchar_t_str(ptr)?.len();
@@ -719,7 +730,8 @@ fn emulate_foreign_item_inner(
)?;
}
"memcpy" => {
- let [ptr_dest, ptr_src, n] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr_dest, ptr_src, n] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let ptr_dest = this.read_pointer(ptr_dest)?;
let ptr_src = this.read_pointer(ptr_src)?;
let n = this.read_target_usize(n)?;
@@ -733,7 +745,8 @@ fn emulate_foreign_item_inner(
this.write_pointer(ptr_dest, dest)?;
}
"strcpy" => {
- let [ptr_dest, ptr_src] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr_dest, ptr_src] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let ptr_dest = this.read_pointer(ptr_dest)?;
let ptr_src = this.read_pointer(ptr_src)?;
@@ -764,7 +777,7 @@ fn emulate_foreign_item_inner(
| "erff"
| "erfcf"
=> {
- let [f] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
+ let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
let f = this.read_scalar(f)?.to_f32()?;
// Using host floats (but it's fine, these operations do not have guaranteed precision).
let f_host = f.to_host();
@@ -802,7 +815,7 @@ fn emulate_foreign_item_inner(
| "atan2f"
| "fdimf"
=> {
- let [f1, f2] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
+ let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
let f1 = this.read_scalar(f1)?.to_f32()?;
let f2 = this.read_scalar(f2)?.to_f32()?;
// underscore case for windows, here and below
@@ -841,7 +854,7 @@ fn emulate_foreign_item_inner(
| "erf"
| "erfc"
=> {
- let [f] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
+ let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
let f = this.read_scalar(f)?.to_f64()?;
// Using host floats (but it's fine, these operations do not have guaranteed precision).
let f_host = f.to_host();
@@ -879,7 +892,7 @@ fn emulate_foreign_item_inner(
| "atan2"
| "fdim"
=> {
- let [f1, f2] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
+ let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
let f1 = this.read_scalar(f1)?.to_f64()?;
let f2 = this.read_scalar(f2)?.to_f64()?;
// underscore case for windows, here and below
@@ -908,7 +921,7 @@ fn emulate_foreign_item_inner(
| "ldexp"
| "scalbn"
=> {
- let [x, exp] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
+ let [x, exp] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
// For radix-2 (binary) systems, `ldexp` and `scalbn` are the same.
let x = this.read_scalar(x)?.to_f64()?;
let exp = this.read_scalar(exp)?.to_i32()?;
@@ -918,7 +931,7 @@ fn emulate_foreign_item_inner(
this.write_scalar(res, dest)?;
}
"lgammaf_r" => {
- let [x, signp] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [x, signp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let x = this.read_scalar(x)?.to_f32()?;
let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?;
@@ -934,7 +947,7 @@ fn emulate_foreign_item_inner(
this.write_scalar(res, dest)?;
}
"lgamma_r" => {
- let [x, signp] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [x, signp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let x = this.read_scalar(x)?.to_f64()?;
let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?;
@@ -952,7 +965,8 @@ fn emulate_foreign_item_inner(
// LLVM intrinsics
"llvm.prefetch" => {
- let [p, rw, loc, ty] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [p, rw, loc, ty] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let _ = this.read_pointer(p)?;
let rw = this.read_scalar(rw)?.to_i32()?;
@@ -979,7 +993,7 @@ fn emulate_foreign_item_inner(
// Used to implement the x86 `_mm{,256,512}_popcnt_epi{8,16,32,64}` and wasm
// `{i,u}8x16_popcnt` functions.
name if name.starts_with("llvm.ctpop.v") => {
- let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (op, op_len) = this.project_to_simd(op)?;
let (dest, dest_len) = this.project_to_simd(dest)?;
@@ -1015,7 +1029,7 @@ fn emulate_foreign_item_inner(
}
// FIXME: Move this to an `arm` submodule.
"llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => {
- let [arg] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [arg] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let arg = this.read_scalar(arg)?.to_i32()?;
// Note that different arguments might have different target feature requirements.
match arg {
diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs
index 2a77098..7f594d4 100644
--- a/src/tools/miri/src/shims/mod.rs
+++ b/src/tools/miri/src/shims/mod.rs
@@ -18,6 +18,7 @@
pub mod io_error;
pub mod os_str;
pub mod panic;
+pub mod sig;
pub mod time;
pub mod tls;
pub mod unwind;
diff --git a/src/tools/miri/src/shims/sig.rs b/src/tools/miri/src/shims/sig.rs
new file mode 100644
index 0000000..bc5e7f5
--- /dev/null
+++ b/src/tools/miri/src/shims/sig.rs
@@ -0,0 +1,266 @@
+//! Everything related to checking the signature of shim invocations.
+
+use rustc_abi::{CanonAbi, ExternAbi};
+use rustc_hir::Safety;
+use rustc_middle::ty::{Binder, FnSig, Ty};
+use rustc_span::Symbol;
+use rustc_target::callconv::FnAbi;
+
+use crate::*;
+
+/// Describes the expected signature of a shim.
+pub struct ShimSig<'tcx, const ARGS: usize> {
+ pub abi: ExternAbi,
+ pub args: [Ty<'tcx>; ARGS],
+ pub ret: Ty<'tcx>,
+}
+
+/// Construct a `ShimSig` with convenient syntax:
+/// ```rust,ignore
+/// shim_sig!(this, extern "C" fn (*const T, i32) -> usize)
+/// ```
+#[macro_export]
+macro_rules! shim_sig {
+ (extern $abi:literal fn($($arg:ty),*) -> $ret:ty) => {
+ |this| $crate::shims::sig::ShimSig {
+ abi: std::str::FromStr::from_str($abi).expect("incorrect abi specified"),
+ args: [$(shim_sig_arg!(this, $arg)),*],
+ ret: shim_sig_arg!(this, $ret),
+ }
+ };
+}
+
+/// Helper for `shim_sig!`.
+#[macro_export]
+macro_rules! shim_sig_arg {
+ // Unfortuantely we cannot take apart a `ty`-typed token at compile time,
+ // so we have to stringify it and match at runtime.
+ ($this:ident, $x:ty) => {{
+ match stringify!($x) {
+ "i8" => $this.tcx.types.i8,
+ "i16" => $this.tcx.types.i16,
+ "i32" => $this.tcx.types.i32,
+ "i64" => $this.tcx.types.i64,
+ "i128" => $this.tcx.types.i128,
+ "isize" => $this.tcx.types.isize,
+ "u8" => $this.tcx.types.u8,
+ "u16" => $this.tcx.types.u16,
+ "u32" => $this.tcx.types.u32,
+ "u64" => $this.tcx.types.u64,
+ "u128" => $this.tcx.types.u128,
+ "usize" => $this.tcx.types.usize,
+ "()" => $this.tcx.types.unit,
+ "*const _" => $this.machine.layouts.const_raw_ptr.ty,
+ "*mut _" => $this.machine.layouts.mut_raw_ptr.ty,
+ ty if let Some(libc_ty) = ty.strip_prefix("libc::") => $this.libc_ty_layout(libc_ty).ty,
+ ty => panic!("unsupported signature type {ty:?}"),
+ }
+ }};
+}
+
+/// Helper function to compare two ABIs.
+fn check_shim_abi<'tcx>(
+ this: &MiriInterpCx<'tcx>,
+ callee_abi: &FnAbi<'tcx, Ty<'tcx>>,
+ caller_abi: &FnAbi<'tcx, Ty<'tcx>>,
+) -> InterpResult<'tcx> {
+ if callee_abi.conv != caller_abi.conv {
+ throw_ub_format!(
+ r#"calling a function with calling convention "{callee}" using caller calling convention "{caller}""#,
+ callee = callee_abi.conv,
+ caller = caller_abi.conv,
+ );
+ }
+ if callee_abi.can_unwind && !caller_abi.can_unwind {
+ throw_ub_format!(
+ "ABI mismatch: callee may unwind, but caller-side signature prohibits unwinding",
+ );
+ }
+ if caller_abi.c_variadic && !callee_abi.c_variadic {
+ throw_ub_format!(
+ "ABI mismatch: calling a non-variadic function with a variadic caller-side signature"
+ );
+ }
+ if !caller_abi.c_variadic && callee_abi.c_variadic {
+ throw_ub_format!(
+ "ABI mismatch: calling a variadic function with a non-variadic caller-side signature"
+ );
+ }
+
+ if callee_abi.fixed_count != caller_abi.fixed_count {
+ throw_ub_format!(
+ "ABI mismatch: expected {} arguments, found {} arguments ",
+ callee_abi.fixed_count,
+ caller_abi.fixed_count
+ );
+ }
+
+ if !this.check_argument_compat(&caller_abi.ret, &callee_abi.ret)? {
+ throw_ub!(AbiMismatchReturn {
+ caller_ty: caller_abi.ret.layout.ty,
+ callee_ty: callee_abi.ret.layout.ty
+ });
+ }
+
+ for (idx, (caller_arg, callee_arg)) in
+ caller_abi.args.iter().zip(callee_abi.args.iter()).enumerate()
+ {
+ if !this.check_argument_compat(caller_arg, callee_arg)? {
+ throw_ub!(AbiMismatchArgument {
+ arg_idx: idx,
+ caller_ty: caller_abi.args[idx].layout.ty,
+ callee_ty: callee_abi.args[idx].layout.ty
+ });
+ }
+ }
+
+ interp_ok(())
+}
+
+fn check_shim_symbol_clash<'tcx>(
+ this: &mut MiriInterpCx<'tcx>,
+ link_name: Symbol,
+) -> InterpResult<'tcx, ()> {
+ if let Some((body, instance)) = this.lookup_exported_symbol(link_name)? {
+ // If compiler-builtins is providing the symbol, then don't treat it as a clash.
+ // We'll use our built-in implementation in `emulate_foreign_item_inner` for increased
+ // performance. Note that this means we won't catch any undefined behavior in
+ // compiler-builtins when running other crates, but Miri can still be run on
+ // compiler-builtins itself (or any crate that uses it as a normal dependency)
+ if this.tcx.is_compiler_builtins(instance.def_id().krate) {
+ return interp_ok(());
+ }
+
+ throw_machine_stop!(TerminationInfo::SymbolShimClashing {
+ link_name,
+ span: body.span.data(),
+ })
+ }
+ interp_ok(())
+}
+
+impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
+pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+ fn check_shim_sig_lenient<'a, const N: usize>(
+ &mut self,
+ abi: &FnAbi<'tcx, Ty<'tcx>>,
+ exp_abi: CanonAbi,
+ link_name: Symbol,
+ args: &'a [OpTy<'tcx>],
+ ) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
+ let this = self.eval_context_mut();
+ check_shim_symbol_clash(this, link_name)?;
+
+ if abi.conv != exp_abi {
+ throw_ub_format!(
+ r#"calling a function with calling convention "{exp_abi}" using caller calling convention "{}""#,
+ abi.conv
+ );
+ }
+ if abi.c_variadic {
+ throw_ub_format!(
+ "calling a non-variadic function with a variadic caller-side signature"
+ );
+ }
+
+ if let Ok(ops) = args.try_into() {
+ return interp_ok(ops);
+ }
+ throw_ub_format!(
+ "incorrect number of arguments for `{link_name}`: got {}, expected {}",
+ args.len(),
+ N
+ )
+ }
+
+ /// Check that the given `caller_fn_abi` matches the expected ABI described by `shim_sig`, and
+ /// then returns the list of arguments.
+ fn check_shim_sig<'a, const N: usize>(
+ &mut self,
+ shim_sig: fn(&MiriInterpCx<'tcx>) -> ShimSig<'tcx, N>,
+ link_name: Symbol,
+ caller_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+ caller_args: &'a [OpTy<'tcx>],
+ ) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
+ let this = self.eval_context_mut();
+ let shim_sig = shim_sig(this);
+
+ // Compute full callee ABI.
+ let mut inputs_and_output = Vec::with_capacity(N.strict_add(1));
+ inputs_and_output.extend(&shim_sig.args);
+ inputs_and_output.push(shim_sig.ret);
+ let fn_sig_binder = Binder::dummy(FnSig {
+ inputs_and_output: this.machine.tcx.mk_type_list(&inputs_and_output),
+ c_variadic: false,
+ // This does not matter for the ABI.
+ safety: Safety::Safe,
+ abi: shim_sig.abi,
+ });
+ let callee_fn_abi = this.fn_abi_of_fn_ptr(fn_sig_binder, Default::default())?;
+
+ // Check everything.
+ check_shim_abi(this, callee_fn_abi, caller_fn_abi)?;
+ check_shim_symbol_clash(this, link_name)?;
+
+ // Return arguments.
+ if let Ok(ops) = caller_args.try_into() {
+ return interp_ok(ops);
+ }
+ unreachable!()
+ }
+
+ /// Check shim for variadic function.
+ /// Returns a tuple that consisting of an array of fixed args, and a slice of varargs.
+ fn check_shim_sig_variadic_lenient<'a, const N: usize>(
+ &mut self,
+ abi: &FnAbi<'tcx, Ty<'tcx>>,
+ exp_abi: CanonAbi,
+ link_name: Symbol,
+ args: &'a [OpTy<'tcx>],
+ ) -> InterpResult<'tcx, (&'a [OpTy<'tcx>; N], &'a [OpTy<'tcx>])>
+ where
+ &'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>,
+ {
+ let this = self.eval_context_mut();
+ check_shim_symbol_clash(this, link_name)?;
+
+ if abi.conv != exp_abi {
+ throw_ub_format!(
+ r#"calling a function with calling convention "{exp_abi}" using caller calling convention "{}""#,
+ abi.conv
+ );
+ }
+ if !abi.c_variadic {
+ throw_ub_format!(
+ "calling a variadic function with a non-variadic caller-side signature"
+ );
+ }
+ if abi.fixed_count != u32::try_from(N).unwrap() {
+ throw_ub_format!(
+ "incorrect number of fixed arguments for variadic function `{}`: got {}, expected {N}",
+ link_name.as_str(),
+ abi.fixed_count
+ )
+ }
+ if let Some(args) = args.split_first_chunk() {
+ return interp_ok(args);
+ }
+ panic!("mismatch between signature and `args` slice");
+ }
+}
+
+/// Check that the number of varargs is at least the minimum what we expect.
+/// Fixed args should not be included.
+pub fn check_min_vararg_count<'a, 'tcx, const N: usize>(
+ name: &'a str,
+ args: &'a [OpTy<'tcx>],
+) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
+ if let Some((ops, _)) = args.split_first_chunk() {
+ return interp_ok(ops);
+ }
+ throw_ub_format!(
+ "not enough variadic arguments for `{name}`: got {}, expected at least {}",
+ args.len(),
+ N
+ )
+}
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index eb21abc..b5b3579 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -17,73 +17,71 @@ pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Du
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+ fn parse_clockid(&self, clk_id: Scalar) -> Option<TimeoutClock> {
+ // This clock support is deliberately minimal because a lot of clock types have fiddly
+ // properties (is it possible for Miri to be suspended independently of the host?). If you
+ // have a use for another clock type, please open an issue.
+ let this = self.eval_context_ref();
+
+ // Portable names that exist everywhere.
+ if clk_id == this.eval_libc("CLOCK_REALTIME") {
+ return Some(TimeoutClock::RealTime);
+ } else if clk_id == this.eval_libc("CLOCK_MONOTONIC") {
+ return Some(TimeoutClock::Monotonic);
+ }
+
+ // Some further platform-specific names we support.
+ match this.tcx.sess.target.os.as_ref() {
+ "linux" | "freebsd" | "android" => {
+ // Linux further distinguishes regular and "coarse" clocks, but the "coarse" version
+ // is just specified to be "faster and less precise", so we treat it like normal
+ // clocks.
+ if clk_id == this.eval_libc("CLOCK_REALTIME_COARSE") {
+ return Some(TimeoutClock::RealTime);
+ } else if clk_id == this.eval_libc("CLOCK_MONOTONIC_COARSE") {
+ return Some(TimeoutClock::Monotonic);
+ }
+ }
+ "macos" => {
+ // `CLOCK_UPTIME_RAW` supposed to not increment while the system is asleep... but
+ // that's not really something a program running inside Miri can tell, anyway.
+ // We need to support it because std uses it.
+ if clk_id == this.eval_libc("CLOCK_UPTIME_RAW") {
+ return Some(TimeoutClock::Monotonic);
+ }
+ }
+ _ => {}
+ }
+
+ None
+ }
+
fn clock_gettime(
&mut self,
clk_id_op: &OpTy<'tcx>,
tp_op: &OpTy<'tcx>,
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
- // This clock support is deliberately minimal because a lot of clock types have fiddly
- // properties (is it possible for Miri to be suspended independently of the host?). If you
- // have a use for another clock type, please open an issue.
-
let this = self.eval_context_mut();
this.assert_target_os_is_unix("clock_gettime");
- let clockid_t_size = this.libc_ty_layout("clockid_t").size;
- let clk_id = this.read_scalar(clk_id_op)?.to_int(clockid_t_size)?;
+ let clk_id = this.read_scalar(clk_id_op)?;
let tp = this.deref_pointer_as(tp_op, this.libc_ty_layout("timespec"))?;
- let absolute_clocks;
- let mut relative_clocks;
-
- match this.tcx.sess.target.os.as_ref() {
- "linux" | "freebsd" | "android" => {
- // Linux, Android, and FreeBSD have two main kinds of clocks. REALTIME clocks return the actual time since the
- // Unix epoch, including effects which may cause time to move backwards such as NTP.
- // Linux further distinguishes regular and "coarse" clocks, but the "coarse" version
- // is just specified to be "faster and less precise", so we implement both the same way.
- absolute_clocks = vec![
- this.eval_libc("CLOCK_REALTIME").to_int(clockid_t_size)?,
- this.eval_libc("CLOCK_REALTIME_COARSE").to_int(clockid_t_size)?,
- ];
- // The second kind is MONOTONIC clocks for which 0 is an arbitrary time point, but they are
- // never allowed to go backwards. We don't need to do any additional monotonicity
- // enforcement because std::time::Instant already guarantees that it is monotonic.
- relative_clocks = vec![
- this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)?,
- this.eval_libc("CLOCK_MONOTONIC_COARSE").to_int(clockid_t_size)?,
- ];
+ let duration = match this.parse_clockid(clk_id) {
+ Some(TimeoutClock::RealTime) => {
+ this.check_no_isolation("`clock_gettime` with `REALTIME` clocks")?;
+ system_time_to_duration(&SystemTime::now())?
}
- "macos" => {
- absolute_clocks = vec![this.eval_libc("CLOCK_REALTIME").to_int(clockid_t_size)?];
- relative_clocks = vec![this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)?];
- // `CLOCK_UPTIME_RAW` supposed to not increment while the system is asleep... but
- // that's not really something a program running inside Miri can tell, anyway.
- // We need to support it because std uses it.
- relative_clocks.push(this.eval_libc("CLOCK_UPTIME_RAW").to_int(clockid_t_size)?);
+ Some(TimeoutClock::Monotonic) =>
+ this.machine
+ .monotonic_clock
+ .now()
+ .duration_since(this.machine.monotonic_clock.epoch()),
+ None => {
+ return this.set_last_error_and_return(LibcError("EINVAL"), dest);
}
- "solaris" | "illumos" => {
- // The REALTIME clock returns the actual time since the Unix epoch.
- absolute_clocks = vec![this.eval_libc("CLOCK_REALTIME").to_int(clockid_t_size)?];
- // MONOTONIC, in the other hand, is the high resolution, non-adjustable
- // clock from an arbitrary time in the past.
- // Note that the man page mentions HIGHRES but it is just
- // an alias of MONOTONIC and the libc crate does not expose it anyway.
- // https://docs.oracle.com/cd/E23824_01/html/821-1465/clock-gettime-3c.html
- relative_clocks = vec![this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)?];
- }
- target => throw_unsup_format!("`clock_gettime` is not supported on target OS {target}"),
- }
-
- let duration = if absolute_clocks.contains(&clk_id) {
- this.check_no_isolation("`clock_gettime` with `REALTIME` clocks")?;
- system_time_to_duration(&SystemTime::now())?
- } else if relative_clocks.contains(&clk_id) {
- this.machine.monotonic_clock.now().duration_since(this.machine.monotonic_clock.epoch())
- } else {
- return this.set_last_error_and_return(LibcError("EINVAL"), dest);
};
let tv_sec = duration.as_secs();
diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs
index 690b529..04c5d28 100644
--- a/src/tools/miri/src/shims/unix/android/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs
@@ -26,29 +26,30 @@ fn emulate_foreign_item_inner(
match link_name.as_str() {
// epoll, eventfd
"epoll_create1" => {
- let [flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.epoll_create1(flag)?;
this.write_scalar(result, dest)?;
}
"epoll_ctl" => {
- let [epfd, op, fd, event] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [epfd, op, fd, event] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.epoll_ctl(epfd, op, fd, event)?;
this.write_scalar(result, dest)?;
}
"epoll_wait" => {
let [epfd, events, maxevents, timeout] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
}
"eventfd" => {
- let [val, flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [val, flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.eventfd(val, flag)?;
this.write_scalar(result, dest)?;
}
// Miscellaneous
"__errno" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs
index 5d17d6c..4e7b21d 100644
--- a/src/tools/miri/src/shims/unix/android/thread.rs
+++ b/src/tools/miri/src/shims/unix/android/thread.rs
@@ -3,7 +3,7 @@
use rustc_span::Symbol;
use rustc_target::callconv::FnAbi;
-use crate::helpers::check_min_vararg_count;
+use crate::shims::sig::check_min_vararg_count;
use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult};
use crate::*;
@@ -16,7 +16,7 @@ pub fn prctl<'tcx>(
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
- let ([op], varargs) = ecx.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
+ let ([op], varargs) = ecx.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
// FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch.
let pr_set_name = 15;
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index 71102d9..e226a55 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -4,10 +4,11 @@
use std::io;
use std::io::ErrorKind;
+use rand::Rng;
use rustc_abi::Size;
-use crate::helpers::check_min_vararg_count;
use crate::shims::files::FileDescription;
+use crate::shims::sig::check_min_vararg_count;
use crate::shims::unix::linux_like::epoll::EpollReadyEvents;
use crate::shims::unix::*;
use crate::*;
@@ -263,9 +264,18 @@ fn read(
return this.set_last_error_and_return(LibcError("EBADF"), dest);
};
+ // Non-deterministically decide to further reduce the count, simulating a partial read (but
+ // never to 0, that has different behavior).
+ let count =
+ if fd.nondet_short_accesses() && count >= 2 && this.machine.rng.get_mut().random() {
+ count / 2
+ } else {
+ count
+ };
+
trace!("read: FD mapped to {fd:?}");
// We want to read at most `count` bytes. We are sure that `count` is not negative
- // because it was a target's `usize`. Also we are sure that its smaller than
+ // because it was a target's `usize`. Also we are sure that it's smaller than
// `usize::MAX` because it is bounded by the host's `isize`.
let finish = {
@@ -328,6 +338,15 @@ fn write(
return this.set_last_error_and_return(LibcError("EBADF"), dest);
};
+ // Non-deterministically decide to further reduce the count, simulating a partial write (but
+ // never to 0, that has different behavior).
+ let count =
+ if fd.nondet_short_accesses() && count >= 2 && this.machine.rng.get_mut().random() {
+ count / 2
+ } else {
+ count
+ };
+
let finish = {
let dest = dest.clone();
callback!(
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 548eabb..55906f4 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -1,7 +1,7 @@
use std::ffi::OsStr;
use std::str;
-use rustc_abi::{CanonAbi, ExternAbi, Size};
+use rustc_abi::{CanonAbi, Size};
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::FnAbi;
@@ -14,7 +14,7 @@
use crate::concurrency::cpu_affinity::CpuAffinityMask;
use crate::shims::alloc::EvalContextExt as _;
use crate::shims::unix::*;
-use crate::*;
+use crate::{shim_sig, *};
pub fn is_dyn_sym(name: &str, target_os: &str) -> bool {
match name {
@@ -111,40 +111,30 @@ fn emulate_foreign_item_inner(
match link_name.as_str() {
// Environment related shims
"getenv" => {
- let [name] = this.check_shim_abi(
+ let [name] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*const _) -> *mut _),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.const_raw_ptr.ty],
- this.machine.layouts.mut_raw_ptr.ty,
args,
)?;
let result = this.getenv(name)?;
this.write_pointer(result, dest)?;
}
"unsetenv" => {
- let [name] = this.check_shim_abi(
+ let [name] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*const _) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.const_raw_ptr.ty],
- this.tcx.types.i32,
args,
)?;
let result = this.unsetenv(name)?;
this.write_scalar(result, dest)?;
}
"setenv" => {
- let [name, value, overwrite] = this.check_shim_abi(
+ let [name, value, overwrite] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*const _, *const _, i32) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [
- this.machine.layouts.const_raw_ptr.ty,
- this.machine.layouts.const_raw_ptr.ty,
- this.tcx.types.i32,
- ],
- this.tcx.types.i32,
args,
)?;
this.read_scalar(overwrite)?.to_i32()?;
@@ -152,48 +142,40 @@ fn emulate_foreign_item_inner(
this.write_scalar(result, dest)?;
}
"getcwd" => {
- let [buf, size] = this.check_shim_abi(
+ let [buf, size] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*mut _, usize) -> *mut _),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.usize],
- this.machine.layouts.mut_raw_ptr.ty,
args,
)?;
let result = this.getcwd(buf, size)?;
this.write_pointer(result, dest)?;
}
"chdir" => {
- let [path] = this.check_shim_abi(
+ let [path] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*const _) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.const_raw_ptr.ty],
- this.tcx.types.i32,
args,
)?;
let result = this.chdir(path)?;
this.write_scalar(result, dest)?;
}
"getpid" => {
- let [] = this.check_shim_abi(
+ let [] = this.check_shim_sig(
+ shim_sig!(extern "C" fn() -> libc::pid_t),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [],
- this.libc_ty_layout("pid_t").ty,
args,
)?;
let result = this.getpid()?;
this.write_scalar(result, dest)?;
}
"sysconf" => {
- let [val] = this.check_shim_abi(
+ let [val] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32) -> isize),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.tcx.types.i32],
- this.tcx.types.isize,
args,
)?;
let result = this.sysconf(val)?;
@@ -201,12 +183,10 @@ fn emulate_foreign_item_inner(
}
// File descriptors
"read" => {
- let [fd, buf, count] = this.check_shim_abi(
+ let [fd, buf, count] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, *mut _, usize) -> isize),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.tcx.types.i32, this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.usize],
- this.tcx.types.isize,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
@@ -215,16 +195,10 @@ fn emulate_foreign_item_inner(
this.read(fd, buf, count, None, dest)?;
}
"write" => {
- let [fd, buf, n] = this.check_shim_abi(
+ let [fd, buf, n] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, *const _, usize) -> isize),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [
- this.tcx.types.i32,
- this.machine.layouts.const_raw_ptr.ty,
- this.tcx.types.usize,
- ],
- this.tcx.types.isize,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
@@ -234,98 +208,64 @@ fn emulate_foreign_item_inner(
this.write(fd, buf, count, None, dest)?;
}
"pread" => {
- let off_t = this.libc_ty_layout("off_t");
- let [fd, buf, count, offset] = this.check_shim_abi(
+ let [fd, buf, count, offset] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off_t) -> isize),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [
- this.tcx.types.i32,
- this.machine.layouts.mut_raw_ptr.ty,
- this.tcx.types.usize,
- off_t.ty,
- ],
- this.tcx.types.isize,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(count)?;
- let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
+ let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
this.read(fd, buf, count, Some(offset), dest)?;
}
"pwrite" => {
- let off_t = this.libc_ty_layout("off_t");
- let [fd, buf, n, offset] = this.check_shim_abi(
+ let [fd, buf, n, offset] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, *const _, usize, libc::off_t) -> isize),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [
- this.tcx.types.i32,
- this.machine.layouts.const_raw_ptr.ty,
- this.tcx.types.usize,
- off_t.ty,
- ],
- this.tcx.types.isize,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(n)?;
- let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
+ let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
this.write(fd, buf, count, Some(offset), dest)?;
}
"pread64" => {
- let off64_t = this.libc_ty_layout("off64_t");
- let [fd, buf, count, offset] = this.check_shim_abi(
+ let [fd, buf, count, offset] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off64_t) -> isize),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [
- this.tcx.types.i32,
- this.machine.layouts.mut_raw_ptr.ty,
- this.tcx.types.usize,
- off64_t.ty,
- ],
- this.tcx.types.isize,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(count)?;
- let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
+ let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
this.read(fd, buf, count, Some(offset), dest)?;
}
"pwrite64" => {
- let off64_t = this.libc_ty_layout("off64_t");
- let [fd, buf, n, offset] = this.check_shim_abi(
+ let [fd, buf, n, offset] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, *const _, usize, libc::off64_t) -> isize),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [
- this.tcx.types.i32,
- this.machine.layouts.const_raw_ptr.ty,
- this.tcx.types.usize,
- off64_t.ty,
- ],
- this.tcx.types.isize,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(n)?;
- let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
+ let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
this.write(fd, buf, count, Some(offset), dest)?;
}
"close" => {
- let [fd] = this.check_shim_abi(
+ let [fd] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.tcx.types.i32],
- this.tcx.types.i32,
args,
)?;
let result = this.close(fd)?;
@@ -333,17 +273,15 @@ fn emulate_foreign_item_inner(
}
"fcntl" => {
let ([fd_num, cmd], varargs) =
- this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.fcntl(fd_num, cmd, varargs)?;
this.write_scalar(result, dest)?;
}
"dup" => {
- let [old_fd] = this.check_shim_abi(
+ let [old_fd] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.tcx.types.i32],
- this.tcx.types.i32,
args,
)?;
let old_fd = this.read_scalar(old_fd)?.to_i32()?;
@@ -351,12 +289,10 @@ fn emulate_foreign_item_inner(
this.write_scalar(new_fd, dest)?;
}
"dup2" => {
- let [old_fd, new_fd] = this.check_shim_abi(
+ let [old_fd, new_fd] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, i32) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.tcx.types.i32, this.tcx.types.i32],
- this.tcx.types.i32,
args,
)?;
let old_fd = this.read_scalar(old_fd)?.to_i32()?;
@@ -367,12 +303,10 @@ fn emulate_foreign_item_inner(
"flock" => {
// Currently this function does not exist on all Unixes, e.g. on Solaris.
this.check_target_os(&["linux", "freebsd", "macos", "illumos"], link_name)?;
- let [fd, op] = this.check_shim_abi(
+ let [fd, op] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, i32) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.tcx.types.i32, this.tcx.types.i32],
- this.tcx.types.i32,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
@@ -386,230 +320,187 @@ fn emulate_foreign_item_inner(
// `open` is variadic, the third argument is only present when the second argument
// has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
let ([path_raw, flag], varargs) =
- this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.open(path_raw, flag, varargs)?;
this.write_scalar(result, dest)?;
}
"unlink" => {
- let [path] = this.check_shim_abi(
+ let [path] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*const _) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.const_raw_ptr.ty],
- this.tcx.types.i32,
args,
)?;
let result = this.unlink(path)?;
this.write_scalar(result, dest)?;
}
"symlink" => {
- let [target, linkpath] = this.check_shim_abi(
+ let [target, linkpath] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*const _, *const _) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.const_raw_ptr.ty],
- this.tcx.types.i32,
args,
)?;
let result = this.symlink(target, linkpath)?;
this.write_scalar(result, dest)?;
}
"rename" => {
- let [oldpath, newpath] = this.check_shim_abi(
+ let [oldpath, newpath] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*const _, *const _) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.const_raw_ptr.ty],
- this.tcx.types.i32,
args,
)?;
let result = this.rename(oldpath, newpath)?;
this.write_scalar(result, dest)?;
}
"mkdir" => {
- let [path, mode] = this.check_shim_abi(
+ let [path, mode] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*const _, libc::mode_t) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.const_raw_ptr.ty, this.libc_ty_layout("mode_t").ty],
- this.tcx.types.i32,
args,
)?;
let result = this.mkdir(path, mode)?;
this.write_scalar(result, dest)?;
}
"rmdir" => {
- let [path] = this.check_shim_abi(
+ let [path] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*const _) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.const_raw_ptr.ty],
- this.tcx.types.i32,
args,
)?;
let result = this.rmdir(path)?;
this.write_scalar(result, dest)?;
}
"opendir" => {
- let [name] = this.check_shim_abi(
+ let [name] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*const _) -> *mut _),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.const_raw_ptr.ty],
- this.machine.layouts.mut_raw_ptr.ty,
args,
)?;
let result = this.opendir(name)?;
this.write_scalar(result, dest)?;
}
"closedir" => {
- let [dirp] = this.check_shim_abi(
+ let [dirp] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*mut _) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.mut_raw_ptr.ty],
- this.tcx.types.i32,
args,
)?;
let result = this.closedir(dirp)?;
this.write_scalar(result, dest)?;
}
"lseek64" => {
- let off64_t = this.libc_ty_layout("off64_t");
- let [fd, offset, whence] = this.check_shim_abi(
+ let [fd, offset, whence] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.tcx.types.i32, off64_t.ty, this.tcx.types.i32],
- off64_t.ty,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
- let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
+ let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
let whence = this.read_scalar(whence)?.to_i32()?;
this.lseek64(fd, offset, whence, dest)?;
}
"lseek" => {
- let off_t = this.libc_ty_layout("off_t");
- let [fd, offset, whence] = this.check_shim_abi(
+ let [fd, offset, whence] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, libc::off_t, i32) -> libc::off_t),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.tcx.types.i32, off_t.ty, this.tcx.types.i32],
- off_t.ty,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
- let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
+ let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
let whence = this.read_scalar(whence)?.to_i32()?;
this.lseek64(fd, offset, whence, dest)?;
}
"ftruncate64" => {
- let off64_t = this.libc_ty_layout("off64_t");
- let [fd, length] = this.check_shim_abi(
+ let [fd, length] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, libc::off64_t) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.tcx.types.i32, off64_t.ty],
- this.tcx.types.i32,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
- let length = this.read_scalar(length)?.to_int(off64_t.size)?;
+ let length = this.read_scalar(length)?.to_int(length.layout.size)?;
let result = this.ftruncate64(fd, length)?;
this.write_scalar(result, dest)?;
}
"ftruncate" => {
- let off_t = this.libc_ty_layout("off_t");
- let [fd, length] = this.check_shim_abi(
+ let [fd, length] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, libc::off_t) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.tcx.types.i32, off_t.ty],
- this.tcx.types.i32,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
- let length = this.read_scalar(length)?.to_int(off_t.size)?;
+ let length = this.read_scalar(length)?.to_int(length.layout.size)?;
let result = this.ftruncate64(fd, length)?;
this.write_scalar(result, dest)?;
}
"fsync" => {
- let [fd] = this.check_shim_abi(
+ let [fd] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.tcx.types.i32],
- this.tcx.types.i32,
args,
)?;
let result = this.fsync(fd)?;
this.write_scalar(result, dest)?;
}
"fdatasync" => {
- let [fd] = this.check_shim_abi(
+ let [fd] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.tcx.types.i32],
- this.tcx.types.i32,
args,
)?;
let result = this.fdatasync(fd)?;
this.write_scalar(result, dest)?;
}
"readlink" => {
- let [pathname, buf, bufsize] = this.check_shim_abi(
+ let [pathname, buf, bufsize] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*const _, *mut _, usize) -> isize),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [
- this.machine.layouts.const_raw_ptr.ty,
- this.machine.layouts.mut_raw_ptr.ty,
- this.tcx.types.usize,
- ],
- this.tcx.types.isize,
args,
)?;
let result = this.readlink(pathname, buf, bufsize)?;
this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
}
"posix_fadvise" => {
- let off_t = this.libc_ty_layout("off_t");
- let [fd, offset, len, advice] = this.check_shim_abi(
+ let [fd, offset, len, advice] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t, i32) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.tcx.types.i32, off_t.ty, off_t.ty, this.tcx.types.i32],
- this.tcx.types.i32,
args,
)?;
this.read_scalar(fd)?.to_i32()?;
- this.read_scalar(offset)?.to_int(off_t.size)?;
- this.read_scalar(len)?.to_int(off_t.size)?;
+ this.read_scalar(offset)?.to_int(offset.layout.size)?;
+ this.read_scalar(len)?.to_int(len.layout.size)?;
this.read_scalar(advice)?.to_i32()?;
// fadvise is only informational, we can ignore it.
this.write_null(dest)?;
}
"realpath" => {
- let [path, resolved_path] = this.check_shim_abi(
+ let [path, resolved_path] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
- this.machine.layouts.mut_raw_ptr.ty,
args,
)?;
let result = this.realpath(path, resolved_path)?;
this.write_scalar(result, dest)?;
}
"mkstemp" => {
- let [template] = this.check_shim_abi(
+ let [template] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*mut _) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.mut_raw_ptr.ty],
- this.tcx.types.i32,
args,
)?;
let result = this.mkstemp(template)?;
@@ -618,29 +509,20 @@ fn emulate_foreign_item_inner(
// Unnamed sockets and pipes
"socketpair" => {
- let [domain, type_, protocol, sv] = this.check_shim_abi(
+ let [domain, type_, protocol, sv] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(i32, i32, i32, *mut _) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [
- this.tcx.types.i32,
- this.tcx.types.i32,
- this.tcx.types.i32,
- this.machine.layouts.mut_raw_ptr.ty,
- ],
- this.tcx.types.i32,
args,
)?;
let result = this.socketpair(domain, type_, protocol, sv)?;
this.write_scalar(result, dest)?;
}
"pipe" => {
- let [pipefd] = this.check_shim_abi(
+ let [pipefd] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*mut _) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.mut_raw_ptr.ty],
- this.tcx.types.i32,
args,
)?;
let result = this.pipe2(pipefd, /*flags*/ None)?;
@@ -649,12 +531,10 @@ fn emulate_foreign_item_inner(
"pipe2" => {
// Currently this function does not exist on all Unixes, e.g. on macOS.
this.check_target_os(&["linux", "freebsd", "solaris", "illumos"], link_name)?;
- let [pipefd, flags] = this.check_shim_abi(
+ let [pipefd, flags] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*mut _, i32) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.i32],
- this.tcx.types.i32,
args,
)?;
let result = this.pipe2(pipefd, Some(flags))?;
@@ -663,36 +543,30 @@ fn emulate_foreign_item_inner(
// Time
"gettimeofday" => {
- let [tv, tz] = this.check_shim_abi(
+ let [tv, tz] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*mut _, *mut _) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.mut_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
- this.tcx.types.i32,
args,
)?;
let result = this.gettimeofday(tv, tz)?;
this.write_scalar(result, dest)?;
}
"localtime_r" => {
- let [timep, result_op] = this.check_shim_abi(
+ let [timep, result_op] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
- this.machine.layouts.mut_raw_ptr.ty,
args,
)?;
let result = this.localtime_r(timep, result_op)?;
this.write_pointer(result, dest)?;
}
"clock_gettime" => {
- let [clk_id, tp] = this.check_shim_abi(
+ let [clk_id, tp] = this.check_shim_sig(
+ shim_sig!(extern "C" fn(libc::clockid_t, *mut _) -> i32),
link_name,
abi,
- ExternAbi::C { unwind: false },
- [this.libc_ty_layout("clockid_t").ty, this.machine.layouts.mut_raw_ptr.ty],
- this.tcx.types.i32,
args,
)?;
this.clock_gettime(clk_id, tp, dest)?;
@@ -700,20 +574,22 @@ fn emulate_foreign_item_inner(
// Allocation
"posix_memalign" => {
- let [memptr, align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [memptr, align, size] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.posix_memalign(memptr, align, size)?;
this.write_scalar(result, dest)?;
}
"mmap" => {
let [addr, length, prot, flags, fd, offset] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
this.write_scalar(ptr, dest)?;
}
"munmap" => {
- let [addr, length] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [addr, length] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.munmap(addr, length)?;
this.write_scalar(result, dest)?;
}
@@ -721,7 +597,8 @@ fn emulate_foreign_item_inner(
"reallocarray" => {
// Currently this function does not exist on all Unixes, e.g. on macOS.
this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
- let [ptr, nmemb, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr, nmemb, size] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let nmemb = this.read_target_usize(nmemb)?;
let size = this.read_target_usize(size)?;
@@ -744,14 +621,16 @@ fn emulate_foreign_item_inner(
"aligned_alloc" => {
// This is a C11 function, we assume all Unixes have it.
// (MSVC explicitly does not support this.)
- let [align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [align, size] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let res = this.aligned_alloc(align, size)?;
this.write_pointer(res, dest)?;
}
// Dynamic symbol loading
"dlsym" => {
- let [handle, symbol] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [handle, symbol] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.read_target_usize(handle)?;
let symbol = this.read_pointer(symbol)?;
let name = this.read_c_str(symbol)?;
@@ -767,7 +646,7 @@ fn emulate_foreign_item_inner(
// Thread-local storage
"pthread_key_create" => {
- let [key, dtor] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [key, dtor] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
let dtor = this.read_pointer(dtor)?;
@@ -795,21 +674,22 @@ fn emulate_foreign_item_inner(
this.write_null(dest)?;
}
"pthread_key_delete" => {
- let [key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
this.machine.tls.delete_tls_key(key)?;
// Return success (0)
this.write_null(dest)?;
}
"pthread_getspecific" => {
- let [key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
let active_thread = this.active_thread();
let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
this.write_scalar(ptr, dest)?;
}
"pthread_setspecific" => {
- let [key, new_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [key, new_ptr] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
let active_thread = this.active_thread();
let new_data = this.read_scalar(new_ptr)?;
@@ -821,117 +701,124 @@ fn emulate_foreign_item_inner(
// Synchronization primitives
"pthread_mutexattr_init" => {
- let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_mutexattr_init(attr)?;
this.write_null(dest)?;
}
"pthread_mutexattr_settype" => {
- let [attr, kind] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [attr, kind] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.pthread_mutexattr_settype(attr, kind)?;
this.write_scalar(result, dest)?;
}
"pthread_mutexattr_destroy" => {
- let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_mutexattr_destroy(attr)?;
this.write_null(dest)?;
}
"pthread_mutex_init" => {
- let [mutex, attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [mutex, attr] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_mutex_init(mutex, attr)?;
this.write_null(dest)?;
}
"pthread_mutex_lock" => {
- let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_mutex_lock(mutex, dest)?;
}
"pthread_mutex_trylock" => {
- let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.pthread_mutex_trylock(mutex)?;
this.write_scalar(result, dest)?;
}
"pthread_mutex_unlock" => {
- let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.pthread_mutex_unlock(mutex)?;
this.write_scalar(result, dest)?;
}
"pthread_mutex_destroy" => {
- let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_mutex_destroy(mutex)?;
this.write_int(0, dest)?;
}
"pthread_rwlock_rdlock" => {
- let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_rwlock_rdlock(rwlock, dest)?;
}
"pthread_rwlock_tryrdlock" => {
- let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.pthread_rwlock_tryrdlock(rwlock)?;
this.write_scalar(result, dest)?;
}
"pthread_rwlock_wrlock" => {
- let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_rwlock_wrlock(rwlock, dest)?;
}
"pthread_rwlock_trywrlock" => {
- let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.pthread_rwlock_trywrlock(rwlock)?;
this.write_scalar(result, dest)?;
}
"pthread_rwlock_unlock" => {
- let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_rwlock_unlock(rwlock)?;
this.write_null(dest)?;
}
"pthread_rwlock_destroy" => {
- let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_rwlock_destroy(rwlock)?;
this.write_null(dest)?;
}
"pthread_condattr_init" => {
- let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_condattr_init(attr)?;
this.write_null(dest)?;
}
"pthread_condattr_setclock" => {
- let [attr, clock_id] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [attr, clock_id] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.pthread_condattr_setclock(attr, clock_id)?;
this.write_scalar(result, dest)?;
}
"pthread_condattr_getclock" => {
- let [attr, clock_id] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [attr, clock_id] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_condattr_getclock(attr, clock_id)?;
this.write_null(dest)?;
}
"pthread_condattr_destroy" => {
- let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_condattr_destroy(attr)?;
this.write_null(dest)?;
}
"pthread_cond_init" => {
- let [cond, attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [cond, attr] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_cond_init(cond, attr)?;
this.write_null(dest)?;
}
"pthread_cond_signal" => {
- let [cond] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_cond_signal(cond)?;
this.write_null(dest)?;
}
"pthread_cond_broadcast" => {
- let [cond] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_cond_broadcast(cond)?;
this.write_null(dest)?;
}
"pthread_cond_wait" => {
- let [cond, mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [cond, mutex] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_cond_wait(cond, mutex, dest)?;
}
"pthread_cond_timedwait" => {
- let [cond, mutex, abstime] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [cond, mutex, abstime] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_cond_timedwait(cond, mutex, abstime, dest)?;
}
"pthread_cond_destroy" => {
- let [cond] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_cond_destroy(cond)?;
this.write_null(dest)?;
}
@@ -939,31 +826,33 @@ fn emulate_foreign_item_inner(
// Threading
"pthread_create" => {
let [thread, attr, start, arg] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_create(thread, attr, start, arg)?;
this.write_null(dest)?;
}
"pthread_join" => {
- let [thread, retval] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [thread, retval] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_join(thread, retval, dest)?;
}
"pthread_detach" => {
- let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let res = this.pthread_detach(thread)?;
this.write_scalar(res, dest)?;
}
"pthread_self" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let res = this.pthread_self()?;
this.write_scalar(res, dest)?;
}
"sched_yield" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.sched_yield()?;
this.write_null(dest)?;
}
"nanosleep" => {
- let [duration, rem] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [duration, rem] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.nanosleep(duration, rem)?;
this.write_scalar(result, dest)?;
}
@@ -974,14 +863,15 @@ fn emulate_foreign_item_inner(
link_name,
)?;
let [clock_id, flags, req, rem] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.clock_nanosleep(clock_id, flags, req, rem)?;
this.write_scalar(result, dest)?;
}
"sched_getaffinity" => {
// Currently this function does not exist on all Unixes, e.g. on macOS.
this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
- let [pid, cpusetsize, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [pid, cpusetsize, mask] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let pid = this.read_scalar(pid)?.to_u32()?;
let cpusetsize = this.read_target_usize(cpusetsize)?;
let mask = this.read_pointer(mask)?;
@@ -1018,7 +908,8 @@ fn emulate_foreign_item_inner(
"sched_setaffinity" => {
// Currently this function does not exist on all Unixes, e.g. on macOS.
this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
- let [pid, cpusetsize, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [pid, cpusetsize, mask] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let pid = this.read_scalar(pid)?.to_u32()?;
let cpusetsize = this.read_target_usize(cpusetsize)?;
let mask = this.read_pointer(mask)?;
@@ -1058,13 +949,13 @@ fn emulate_foreign_item_inner(
// Miscellaneous
"isatty" => {
- let [fd] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [fd] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.isatty(fd)?;
this.write_scalar(result, dest)?;
}
"pthread_atfork" => {
let [prepare, parent, child] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.read_pointer(prepare)?;
this.read_pointer(parent)?;
this.read_pointer(child)?;
@@ -1078,7 +969,8 @@ fn emulate_foreign_item_inner(
&["linux", "macos", "freebsd", "illumos", "solaris", "android"],
link_name,
)?;
- let [buf, bufsize] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [buf, bufsize] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let buf = this.read_pointer(buf)?;
let bufsize = this.read_target_usize(bufsize)?;
@@ -1096,7 +988,8 @@ fn emulate_foreign_item_inner(
}
"strerror_r" => {
- let [errnum, buf, buflen] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [errnum, buf, buflen] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.strerror_r(errnum, buf, buflen)?;
this.write_scalar(result, dest)?;
}
@@ -1108,7 +1001,8 @@ fn emulate_foreign_item_inner(
&["linux", "freebsd", "illumos", "solaris", "android"],
link_name,
)?;
- let [ptr, len, flags] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr, len, flags] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let len = this.read_target_usize(len)?;
let _flags = this.read_scalar(flags)?.to_i32()?;
@@ -1120,7 +1014,7 @@ fn emulate_foreign_item_inner(
// This function is non-standard but exists with the same signature and
// same behavior (eg never fails) on FreeBSD and Solaris/Illumos.
this.check_target_os(&["freebsd", "illumos", "solaris"], link_name)?;
- let [ptr, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr, len] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let len = this.read_target_usize(len)?;
this.gen_random(ptr, len)?;
@@ -1144,12 +1038,12 @@ fn emulate_foreign_item_inner(
link_name,
)?;
// This function looks and behaves excatly like miri_start_unwind.
- let [payload] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.handle_miri_start_unwind(payload)?;
return interp_ok(EmulateItemResult::NeedsUnwind);
}
"getuid" | "geteuid" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
// For now, just pretend we always have this fixed UID.
this.write_int(UID, dest)?;
}
@@ -1157,7 +1051,8 @@ fn emulate_foreign_item_inner(
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// These shims are enabled only when the caller is in the standard library.
"pthread_attr_getguardsize" if this.frame_in_std() => {
- let [_attr, guard_size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [_attr, guard_size] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let guard_size_layout = this.machine.layouts.usize;
let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
this.write_scalar(
@@ -1170,11 +1065,11 @@ fn emulate_foreign_item_inner(
}
"pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
- let [_] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [_] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.write_null(dest)?;
}
"pthread_attr_setstacksize" if this.frame_in_std() => {
- let [_, _] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.write_null(dest)?;
}
@@ -1182,7 +1077,7 @@ fn emulate_foreign_item_inner(
// We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here.
// Hence we can mostly ignore the input `attr_place`.
let [attr_place, addr_place, size_place] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let _attr_place =
this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?;
@@ -1202,18 +1097,18 @@ fn emulate_foreign_item_inner(
}
"signal" | "sigaltstack" if this.frame_in_std() => {
- let [_, _] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.write_null(dest)?;
}
"sigaction" | "mprotect" if this.frame_in_std() => {
- let [_, _, _] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [_, _, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.write_null(dest)?;
}
"getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => {
// getpwuid_r is the standard name, __posix_getpwuid_r is used on solarish
let [uid, pwd, buf, buflen, result] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.check_no_isolation("`getpwuid_r`")?;
let uid = this.read_scalar(uid)?.to_u32()?;
diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
index 33564a2..9e24705 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -24,7 +24,8 @@ fn emulate_foreign_item_inner(
match link_name.as_str() {
// Threading
"pthread_setname_np" => {
- let [thread, name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [thread, name] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let max_len = u64::MAX; // FreeBSD does not seem to have a limit.
let res = match this.pthread_setname_np(
this.read_scalar(thread)?,
@@ -39,7 +40,8 @@ fn emulate_foreign_item_inner(
this.write_scalar(res, dest)?;
}
"pthread_getname_np" => {
- let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [thread, name, len] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
// FreeBSD's pthread_getname_np uses strlcpy, which truncates the resulting value,
// but always adds a null terminator (except for zero-sized buffers).
// https://github.com/freebsd/freebsd-src/blob/c2d93a803acef634bd0eede6673aeea59e90c277/lib/libthr/thread/thr_info.c#L119-L144
@@ -57,7 +59,7 @@ fn emulate_foreign_item_inner(
this.write_scalar(res, dest)?;
}
"pthread_getthreadid_np" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.unix_gettid(link_name.as_str())?;
this.write_scalar(result, dest)?;
}
@@ -65,7 +67,7 @@ fn emulate_foreign_item_inner(
"cpuset_getaffinity" => {
// The "same" kind of api as `sched_getaffinity` but more fine grained control for FreeBSD specifically.
let [level, which, id, set_size, mask] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let level = this.read_scalar(level)?.to_i32()?;
let which = this.read_scalar(which)?.to_i32()?;
@@ -129,7 +131,7 @@ fn emulate_foreign_item_inner(
// Synchronization primitives
"_umtx_op" => {
let [obj, op, val, uaddr, uaddr2] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this._umtx_op(obj, op, val, uaddr, uaddr2, dest)?;
}
@@ -137,29 +139,30 @@ fn emulate_foreign_item_inner(
// For those, we both intercept `func` and `call@FBSD_1.0` symbols cases
// since freebsd 12 the former form can be expected.
"stat" | "stat@FBSD_1.0" => {
- let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_solarish_stat(path, buf)?;
this.write_scalar(result, dest)?;
}
"lstat" | "lstat@FBSD_1.0" => {
- let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_solarish_lstat(path, buf)?;
this.write_scalar(result, dest)?;
}
"fstat" | "fstat@FBSD_1.0" => {
- let [fd, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
this.write_scalar(result, dest)?;
}
"readdir_r" | "readdir_r@FBSD_1.0" => {
- let [dirp, entry, result] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [dirp, entry, result] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
this.write_scalar(result, dest)?;
}
// Miscellaneous
"__error" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
@@ -167,7 +170,8 @@ fn emulate_foreign_item_inner(
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// These shims are enabled only when the caller is in the standard library.
"pthread_attr_get_np" if this.frame_in_std() => {
- let [_thread, _attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [_thread, _attr] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.write_null(dest)?;
}
diff --git a/src/tools/miri/src/shims/unix/freebsd/sync.rs b/src/tools/miri/src/shims/unix/freebsd/sync.rs
index f4e7d9e..13d30e0 100644
--- a/src/tools/miri/src/shims/unix/freebsd/sync.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/sync.rs
@@ -228,26 +228,14 @@ fn read_umtx_time(&mut self, ut: &MPlaceTy<'tcx>) -> InterpResult<'tcx, Option<U
let abs_time_flag = flags == abs_time;
let clock_id_place = this.project_field(ut, FieldIdx::from_u32(2))?;
- let clock_id = this.read_scalar(&clock_id_place)?.to_i32()?;
- let timeout_clock = this.translate_umtx_time_clock_id(clock_id)?;
+ let clock_id = this.read_scalar(&clock_id_place)?;
+ let Some(timeout_clock) = this.parse_clockid(clock_id) else {
+ throw_unsup_format!("unsupported clock")
+ };
+ if timeout_clock == TimeoutClock::RealTime {
+ this.check_no_isolation("`_umtx_op` with `CLOCK_REALTIME`")?;
+ }
interp_ok(Some(UmtxTime { timeout: duration, abs_time: abs_time_flag, timeout_clock }))
}
-
- /// Translate raw FreeBSD clockid to a Miri TimeoutClock.
- /// FIXME: share this code with the pthread and clock_gettime shims.
- fn translate_umtx_time_clock_id(&mut self, raw_id: i32) -> InterpResult<'tcx, TimeoutClock> {
- let this = self.eval_context_mut();
-
- let timeout = if raw_id == this.eval_libc_i32("CLOCK_REALTIME") {
- // RealTime clock can't be used in isolation mode.
- this.check_no_isolation("`_umtx_op` with `CLOCK_REALTIME` timeout")?;
- TimeoutClock::RealTime
- } else if raw_id == this.eval_libc_i32("CLOCK_MONOTONIC") {
- TimeoutClock::Monotonic
- } else {
- throw_unsup_format!("unsupported clock id {raw_id}");
- };
- interp_ok(timeout)
- }
}
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 0f2878a..f9bcacf 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -13,9 +13,9 @@
use rustc_data_structures::fx::FxHashMap;
use self::shims::time::system_time_to_duration;
-use crate::helpers::check_min_vararg_count;
use crate::shims::files::FileHandle;
use crate::shims::os_str::bytes_to_os_str;
+use crate::shims::sig::check_min_vararg_count;
use crate::shims::unix::fd::{FlockOp, UnixFileDescription};
use crate::*;
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index b3e99e6..e7e0c3b 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -37,48 +37,50 @@ fn emulate_foreign_item_inner(
match link_name.as_str() {
// File related shims
"readdir64" => {
- let [dirp] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.linux_solarish_readdir64("dirent64", dirp)?;
this.write_scalar(result, dest)?;
}
"sync_file_range" => {
let [fd, offset, nbytes, flags] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.sync_file_range(fd, offset, nbytes, flags)?;
this.write_scalar(result, dest)?;
}
"statx" => {
let [dirfd, pathname, flags, mask, statxbuf] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?;
this.write_scalar(result, dest)?;
}
// epoll, eventfd
"epoll_create1" => {
- let [flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.epoll_create1(flag)?;
this.write_scalar(result, dest)?;
}
"epoll_ctl" => {
- let [epfd, op, fd, event] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [epfd, op, fd, event] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.epoll_ctl(epfd, op, fd, event)?;
this.write_scalar(result, dest)?;
}
"epoll_wait" => {
let [epfd, events, maxevents, timeout] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
}
"eventfd" => {
- let [val, flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [val, flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.eventfd(val, flag)?;
this.write_scalar(result, dest)?;
}
// Threading
"pthread_setname_np" => {
- let [thread, name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [thread, name] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let res = match this.pthread_setname_np(
this.read_scalar(thread)?,
this.read_scalar(name)?,
@@ -93,7 +95,8 @@ fn emulate_foreign_item_inner(
this.write_scalar(res, dest)?;
}
"pthread_getname_np" => {
- let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [thread, name, len] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
// The function's behavior isn't portable between platforms.
// In case of glibc, the length of the output buffer must
// be not shorter than TASK_COMM_LEN.
@@ -116,7 +119,7 @@ fn emulate_foreign_item_inner(
this.write_scalar(res, dest)?;
}
"gettid" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.unix_gettid(link_name.as_str())?;
this.write_scalar(result, dest)?;
}
@@ -129,34 +132,35 @@ fn emulate_foreign_item_inner(
// Miscellaneous
"mmap64" => {
let [addr, length, prot, flags, fd, offset] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let offset = this.read_scalar(offset)?.to_i64()?;
let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?;
this.write_scalar(ptr, dest)?;
}
"mremap" => {
let ([old_address, old_size, new_size, flags], _) =
- this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
let ptr = this.mremap(old_address, old_size, new_size, flags)?;
this.write_scalar(ptr, dest)?;
}
"__xpg_strerror_r" => {
- let [errnum, buf, buflen] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [errnum, buf, buflen] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.strerror_r(errnum, buf, buflen)?;
this.write_scalar(result, dest)?;
}
"__errno_location" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
"__libc_current_sigrtmin" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.write_int(SIGRTMIN, dest)?;
}
"__libc_current_sigrtmax" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.write_int(SIGRTMAX, dest)?;
}
@@ -164,7 +168,8 @@ fn emulate_foreign_item_inner(
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// These shims are enabled only when the caller is in the standard library.
"pthread_getattr_np" if this.frame_in_std() => {
- let [_thread, _attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [_thread, _attr] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.write_null(dest)?;
}
diff --git a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
index ee7deb8..2d35ef0 100644
--- a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
@@ -37,6 +37,11 @@ fn name(&self) -> &'static str {
"event"
}
+ fn nondet_short_accesses(&self) -> bool {
+ // We always read and write exactly one `u64`.
+ false
+ }
+
fn close<'tcx>(
self,
_communicate_allowed: bool,
diff --git a/src/tools/miri/src/shims/unix/linux_like/sync.rs b/src/tools/miri/src/shims/unix/linux_like/sync.rs
index 9fad74c..5f032c5 100644
--- a/src/tools/miri/src/shims/unix/linux_like/sync.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/sync.rs
@@ -1,5 +1,5 @@
use crate::concurrency::sync::FutexRef;
-use crate::helpers::check_min_vararg_count;
+use crate::shims::sig::check_min_vararg_count;
use crate::*;
struct LinuxFutex {
diff --git a/src/tools/miri/src/shims/unix/linux_like/syscall.rs b/src/tools/miri/src/shims/unix/linux_like/syscall.rs
index d3534e6..106e6c4 100644
--- a/src/tools/miri/src/shims/unix/linux_like/syscall.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/syscall.rs
@@ -3,7 +3,7 @@
use rustc_span::Symbol;
use rustc_target::callconv::FnAbi;
-use crate::helpers::check_min_vararg_count;
+use crate::shims::sig::check_min_vararg_count;
use crate::shims::unix::env::EvalContextExt;
use crate::shims::unix::linux_like::eventfd::EvalContextExt as _;
use crate::shims::unix::linux_like::sync::futex;
@@ -16,7 +16,7 @@ pub fn syscall<'tcx>(
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
- let ([op], varargs) = ecx.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
+ let ([op], varargs) = ecx.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
// The syscall variadic function is legal to call with more arguments than needed,
// extra arguments are simply ignored. The important check is that when we use an
// argument, we have to also check all arguments *before* it to ensure that they
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index 2330371..297d903 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -35,64 +35,67 @@ fn emulate_foreign_item_inner(
match link_name.as_str() {
// errno
"__error" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
// File related shims
"close$NOCANCEL" => {
- let [result] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [result] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.close(result)?;
this.write_scalar(result, dest)?;
}
"stat" | "stat64" | "stat$INODE64" => {
- let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_solarish_stat(path, buf)?;
this.write_scalar(result, dest)?;
}
"lstat" | "lstat64" | "lstat$INODE64" => {
- let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_solarish_lstat(path, buf)?;
this.write_scalar(result, dest)?;
}
"fstat" | "fstat64" | "fstat$INODE64" => {
- let [fd, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
this.write_scalar(result, dest)?;
}
"opendir$INODE64" => {
- let [name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [name] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.opendir(name)?;
this.write_scalar(result, dest)?;
}
"readdir_r" | "readdir_r$INODE64" => {
- let [dirp, entry, result] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [dirp, entry, result] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
this.write_scalar(result, dest)?;
}
"realpath$DARWIN_EXTSN" => {
- let [path, resolved_path] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [path, resolved_path] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.realpath(path, resolved_path)?;
this.write_scalar(result, dest)?;
}
"ioctl" => {
let ([fd_num, cmd], varargs) =
- this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.ioctl(fd_num, cmd, varargs)?;
this.write_scalar(result, dest)?;
}
// Environment related shims
"_NSGetEnviron" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let environ = this.machine.env_vars.unix().environ();
this.write_pointer(environ, dest)?;
}
// Random data generation
"CCRandomGenerateBytes" => {
- let [bytes, count] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [bytes, count] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let bytes = this.read_pointer(bytes)?;
let count = this.read_target_usize(count)?;
let success = this.eval_libc_i32("kCCSuccess");
@@ -102,28 +105,29 @@ fn emulate_foreign_item_inner(
// Time related shims
"mach_absolute_time" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.mach_absolute_time()?;
this.write_scalar(result, dest)?;
}
"mach_timebase_info" => {
- let [info] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [info] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.mach_timebase_info(info)?;
this.write_scalar(result, dest)?;
}
// Access to command-line arguments
"_NSGetArgc" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?;
}
"_NSGetArgv" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?;
}
"_NSGetExecutablePath" => {
- let [buf, bufsize] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [buf, bufsize] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.check_no_isolation("`_NSGetExecutablePath`")?;
let buf_ptr = this.read_pointer(buf)?;
@@ -148,7 +152,8 @@ fn emulate_foreign_item_inner(
// Thread-local storage
"_tlv_atexit" => {
- let [dtor, data] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [dtor, data] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let dtor = this.read_pointer(dtor)?;
let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
let data = this.read_scalar(data)?;
@@ -158,13 +163,13 @@ fn emulate_foreign_item_inner(
// Querying system information
"pthread_get_stackaddr_np" => {
- let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.read_target_usize(thread)?;
let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size());
this.write_scalar(stack_addr, dest)?;
}
"pthread_get_stacksize_np" => {
- let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.read_target_usize(thread)?;
let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size());
this.write_scalar(stack_size, dest)?;
@@ -172,7 +177,7 @@ fn emulate_foreign_item_inner(
// Threading
"pthread_setname_np" => {
- let [name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [name] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
// The real implementation has logic in two places:
// * in userland at https://github.com/apple-oss-distributions/libpthread/blob/c032e0b076700a0a47db75528a282b8d3a06531a/src/pthread.c#L1178-L1200,
@@ -199,7 +204,8 @@ fn emulate_foreign_item_inner(
this.write_scalar(res, dest)?;
}
"pthread_getname_np" => {
- let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [thread, name, len] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
// The function's behavior isn't portable between platforms.
// In case of macOS, a truncated name (due to a too small buffer)
@@ -223,7 +229,8 @@ fn emulate_foreign_item_inner(
this.write_scalar(res, dest)?;
}
"pthread_threadid_np" => {
- let [thread, tid_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [thread, tid_ptr] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let res = this.apple_pthread_threadip_np(thread, tid_ptr)?;
this.write_scalar(res, dest)?;
}
@@ -231,7 +238,7 @@ fn emulate_foreign_item_inner(
// Synchronization primitives
"os_sync_wait_on_address" => {
let [addr_op, value_op, size_op, flags_op] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.os_sync_wait_on_address(
addr_op,
value_op,
@@ -243,7 +250,7 @@ fn emulate_foreign_item_inner(
}
"os_sync_wait_on_address_with_deadline" => {
let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.os_sync_wait_on_address(
addr_op,
value_op,
@@ -255,7 +262,7 @@ fn emulate_foreign_item_inner(
}
"os_sync_wait_on_address_with_timeout" => {
let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.os_sync_wait_on_address(
addr_op,
value_op,
@@ -267,36 +274,36 @@ fn emulate_foreign_item_inner(
}
"os_sync_wake_by_address_any" => {
let [addr_op, size_op, flags_op] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.os_sync_wake_by_address(
addr_op, size_op, flags_op, /* all */ false, dest,
)?;
}
"os_sync_wake_by_address_all" => {
let [addr_op, size_op, flags_op] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.os_sync_wake_by_address(
addr_op, size_op, flags_op, /* all */ true, dest,
)?;
}
"os_unfair_lock_lock" => {
- let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.os_unfair_lock_lock(lock_op)?;
}
"os_unfair_lock_trylock" => {
- let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.os_unfair_lock_trylock(lock_op, dest)?;
}
"os_unfair_lock_unlock" => {
- let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.os_unfair_lock_unlock(lock_op)?;
}
"os_unfair_lock_assert_owner" => {
- let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.os_unfair_lock_assert_owner(lock_op)?;
}
"os_unfair_lock_assert_not_owner" => {
- let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.os_unfair_lock_assert_not_owner(lock_op)?;
}
diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
index e3d15b8..d7033a6 100644
--- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
@@ -27,32 +27,34 @@ fn emulate_foreign_item_inner(
// epoll, eventfd (NOT available on Solaris!)
"epoll_create1" => {
this.assert_target_os("illumos", "epoll_create1");
- let [flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.epoll_create1(flag)?;
this.write_scalar(result, dest)?;
}
"epoll_ctl" => {
this.assert_target_os("illumos", "epoll_ctl");
- let [epfd, op, fd, event] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [epfd, op, fd, event] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.epoll_ctl(epfd, op, fd, event)?;
this.write_scalar(result, dest)?;
}
"epoll_wait" => {
this.assert_target_os("illumos", "epoll_wait");
let [epfd, events, maxevents, timeout] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
}
"eventfd" => {
this.assert_target_os("illumos", "eventfd");
- let [val, flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [val, flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.eventfd(val, flag)?;
this.write_scalar(result, dest)?;
}
// Threading
"pthread_setname_np" => {
- let [thread, name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [thread, name] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
// THREAD_NAME_MAX allows a thread name of 31+1 length
// https://github.com/illumos/illumos-gate/blob/7671517e13b8123748eda4ef1ee165c6d9dba7fe/usr/src/uts/common/sys/thread.h#L613
let max_len = 32;
@@ -70,7 +72,8 @@ fn emulate_foreign_item_inner(
this.write_scalar(res, dest)?;
}
"pthread_getname_np" => {
- let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [thread, name, len] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
// See https://illumos.org/man/3C/pthread_getname_np for the error codes.
let res = match this.pthread_getname_np(
this.read_scalar(thread)?,
@@ -87,22 +90,22 @@ fn emulate_foreign_item_inner(
// File related shims
"stat" | "stat64" => {
- let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_solarish_stat(path, buf)?;
this.write_scalar(result, dest)?;
}
"lstat" | "lstat64" => {
- let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_solarish_lstat(path, buf)?;
this.write_scalar(result, dest)?;
}
"fstat" | "fstat64" => {
- let [fd, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
this.write_scalar(result, dest)?;
}
"readdir" => {
- let [dirp] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.linux_solarish_readdir64("dirent", dirp)?;
this.write_scalar(result, dest)?;
}
@@ -110,20 +113,20 @@ fn emulate_foreign_item_inner(
// Sockets and pipes
"__xnet_socketpair" => {
let [domain, type_, protocol, sv] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.socketpair(domain, type_, protocol, sv)?;
this.write_scalar(result, dest)?;
}
// Miscellaneous
"___errno" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
"stack_getbounds" => {
- let [stack] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [stack] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let stack = this.deref_pointer_as(stack, this.libc_ty_layout("stack_t"))?;
this.write_int_fields_named(
@@ -141,7 +144,8 @@ fn emulate_foreign_item_inner(
}
"pset_info" => {
- let [pset, tpe, cpus, list] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [pset, tpe, cpus, list] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
// We do not need to handle the current process cpu mask, available_parallelism
// implementation pass null anyway. We only care for the number of
// cpus.
@@ -170,7 +174,7 @@ fn emulate_foreign_item_inner(
}
"__sysconf_xpg7" => {
- let [val] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [val] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.sysconf(val)?;
this.write_scalar(result, dest)?;
}
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index e20e3b7..5ad4fd5 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -297,14 +297,13 @@ fn condattr_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u
fn condattr_get_clock_id<'tcx>(
ecx: &MiriInterpCx<'tcx>,
attr_ptr: &OpTy<'tcx>,
-) -> InterpResult<'tcx, i32> {
+) -> InterpResult<'tcx, Scalar> {
ecx.deref_pointer_and_read(
attr_ptr,
condattr_clock_offset(ecx)?,
ecx.libc_ty_layout("pthread_condattr_t"),
ecx.machine.layouts.i32,
- )?
- .to_i32()
+ )
}
fn condattr_set_clock_id<'tcx>(
@@ -321,20 +320,6 @@ fn condattr_set_clock_id<'tcx>(
)
}
-/// Translates the clock from what is stored in pthread_condattr_t to our enum.
-fn condattr_translate_clock_id<'tcx>(
- ecx: &MiriInterpCx<'tcx>,
- raw_id: i32,
-) -> InterpResult<'tcx, ClockId> {
- interp_ok(if raw_id == ecx.eval_libc_i32("CLOCK_REALTIME") {
- ClockId::Realtime
- } else if raw_id == ecx.eval_libc_i32("CLOCK_MONOTONIC") {
- ClockId::Monotonic
- } else {
- throw_unsup_format!("unsupported clock id: {raw_id}");
- })
-}
-
// # pthread_cond_t
// We store some data directly inside the type, ignoring the platform layout:
// - init: u32
@@ -363,22 +348,16 @@ fn cond_init_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, Size>
interp_ok(offset)
}
-#[derive(Debug, Clone, Copy)]
-enum ClockId {
- Realtime,
- Monotonic,
-}
-
#[derive(Debug, Clone)]
struct PthreadCondvar {
condvar_ref: CondvarRef,
- clock: ClockId,
+ clock: TimeoutClock,
}
fn cond_create<'tcx>(
ecx: &mut MiriInterpCx<'tcx>,
cond_ptr: &OpTy<'tcx>,
- clock: ClockId,
+ clock: TimeoutClock,
) -> InterpResult<'tcx, PthreadCondvar> {
let cond = ecx.deref_pointer_as(cond_ptr, ecx.libc_ty_layout("pthread_cond_t"))?;
let data = PthreadCondvar { condvar_ref: CondvarRef::new(), clock };
@@ -407,7 +386,10 @@ fn cond_get_data<'tcx, 'a>(
throw_unsup_format!("unsupported static initializer used for `pthread_cond_t`");
}
// This used the static initializer. The clock there is always CLOCK_REALTIME.
- interp_ok(PthreadCondvar { condvar_ref: CondvarRef::new(), clock: ClockId::Realtime })
+ interp_ok(PthreadCondvar {
+ condvar_ref: CondvarRef::new(),
+ clock: TimeoutClock::RealTime,
+ })
},
)
}
@@ -742,11 +724,9 @@ fn pthread_condattr_setclock(
) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
- let clock_id = this.read_scalar(clock_id_op)?.to_i32()?;
- if clock_id == this.eval_libc_i32("CLOCK_REALTIME")
- || clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")
- {
- condattr_set_clock_id(this, attr_op, clock_id)?;
+ let clock_id = this.read_scalar(clock_id_op)?;
+ if this.parse_clockid(clock_id).is_some() {
+ condattr_set_clock_id(this, attr_op, clock_id.to_i32()?)?;
} else {
let einval = this.eval_libc_i32("EINVAL");
return interp_ok(Scalar::from_i32(einval));
@@ -764,7 +744,7 @@ fn pthread_condattr_getclock(
let clock_id = condattr_get_clock_id(this, attr_op)?;
this.write_scalar(
- Scalar::from_i32(clock_id),
+ clock_id,
&this.deref_pointer_as(clk_id_op, this.libc_ty_layout("clockid_t"))?,
)?;
@@ -799,13 +779,16 @@ fn pthread_cond_init(
let attr = this.read_pointer(attr_op)?;
// Default clock if `attr` is null, and on macOS where there is no clock attribute.
let clock_id = if this.ptr_is_null(attr)? || this.tcx.sess.target.os == "macos" {
- this.eval_libc_i32("CLOCK_REALTIME")
+ this.eval_libc("CLOCK_REALTIME")
} else {
condattr_get_clock_id(this, attr_op)?
};
- let clock_id = condattr_translate_clock_id(this, clock_id)?;
+ let Some(clock) = this.parse_clockid(clock_id) else {
+ // This is UB since this situation cannot arise when using pthread_condattr_setclock.
+ throw_ub_format!("pthread_cond_init: invalid attributes (unsupported clock)")
+ };
- cond_create(this, cond_op, clock_id)?;
+ cond_create(this, cond_op, clock)?;
interp_ok(())
}
@@ -870,18 +853,14 @@ fn pthread_cond_timedwait(
return interp_ok(());
}
};
- let timeout_clock = match data.clock {
- ClockId::Realtime => {
- this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?;
- TimeoutClock::RealTime
- }
- ClockId::Monotonic => TimeoutClock::Monotonic,
- };
+ if data.clock == TimeoutClock::RealTime {
+ this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?;
+ }
this.condvar_wait(
data.condvar_ref,
mutex_ref,
- Some((timeout_clock, TimeoutAnchor::Absolute, duration)),
+ Some((data.clock, TimeoutAnchor::Absolute, duration)),
Scalar::from_i32(0),
this.eval_libc("ETIMEDOUT"), // retval_timeout
dest.clone(),
diff --git a/src/tools/miri/src/shims/unwind.rs b/src/tools/miri/src/shims/unwind.rs
index ba0c50b..0dd2b20 100644
--- a/src/tools/miri/src/shims/unwind.rs
+++ b/src/tools/miri/src/shims/unwind.rs
@@ -16,7 +16,6 @@
use rustc_middle::mir;
use rustc_target::spec::PanicStrategy;
-use self::helpers::check_intrinsic_arg_count;
use crate::*;
/// Holds all of the relevant data for when unwinding hits a `try` frame.
@@ -60,7 +59,9 @@ fn handle_miri_start_unwind(&mut self, payload: &OpTy<'tcx>) -> InterpResult<'tc
/// Handles the `catch_unwind` intrinsic.
fn handle_catch_unwind(
&mut self,
- args: &[OpTy<'tcx>],
+ try_fn: &OpTy<'tcx>,
+ data: &OpTy<'tcx>,
+ catch_fn: &OpTy<'tcx>,
dest: &MPlaceTy<'tcx>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
@@ -78,7 +79,6 @@ fn handle_catch_unwind(
// a pointer to `Box<dyn Any + Send + 'static>`.
// Get all the arguments.
- let [try_fn, data, catch_fn] = check_intrinsic_arg_count(args)?;
let try_fn = this.read_pointer(try_fn)?;
let data = this.read_immediate(data)?;
let catch_fn = this.read_pointer(catch_fn)?;
diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs
index 8d92d0f..bfcdbd8 100644
--- a/src/tools/miri/src/shims/wasi/foreign_items.rs
+++ b/src/tools/miri/src/shims/wasi/foreign_items.rs
@@ -23,12 +23,14 @@ fn emulate_foreign_item_inner(
match link_name.as_str() {
// Allocation
"posix_memalign" => {
- let [memptr, align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [memptr, align, size] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.posix_memalign(memptr, align, size)?;
this.write_scalar(result, dest)?;
}
"aligned_alloc" => {
- let [align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [align, size] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let res = this.aligned_alloc(align, size)?;
this.write_pointer(res, dest)?;
}
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 959abc0..7b13f1d 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -157,42 +157,44 @@ fn emulate_foreign_item_inner(
match link_name.as_str() {
// Environment related shims
"GetEnvironmentVariableW" => {
- let [name, buf, size] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [name, buf, size] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let result = this.GetEnvironmentVariableW(name, buf, size)?;
this.write_scalar(result, dest)?;
}
"SetEnvironmentVariableW" => {
- let [name, value] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [name, value] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let result = this.SetEnvironmentVariableW(name, value)?;
this.write_scalar(result, dest)?;
}
"GetEnvironmentStringsW" => {
- let [] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let result = this.GetEnvironmentStringsW()?;
this.write_pointer(result, dest)?;
}
"FreeEnvironmentStringsW" => {
- let [env_block] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [env_block] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let result = this.FreeEnvironmentStringsW(env_block)?;
this.write_scalar(result, dest)?;
}
"GetCurrentDirectoryW" => {
- let [size, buf] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [size, buf] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let result = this.GetCurrentDirectoryW(size, buf)?;
this.write_scalar(result, dest)?;
}
"SetCurrentDirectoryW" => {
- let [path] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [path] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let result = this.SetCurrentDirectoryW(path)?;
this.write_scalar(result, dest)?;
}
"GetUserProfileDirectoryW" => {
- let [token, buf, size] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [token, buf, size] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let result = this.GetUserProfileDirectoryW(token, buf, size)?;
this.write_scalar(result, dest)?;
}
"GetCurrentProcessId" => {
- let [] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let result = this.GetCurrentProcessId()?;
this.write_scalar(result, dest)?;
}
@@ -209,7 +211,7 @@ fn emulate_foreign_item_inner(
n,
byte_offset,
key,
- ] = this.check_shim(abi, sys_conv, link_name, args)?;
+ ] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.NtWriteFile(
handle,
event,
@@ -234,7 +236,7 @@ fn emulate_foreign_item_inner(
n,
byte_offset,
key,
- ] = this.check_shim(abi, sys_conv, link_name, args)?;
+ ] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.NtReadFile(
handle,
event,
@@ -250,7 +252,7 @@ fn emulate_foreign_item_inner(
}
"GetFullPathNameW" => {
let [filename, size, buffer, filepart] =
- this.check_shim(abi, sys_conv, link_name, args)?;
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.check_no_isolation("`GetFullPathNameW`")?;
let filename = this.read_pointer(filename)?;
@@ -287,7 +289,7 @@ fn emulate_foreign_item_inner(
creation_disposition,
flags_and_attributes,
template_file,
- ] = this.check_shim(abi, sys_conv, link_name, args)?;
+ ] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let handle = this.CreateFileW(
file_name,
desired_access,
@@ -300,18 +302,18 @@ fn emulate_foreign_item_inner(
this.write_scalar(handle.to_scalar(this), dest)?;
}
"GetFileInformationByHandle" => {
- let [handle, info] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [handle, info] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let res = this.GetFileInformationByHandle(handle, info)?;
this.write_scalar(res, dest)?;
}
"DeleteFileW" => {
- let [file_name] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [file_name] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let res = this.DeleteFileW(file_name)?;
this.write_scalar(res, dest)?;
}
"SetFilePointerEx" => {
let [file, distance_to_move, new_file_pointer, move_method] =
- this.check_shim(abi, sys_conv, link_name, args)?;
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let res =
this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?;
this.write_scalar(res, dest)?;
@@ -319,7 +321,8 @@ fn emulate_foreign_item_inner(
// Allocation
"HeapAlloc" => {
- let [handle, flags, size] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [handle, flags, size] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.read_target_isize(handle)?;
let flags = this.read_scalar(flags)?.to_u32()?;
let size = this.read_target_usize(size)?;
@@ -341,7 +344,8 @@ fn emulate_foreign_item_inner(
this.write_pointer(ptr, dest)?;
}
"HeapFree" => {
- let [handle, flags, ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [handle, flags, ptr] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.read_target_isize(handle)?;
this.read_scalar(flags)?.to_u32()?;
let ptr = this.read_pointer(ptr)?;
@@ -354,7 +358,7 @@ fn emulate_foreign_item_inner(
}
"HeapReAlloc" => {
let [handle, flags, old_ptr, size] =
- this.check_shim(abi, sys_conv, link_name, args)?;
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.read_target_isize(handle)?;
this.read_scalar(flags)?.to_u32()?;
let old_ptr = this.read_pointer(old_ptr)?;
@@ -374,7 +378,7 @@ fn emulate_foreign_item_inner(
this.write_pointer(new_ptr, dest)?;
}
"LocalFree" => {
- let [ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [ptr] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
// "If the hMem parameter is NULL, LocalFree ignores the parameter and returns NULL."
// (https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localfree)
@@ -386,17 +390,17 @@ fn emulate_foreign_item_inner(
// errno
"SetLastError" => {
- let [error] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [error] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let error = this.read_scalar(error)?;
this.set_last_error(error)?;
}
"GetLastError" => {
- let [] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
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.check_shim_sig_lenient(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
@@ -418,7 +422,7 @@ fn emulate_foreign_item_inner(
// Querying system information
"GetSystemInfo" => {
// Also called from `page_size` crate.
- let [system_info] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [system_info] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let system_info =
this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
// Initialize with `0`.
@@ -441,19 +445,19 @@ fn emulate_foreign_item_inner(
// This just creates a key; Windows does not natively support TLS destructors.
// Create key and return it.
- let [] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
}
"TlsGetValue" => {
- let [key] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [key] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let key = u128::from(this.read_scalar(key)?.to_u32()?);
let active_thread = this.active_thread();
let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
this.write_scalar(ptr, dest)?;
}
"TlsSetValue" => {
- let [key, new_ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [key, new_ptr] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let key = u128::from(this.read_scalar(key)?.to_u32()?);
let active_thread = this.active_thread();
let new_data = this.read_scalar(new_ptr)?;
@@ -463,7 +467,7 @@ fn emulate_foreign_item_inner(
this.write_int(1, dest)?;
}
"TlsFree" => {
- let [key] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [key] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let key = u128::from(this.read_scalar(key)?.to_u32()?);
this.machine.tls.delete_tls_key(key)?;
@@ -473,7 +477,7 @@ fn emulate_foreign_item_inner(
// Access to command-line arguments
"GetCommandLineW" => {
- let [] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.write_pointer(
this.machine.cmd_line.expect("machine must be initialized"),
dest,
@@ -483,29 +487,30 @@ fn emulate_foreign_item_inner(
// Time related shims
"GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
#[allow(non_snake_case)]
- let [LPFILETIME] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [LPFILETIME] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.GetSystemTimeAsFileTime(link_name.as_str(), LPFILETIME)?;
}
"QueryPerformanceCounter" => {
#[allow(non_snake_case)]
- let [lpPerformanceCount] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [lpPerformanceCount] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
this.write_scalar(result, dest)?;
}
"QueryPerformanceFrequency" => {
#[allow(non_snake_case)]
- let [lpFrequency] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [lpFrequency] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let result = this.QueryPerformanceFrequency(lpFrequency)?;
this.write_scalar(result, dest)?;
}
"Sleep" => {
- let [timeout] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [timeout] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.Sleep(timeout)?;
}
"CreateWaitableTimerExW" => {
let [attributes, name, flags, access] =
- this.check_shim(abi, sys_conv, link_name, args)?;
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.read_pointer(attributes)?;
this.read_pointer(name)?;
this.read_scalar(flags)?.to_u32()?;
@@ -519,27 +524,28 @@ fn emulate_foreign_item_inner(
// Synchronization primitives
"InitOnceBeginInitialize" => {
let [ptr, flags, pending, context] =
- this.check_shim(abi, sys_conv, link_name, args)?;
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
}
"InitOnceComplete" => {
- let [ptr, flags, context] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [ptr, flags, context] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let result = this.InitOnceComplete(ptr, flags, context)?;
this.write_scalar(result, dest)?;
}
"WaitOnAddress" => {
let [ptr_op, compare_op, size_op, timeout_op] =
- this.check_shim(abi, sys_conv, link_name, args)?;
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
}
"WakeByAddressSingle" => {
- let [ptr_op] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [ptr_op] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.WakeByAddressSingle(ptr_op)?;
}
"WakeByAddressAll" => {
- let [ptr_op] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [ptr_op] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.WakeByAddressAll(ptr_op)?;
}
@@ -547,7 +553,8 @@ fn emulate_foreign_item_inner(
// Dynamic symbol loading
"GetProcAddress" => {
#[allow(non_snake_case)]
- let [hModule, lpProcName] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [hModule, lpProcName] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.read_target_isize(hModule)?;
let name = this.read_c_str(this.read_pointer(lpProcName)?)?;
if let Ok(name) = str::from_utf8(name)
@@ -563,7 +570,7 @@ fn emulate_foreign_item_inner(
// Threading
"CreateThread" => {
let [security, stacksize, start, arg, flags, thread] =
- this.check_shim(abi, sys_conv, link_name, args)?;
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let thread_id =
this.CreateThread(security, stacksize, start, arg, flags, thread)?;
@@ -571,12 +578,13 @@ fn emulate_foreign_item_inner(
this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
}
"WaitForSingleObject" => {
- let [handle, timeout] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [handle, timeout] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.WaitForSingleObject(handle, timeout, dest)?;
}
"GetCurrentProcess" => {
- let [] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.write_scalar(
Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
@@ -584,7 +592,7 @@ fn emulate_foreign_item_inner(
)?;
}
"GetCurrentThread" => {
- let [] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.write_scalar(
Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
@@ -592,7 +600,7 @@ fn emulate_foreign_item_inner(
)?;
}
"SetThreadDescription" => {
- let [handle, name] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [handle, name] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let handle = this.read_handle(handle, "SetThreadDescription")?;
let name = this.read_wide_str(this.read_pointer(name)?)?;
@@ -607,7 +615,8 @@ fn emulate_foreign_item_inner(
this.write_scalar(Scalar::from_u32(0), dest)?;
}
"GetThreadDescription" => {
- let [handle, name_ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [handle, name_ptr] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let handle = this.read_handle(handle, "GetThreadDescription")?;
let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; // the pointer where we should store the ptr to the name
@@ -630,7 +639,7 @@ fn emulate_foreign_item_inner(
this.write_scalar(res, dest)?;
}
"GetThreadId" => {
- let [handle] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let handle = this.read_handle(handle, "GetThreadId")?;
let thread = match handle {
Handle::Thread(thread) => thread,
@@ -641,7 +650,7 @@ fn emulate_foreign_item_inner(
this.write_scalar(Scalar::from_u32(tid), dest)?;
}
"GetCurrentThreadId" => {
- let [] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let thread = this.active_thread();
let tid = this.get_tid(thread);
this.write_scalar(Scalar::from_u32(tid), dest)?;
@@ -649,7 +658,7 @@ fn emulate_foreign_item_inner(
// Miscellaneous
"ExitProcess" => {
- let [code] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [code] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
// Windows technically uses u32, but we unify everything to a Unix-style i32.
let code = this.read_scalar(code)?.to_i32()?;
throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
@@ -657,7 +666,7 @@ fn emulate_foreign_item_inner(
"SystemFunction036" => {
// used by getrandom 0.1
// This is really 'RtlGenRandom'.
- let [ptr, len] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [ptr, len] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let len = this.read_scalar(len)?.to_u32()?;
this.gen_random(ptr, len.into())?;
@@ -665,7 +674,7 @@ fn emulate_foreign_item_inner(
}
"ProcessPrng" => {
// used by `std`
- let [ptr, len] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [ptr, len] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let len = this.read_target_usize(len)?;
this.gen_random(ptr, len)?;
@@ -674,7 +683,7 @@ fn emulate_foreign_item_inner(
"BCryptGenRandom" => {
// used by getrandom 0.2
let [algorithm, ptr, len, flags] =
- this.check_shim(abi, sys_conv, link_name, args)?;
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let algorithm = this.read_scalar(algorithm)?;
let algorithm = algorithm.to_target_usize(this)?;
let ptr = this.read_pointer(ptr)?;
@@ -708,7 +717,8 @@ fn emulate_foreign_item_inner(
}
"GetConsoleScreenBufferInfo" => {
// `term` needs this, so we fake it.
- let [console, buffer_info] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [console, buffer_info] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.read_target_isize(console)?;
// FIXME: this should use deref_pointer_as, but CONSOLE_SCREEN_BUFFER_INFO is not in std
this.deref_pointer(buffer_info)?;
@@ -717,13 +727,13 @@ fn emulate_foreign_item_inner(
this.write_null(dest)?;
}
"GetStdHandle" => {
- let [which] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [which] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let res = this.GetStdHandle(which)?;
this.write_scalar(res, dest)?;
}
"DuplicateHandle" => {
let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
- this.check_shim(abi, sys_conv, link_name, args)?;
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let res = this.DuplicateHandle(
src_proc,
src_handle,
@@ -736,14 +746,15 @@ fn emulate_foreign_item_inner(
this.write_scalar(res, dest)?;
}
"CloseHandle" => {
- let [handle] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let ret = this.CloseHandle(handle)?;
this.write_scalar(ret, dest)?;
}
"GetModuleFileNameW" => {
- let [handle, filename, size] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [handle, filename, size] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.check_no_isolation("`GetModuleFileNameW`")?;
let handle = this.read_handle(handle, "GetModuleFileNameW")?;
@@ -777,7 +788,7 @@ fn emulate_foreign_item_inner(
}
"FormatMessageW" => {
let [flags, module, message_id, language_id, buffer, size, arguments] =
- this.check_shim(abi, sys_conv, link_name, args)?;
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let flags = this.read_scalar(flags)?.to_u32()?;
let _module = this.read_pointer(module)?; // seems to contain a module name
@@ -812,26 +823,28 @@ fn emulate_foreign_item_inner(
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// These shims are enabled only when the caller is in the standard library.
"GetProcessHeap" if this.frame_in_std() => {
- let [] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
// Just fake a HANDLE
// It's fine to not use the Handle type here because its a stub
this.write_int(1, dest)?;
}
"GetModuleHandleA" if this.frame_in_std() => {
#[allow(non_snake_case)]
- let [_lpModuleName] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [_lpModuleName] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
// We need to return something non-null here to make `compat_fn!` work.
this.write_int(1, dest)?;
}
"SetConsoleTextAttribute" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_hConsoleOutput, _wAttribute] =
- this.check_shim(abi, sys_conv, link_name, args)?;
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
// Pretend these does not exist / nothing happened, by returning zero.
this.write_null(dest)?;
}
"GetConsoleMode" if this.frame_in_std() => {
- let [console, mode] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [console, mode] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.read_target_isize(console)?;
this.deref_pointer_as(mode, this.machine.layouts.u32)?;
// Indicate an error.
@@ -839,25 +852,27 @@ fn emulate_foreign_item_inner(
}
"GetFileType" if this.frame_in_std() => {
#[allow(non_snake_case)]
- let [_hFile] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [_hFile] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
// Return unknown file type.
this.write_null(dest)?;
}
"AddVectoredExceptionHandler" if this.frame_in_std() => {
#[allow(non_snake_case)]
- let [_First, _Handler] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [_First, _Handler] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
// Any non zero value works for the stdlib. This is just used for stack overflows anyway.
this.write_int(1, dest)?;
}
"SetThreadStackGuarantee" if this.frame_in_std() => {
#[allow(non_snake_case)]
- let [_StackSizeInBytes] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [_StackSizeInBytes] =
+ this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
// Any non zero value works for the stdlib. This is just used for stack overflows anyway.
this.write_int(1, dest)?;
}
// this is only callable from std because we know that std ignores the return value
"SwitchToThread" if this.frame_in_std() => {
- let [] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.yield_active_thread();
@@ -876,7 +891,7 @@ fn emulate_foreign_item_inner(
);
}
// This function looks and behaves excatly like miri_start_unwind.
- let [payload] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.handle_miri_start_unwind(payload)?;
return interp_ok(EmulateItemResult::NeedsUnwind);
}
diff --git a/src/tools/miri/src/shims/windows/fs.rs b/src/tools/miri/src/shims/windows/fs.rs
index 72e016c..e4ec1b0 100644
--- a/src/tools/miri/src/shims/windows/fs.rs
+++ b/src/tools/miri/src/shims/windows/fs.rs
@@ -462,6 +462,9 @@ fn NtWriteFile(
};
let io_status_info = this.project_field_named(&io_status_block, "Information")?;
+ // It seems like short writes are not a thing on Windows, so we don't truncate `count` here.
+ // FIXME: if we are on a Unix host, short host writes are still visible to the program!
+
let finish = {
let io_status = io_status.clone();
let io_status_info = io_status_info.clone();
@@ -491,7 +494,6 @@ fn NtWriteFile(
}}
)
};
-
desc.write(this.machine.communicate(), buf, count.try_into().unwrap(), this, finish)?;
// Return status is written to `dest` and `io_status_block` on callback completion.
@@ -556,6 +558,16 @@ fn NtReadFile(
};
let io_status_info = this.project_field_named(&io_status_block, "Information")?;
+ let fd = match handle {
+ Handle::File(fd) => fd,
+ _ => this.invalid_handle("NtWriteFile")?,
+ };
+
+ let Some(desc) = this.machine.fds.get(fd) else { this.invalid_handle("NtReadFile")? };
+
+ // It seems like short reads are not a thing on Windows, so we don't truncate `count` here.
+ // FIXME: if we are on a Unix host, short host reads are still visible to the program!
+
let finish = {
let io_status = io_status.clone();
let io_status_info = io_status_info.clone();
@@ -585,14 +597,6 @@ fn NtReadFile(
}}
)
};
-
- let fd = match handle {
- Handle::File(fd) => fd,
- _ => this.invalid_handle("NtWriteFile")?,
- };
-
- let Some(desc) = this.machine.fds.get(fd) else { this.invalid_handle("NtReadFile")? };
-
desc.read(this.machine.communicate(), buf, count.try_into().unwrap(), this, finish)?;
// See NtWriteFile for commentary on this
diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs
index 058ca24..fdd3e78 100644
--- a/src/tools/miri/src/shims/x86/aesni.rs
+++ b/src/tools/miri/src/shims/x86/aesni.rs
@@ -26,7 +26,8 @@ fn emulate_x86_aesni_intrinsic(
// `state` with the corresponding 128-bit key of `key`.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec_si128
"aesdec" | "aesdec.256" | "aesdec.512" => {
- let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [state, key] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
aes_round(this, state, key, dest, |state, key| {
let key = aes::Block::from(key.to_le_bytes());
let mut state = aes::Block::from(state.to_le_bytes());
@@ -42,7 +43,8 @@ fn emulate_x86_aesni_intrinsic(
// `state` with the corresponding 128-bit key of `key`.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdeclast_si128
"aesdeclast" | "aesdeclast.256" | "aesdeclast.512" => {
- let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [state, key] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
aes_round(this, state, key, dest, |state, key| {
let mut state = aes::Block::from(state.to_le_bytes());
@@ -66,7 +68,8 @@ fn emulate_x86_aesni_intrinsic(
// `state` with the corresponding 128-bit key of `key`.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenc_si128
"aesenc" | "aesenc.256" | "aesenc.512" => {
- let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [state, key] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
aes_round(this, state, key, dest, |state, key| {
let key = aes::Block::from(key.to_le_bytes());
let mut state = aes::Block::from(state.to_le_bytes());
@@ -82,7 +85,8 @@ fn emulate_x86_aesni_intrinsic(
// `state` with the corresponding 128-bit key of `key`.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenclast_si128
"aesenclast" | "aesenclast.256" | "aesenclast.512" => {
- let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [state, key] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
aes_round(this, state, key, dest, |state, key| {
let mut state = aes::Block::from(state.to_le_bytes());
// `aes::hazmat::cipher_round` does the following operations:
@@ -102,7 +106,7 @@ fn emulate_x86_aesni_intrinsic(
// Used to implement the _mm_aesimc_si128 function.
// Performs the AES InvMixColumns operation on `op`
"aesimc" => {
- let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
// Transmute to `u128`
let op = op.transmute(this.machine.layouts.u128, this)?;
let dest = dest.transmute(this.machine.layouts.u128, this)?;
diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs
index 83d23d6..269ce3b 100644
--- a/src/tools/miri/src/shims/x86/avx.rs
+++ b/src/tools/miri/src/shims/x86/avx.rs
@@ -33,7 +33,8 @@ fn emulate_x86_avx_intrinsic(
// matches the IEEE min/max operations, while x86 has different
// semantics.
"min.ps.256" | "max.ps.256" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"min.ps.256" => FloatBinOp::Min,
@@ -45,7 +46,8 @@ fn emulate_x86_avx_intrinsic(
}
// Used to implement _mm256_min_pd and _mm256_max_pd functions.
"min.pd.256" | "max.pd.256" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"min.pd.256" => FloatBinOp::Min,
@@ -58,21 +60,23 @@ fn emulate_x86_avx_intrinsic(
// Used to implement the _mm256_round_ps function.
// Rounds the elements of `op` according to `rounding`.
"round.ps.256" => {
- let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op, rounding] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
round_all::<rustc_apfloat::ieee::Single>(this, op, rounding, dest)?;
}
// Used to implement the _mm256_round_pd function.
// Rounds the elements of `op` according to `rounding`.
"round.pd.256" => {
- let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op, rounding] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
round_all::<rustc_apfloat::ieee::Double>(this, op, rounding, dest)?;
}
// Used to implement _mm256_{rcp,rsqrt}_ps functions.
// Performs the operations on all components of `op`.
"rcp.ps.256" | "rsqrt.ps.256" => {
- let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"rcp.ps.256" => FloatUnaryOp::Rcp,
@@ -84,7 +88,8 @@ fn emulate_x86_avx_intrinsic(
}
// Used to implement the _mm256_dp_ps function.
"dp.ps.256" => {
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
conditional_dot_product(this, left, right, imm, dest)?;
}
@@ -92,7 +97,8 @@ fn emulate_x86_avx_intrinsic(
// Horizontally add/subtract adjacent floating point values
// in `left` and `right`.
"hadd.ps.256" | "hadd.pd.256" | "hsub.ps.256" | "hsub.pd.256" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"hadd.ps.256" | "hadd.pd.256" => mir::BinOp::Add,
@@ -107,7 +113,8 @@ fn emulate_x86_avx_intrinsic(
// and `right`. For each component, returns 0 if false or u32::MAX
// if true.
"cmp.ps.256" => {
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -119,7 +126,8 @@ fn emulate_x86_avx_intrinsic(
// and `right`. For each component, returns 0 if false or u64::MAX
// if true.
"cmp.pd.256" => {
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -130,7 +138,7 @@ fn emulate_x86_avx_intrinsic(
// and _mm256_cvttpd_epi32 functions.
// Converts packed f32/f64 to packed i32.
"cvt.ps2dq.256" | "cvtt.ps2dq.256" | "cvt.pd2dq.256" | "cvtt.pd2dq.256" => {
- let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let rnd = match unprefixed_name {
// "current SSE rounding mode", assume nearest
@@ -148,7 +156,8 @@ fn emulate_x86_avx_intrinsic(
// sequence of 4-element arrays, and we shuffle each of these arrays, where
// `control` determines which element of the current `data` array is written.
"vpermilvar.ps" | "vpermilvar.ps.256" => {
- let [data, control] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [data, control] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (data, data_len) = this.project_to_simd(data)?;
let (control, control_len) = this.project_to_simd(control)?;
@@ -181,7 +190,8 @@ fn emulate_x86_avx_intrinsic(
// where `right` determines which element of the current `left` array is
// written.
"vpermilvar.pd" | "vpermilvar.pd.256" => {
- let [data, control] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [data, control] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (data, data_len) = this.project_to_simd(data)?;
let (control, control_len) = this.project_to_simd(control)?;
@@ -213,7 +223,8 @@ fn emulate_x86_avx_intrinsic(
// For each 128-bit element of `dest`, copies one from `left`, `right` or
// zero, according to `imm`.
"vperm2f128.ps.256" | "vperm2f128.pd.256" | "vperm2f128.si.256" => {
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
assert_eq!(dest.layout, left.layout);
assert_eq!(dest.layout, right.layout);
@@ -256,7 +267,7 @@ fn emulate_x86_avx_intrinsic(
// is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is
// loaded.
"maskload.ps" | "maskload.pd" | "maskload.ps.256" | "maskload.pd.256" => {
- let [ptr, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr, mask] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
mask_load(this, ptr, mask, dest)?;
}
@@ -266,7 +277,8 @@ fn emulate_x86_avx_intrinsic(
// is one, it is stored into `ptr.wapping_add(i)`.
// Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores.
"maskstore.ps" | "maskstore.pd" | "maskstore.ps.256" | "maskstore.pd.256" => {
- let [ptr, mask, value] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr, mask, value] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
mask_store(this, ptr, mask, value)?;
}
@@ -276,7 +288,7 @@ fn emulate_x86_avx_intrinsic(
// the data crosses a cache line, but for Miri this is just a regular
// unaligned read.
"ldu.dq.256" => {
- let [src_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [src_ptr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let src_ptr = this.read_pointer(src_ptr)?;
let dest = dest.force_mplace(this)?;
@@ -288,7 +300,7 @@ fn emulate_x86_avx_intrinsic(
// Tests `op & mask == 0`, `op & mask == mask` or
// `op & mask != 0 && op & mask != mask`
"ptestz.256" | "ptestc.256" | "ptestnzc.256" => {
- let [op, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op, mask] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (all_zero, masked_set) = test_bits_masked(this, op, mask)?;
let res = match unprefixed_name {
@@ -311,7 +323,7 @@ fn emulate_x86_avx_intrinsic(
"vtestz.pd.256" | "vtestc.pd.256" | "vtestnzc.pd.256" | "vtestz.pd" | "vtestc.pd"
| "vtestnzc.pd" | "vtestz.ps.256" | "vtestc.ps.256" | "vtestnzc.ps.256"
| "vtestz.ps" | "vtestc.ps" | "vtestnzc.ps" => {
- let [op, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op, mask] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (direct, negated) = test_high_bits_masked(this, op, mask)?;
let res = match unprefixed_name {
@@ -333,7 +345,7 @@ fn emulate_x86_avx_intrinsic(
// compiler, making these functions no-ops.
// The only thing that needs to be ensured is the correct calling convention.
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
}
_ => return interp_ok(EmulateItemResult::NotSupported),
}
diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs
index 49d5977..ca80c0e 100644
--- a/src/tools/miri/src/shims/x86/avx2.rs
+++ b/src/tools/miri/src/shims/x86/avx2.rs
@@ -28,7 +28,7 @@ fn emulate_x86_avx2_intrinsic(
// Used to implement the _mm256_abs_epi{8,16,32} functions.
// Calculates the absolute value of packed 8/16/32-bit integers.
"pabs.b" | "pabs.w" | "pabs.d" => {
- let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
int_abs(this, op, dest)?;
}
@@ -36,7 +36,8 @@ fn emulate_x86_avx2_intrinsic(
// Horizontally add / add with saturation / subtract adjacent 16/32-bit
// integer values in `left` and `right`.
"phadd.w" | "phadd.sw" | "phadd.d" | "phsub.w" | "phsub.sw" | "phsub.d" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (which, saturating) = match unprefixed_name {
"phadd.w" | "phadd.d" => (mir::BinOp::Add, false),
@@ -57,7 +58,7 @@ fn emulate_x86_avx2_intrinsic(
| "gather.d.pd.256" | "gather.q.pd" | "gather.q.pd.256" | "gather.d.ps"
| "gather.d.ps.256" | "gather.q.ps" | "gather.q.ps.256" => {
let [src, slice, offsets, mask, scale] =
- this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
assert_eq!(dest.layout, src.layout);
@@ -114,7 +115,8 @@ fn emulate_x86_avx2_intrinsic(
// intermediate signed 32-bit integers. Horizontally add adjacent pairs of
// intermediate 32-bit integers, and pack the results in `dest`.
"pmadd.wd" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -150,7 +152,8 @@ fn emulate_x86_avx2_intrinsic(
// the saturating sum of the products with indices `2*i` and `2*i+1`
// produces the output at index `i`.
"pmadd.ub.sw" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -184,7 +187,7 @@ fn emulate_x86_avx2_intrinsic(
// is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is
// loaded.
"maskload.d" | "maskload.q" | "maskload.d.256" | "maskload.q.256" => {
- let [ptr, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr, mask] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
mask_load(this, ptr, mask, dest)?;
}
@@ -194,7 +197,8 @@ fn emulate_x86_avx2_intrinsic(
// is one, it is stored into `ptr.wapping_add(i)`.
// Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores.
"maskstore.d" | "maskstore.q" | "maskstore.d.256" | "maskstore.q.256" => {
- let [ptr, mask, value] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [ptr, mask, value] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
mask_store(this, ptr, mask, value)?;
}
@@ -205,7 +209,8 @@ fn emulate_x86_avx2_intrinsic(
// offsets specified in `imm`.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mpsadbw_epu8
"mpsadbw" => {
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
mpsadbw(this, left, right, imm, dest)?;
}
@@ -216,7 +221,8 @@ fn emulate_x86_avx2_intrinsic(
// 1 and then taking the bits `1..=16`.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhrs_epi16
"pmul.hr.sw" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
pmulhrsw(this, left, right, dest)?;
}
@@ -224,7 +230,8 @@ fn emulate_x86_avx2_intrinsic(
// Converts two 16-bit integer vectors to a single 8-bit integer
// vector with signed saturation.
"packsswb" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
packsswb(this, left, right, dest)?;
}
@@ -232,7 +239,8 @@ fn emulate_x86_avx2_intrinsic(
// Converts two 32-bit integer vectors to a single 16-bit integer
// vector with signed saturation.
"packssdw" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
packssdw(this, left, right, dest)?;
}
@@ -240,7 +248,8 @@ fn emulate_x86_avx2_intrinsic(
// Converts two 16-bit signed integer vectors to a single 8-bit
// unsigned integer vector with saturation.
"packuswb" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
packuswb(this, left, right, dest)?;
}
@@ -248,7 +257,8 @@ fn emulate_x86_avx2_intrinsic(
// Concatenates two 32-bit signed integer vectors and converts
// the result to a 16-bit unsigned integer vector with saturation.
"packusdw" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
packusdw(this, left, right, dest)?;
}
@@ -257,7 +267,8 @@ fn emulate_x86_avx2_intrinsic(
// Shuffles `left` using the three low bits of each element of `right`
// as indices.
"permd" | "permps" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -277,7 +288,8 @@ fn emulate_x86_avx2_intrinsic(
// Used to implement the _mm256_permute2x128_si256 function.
// Shuffles 128-bit blocks of `a` and `b` using `imm` as pattern.
"vperm2i128" => {
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
assert_eq!(left.layout.size.bits(), 256);
assert_eq!(right.layout.size.bits(), 256);
@@ -314,7 +326,8 @@ fn emulate_x86_avx2_intrinsic(
// in `dest`.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_sad_epu8
"psad.bw" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -346,7 +359,8 @@ fn emulate_x86_avx2_intrinsic(
// Shuffles bytes from `left` using `right` as pattern.
// Each 128-bit block is shuffled independently.
"pshuf.b" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -377,7 +391,8 @@ fn emulate_x86_avx2_intrinsic(
// is writen to the corresponding output element.
// Basically, we multiply `left` with `right.signum()`.
"psign.b" | "psign.w" | "psign.d" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
psign(this, left, right, dest)?;
}
@@ -391,7 +406,8 @@ fn emulate_x86_avx2_intrinsic(
// is copied to remaining bits.
"psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q"
| "psrl.q" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"psll.w" | "psll.d" | "psll.q" => ShiftOp::Left,
@@ -406,7 +422,8 @@ fn emulate_x86_avx2_intrinsic(
// (except _mm{,256}_srav_epi64, which are not available in AVX2).
"psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" | "psrlv.d" | "psrlv.d.256"
| "psrlv.q" | "psrlv.q.256" | "psrav.d" | "psrav.d.256" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" => ShiftOp::Left,
diff --git a/src/tools/miri/src/shims/x86/bmi.rs b/src/tools/miri/src/shims/x86/bmi.rs
index 80b1b2e..140e31c 100644
--- a/src/tools/miri/src/shims/x86/bmi.rs
+++ b/src/tools/miri/src/shims/x86/bmi.rs
@@ -35,7 +35,7 @@ fn emulate_x86_bmi_intrinsic(
return interp_ok(EmulateItemResult::NotSupported);
}
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let left = this.read_scalar(left)?;
let right = this.read_scalar(right)?;
diff --git a/src/tools/miri/src/shims/x86/gfni.rs b/src/tools/miri/src/shims/x86/gfni.rs
index f83ce56..9a98a80 100644
--- a/src/tools/miri/src/shims/x86/gfni.rs
+++ b/src/tools/miri/src/shims/x86/gfni.rs
@@ -31,14 +31,16 @@ fn emulate_x86_gfni_intrinsic(
// See `affine_transform` for details.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affine_
"vgf2p8affineqb.128" | "vgf2p8affineqb.256" | "vgf2p8affineqb.512" => {
- let [left, right, imm8] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm8] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
affine_transform(this, left, right, imm8, dest, /* inverse */ false)?;
}
// Used to implement the `_mm{, 256, 512}_gf2p8affineinv_epi64_epi8` functions.
// See `affine_transform` for details.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affineinv
"vgf2p8affineinvqb.128" | "vgf2p8affineinvqb.256" | "vgf2p8affineinvqb.512" => {
- let [left, right, imm8] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm8] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
affine_transform(this, left, right, imm8, dest, /* inverse */ true)?;
}
// Used to implement the `_mm{, 256, 512}_gf2p8mul_epi8` functions.
@@ -47,7 +49,8 @@ fn emulate_x86_gfni_intrinsic(
// polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul
"vgf2p8mulb.128" | "vgf2p8mulb.256" | "vgf2p8mulb.512" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
let (dest, dest_len) = this.project_to_simd(dest)?;
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index fbfe459..3324b7b 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -45,7 +45,8 @@ fn emulate_x86_intrinsic(
return interp_ok(EmulateItemResult::NotSupported);
}
- let [cb_in, a, b] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [cb_in, a, b] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let op = if unprefixed_name.starts_with("add") {
mir::BinOp::AddWithOverflow
} else {
@@ -67,7 +68,8 @@ fn emulate_x86_intrinsic(
if is_u64 && this.tcx.sess.target.arch != "x86_64" {
return interp_ok(EmulateItemResult::NotSupported);
}
- let [c_in, a, b, out] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [c_in, a, b, out] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let out = this.deref_pointer_as(
out,
if is_u64 { this.machine.layouts.u64 } else { this.machine.layouts.u32 },
@@ -84,7 +86,7 @@ fn emulate_x86_intrinsic(
// the instruction behaves like a no-op, so it is always safe to call the
// intrinsic.
"sse2.pause" => {
- let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
// Only exhibit the spin-loop hint behavior when SSE2 is enabled.
if this.tcx.sess.unstable_target_features.contains(&Symbol::intern("sse2")) {
this.yield_active_thread();
@@ -103,7 +105,8 @@ fn emulate_x86_intrinsic(
len = 8;
}
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
pclmulqdq(this, left, right, imm, dest, len)?;
}
diff --git a/src/tools/miri/src/shims/x86/sha.rs b/src/tools/miri/src/shims/x86/sha.rs
index d37fad3..00fe581 100644
--- a/src/tools/miri/src/shims/x86/sha.rs
+++ b/src/tools/miri/src/shims/x86/sha.rs
@@ -53,7 +53,7 @@ fn write<'c>(
match unprefixed_name {
// Used to implement the _mm_sha256rnds2_epu32 function.
"256rnds2" => {
- let [a, b, k] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [a, b, k] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (a_reg, a_len) = this.project_to_simd(a)?;
let (b_reg, b_len) = this.project_to_simd(b)?;
@@ -74,7 +74,7 @@ fn write<'c>(
}
// Used to implement the _mm_sha256msg1_epu32 function.
"256msg1" => {
- let [a, b] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [a, b] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (a_reg, a_len) = this.project_to_simd(a)?;
let (b_reg, b_len) = this.project_to_simd(b)?;
@@ -92,7 +92,7 @@ fn write<'c>(
}
// Used to implement the _mm_sha256msg2_epu32 function.
"256msg2" => {
- let [a, b] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [a, b] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (a_reg, a_len) = this.project_to_simd(a)?;
let (b_reg, b_len) = this.project_to_simd(b)?;
diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs
index 1ec15d6..6d8def5 100644
--- a/src/tools/miri/src/shims/x86/sse.rs
+++ b/src/tools/miri/src/shims/x86/sse.rs
@@ -34,7 +34,8 @@ fn emulate_x86_sse_intrinsic(
// Performs the operations on the first component of `left` and
// `right` and copies the remaining components from `left`.
"min.ss" | "max.ss" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"min.ss" => FloatBinOp::Min,
@@ -50,7 +51,8 @@ fn emulate_x86_sse_intrinsic(
// matches the IEEE min/max operations, while x86 has different
// semantics.
"min.ps" | "max.ps" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"min.ps" => FloatBinOp::Min,
@@ -64,7 +66,7 @@ fn emulate_x86_sse_intrinsic(
// Performs the operations on the first component of `op` and
// copies the remaining components from `op`.
"rcp.ss" | "rsqrt.ss" => {
- let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"rcp.ss" => FloatUnaryOp::Rcp,
@@ -77,7 +79,7 @@ fn emulate_x86_sse_intrinsic(
// Used to implement _mm_{sqrt,rcp,rsqrt}_ps functions.
// Performs the operations on all components of `op`.
"rcp.ps" | "rsqrt.ps" => {
- let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"rcp.ps" => FloatUnaryOp::Rcp,
@@ -96,7 +98,8 @@ fn emulate_x86_sse_intrinsic(
// _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ss are SSE functions
// with hard-coded operations.
"cmp.ss" => {
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -112,7 +115,8 @@ fn emulate_x86_sse_intrinsic(
// _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ps are SSE functions
// with hard-coded operations.
"cmp.ps" => {
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -125,7 +129,8 @@ fn emulate_x86_sse_intrinsic(
"comieq.ss" | "comilt.ss" | "comile.ss" | "comigt.ss" | "comige.ss" | "comineq.ss"
| "ucomieq.ss" | "ucomilt.ss" | "ucomile.ss" | "ucomigt.ss" | "ucomige.ss"
| "ucomineq.ss" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -153,7 +158,7 @@ fn emulate_x86_sse_intrinsic(
// _mm_cvtss_si64 and _mm_cvttss_si64 functions.
// Converts the first component of `op` from f32 to i32/i64.
"cvtss2si" | "cvttss2si" | "cvtss2si64" | "cvttss2si64" => {
- let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (op, _) = this.project_to_simd(op)?;
let op = this.read_immediate(&this.project_index(&op, 0)?)?;
@@ -181,7 +186,8 @@ fn emulate_x86_sse_intrinsic(
// are copied from `left`.
// https://www.felixcloutier.com/x86/cvtsi2ss
"cvtsi2ss" | "cvtsi642ss" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (dest, dest_len) = this.project_to_simd(dest)?;
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index d6052f8..8f53adf 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -41,7 +41,8 @@ fn emulate_x86_sse2_intrinsic(
// intermediate signed 32-bit integers. Horizontally add adjacent pairs of
// intermediate 32-bit integers, and pack the results in `dest`.
"pmadd.wd" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -79,7 +80,8 @@ fn emulate_x86_sse2_intrinsic(
//
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sad_epu8
"psad.bw" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -117,7 +119,8 @@ fn emulate_x86_sse2_intrinsic(
// is copied to remaining bits.
"psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q"
| "psrl.q" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"psll.w" | "psll.d" | "psll.q" => ShiftOp::Left,
@@ -132,7 +135,7 @@ fn emulate_x86_sse2_intrinsic(
// and _mm_cvttpd_epi32 functions.
// Converts packed f32/f64 to packed i32.
"cvtps2dq" | "cvttps2dq" | "cvtpd2dq" | "cvttpd2dq" => {
- let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (op_len, _) = op.layout.ty.simd_size_and_type(*this.tcx);
let (dest_len, _) = dest.layout.ty.simd_size_and_type(*this.tcx);
@@ -169,7 +172,8 @@ fn emulate_x86_sse2_intrinsic(
// Converts two 16-bit integer vectors to a single 8-bit integer
// vector with signed saturation.
"packsswb.128" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
packsswb(this, left, right, dest)?;
}
@@ -177,7 +181,8 @@ fn emulate_x86_sse2_intrinsic(
// Converts two 16-bit signed integer vectors to a single 8-bit
// unsigned integer vector with saturation.
"packuswb.128" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
packuswb(this, left, right, dest)?;
}
@@ -185,7 +190,8 @@ fn emulate_x86_sse2_intrinsic(
// Converts two 32-bit integer vectors to a single 16-bit integer
// vector with signed saturation.
"packssdw.128" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
packssdw(this, left, right, dest)?;
}
@@ -195,7 +201,8 @@ fn emulate_x86_sse2_intrinsic(
// matches the IEEE min/max operations, while x86 has different
// semantics.
"min.sd" | "max.sd" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"min.sd" => FloatBinOp::Min,
@@ -211,7 +218,8 @@ fn emulate_x86_sse2_intrinsic(
// matches the IEEE min/max operations, while x86 has different
// semantics.
"min.pd" | "max.pd" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"min.pd" => FloatBinOp::Min,
@@ -230,7 +238,8 @@ fn emulate_x86_sse2_intrinsic(
// _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_sd are SSE2 functions
// with hard-coded operations.
"cmp.sd" => {
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -246,7 +255,8 @@ fn emulate_x86_sse2_intrinsic(
// _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_pd are SSE2 functions
// with hard-coded operations.
"cmp.pd" => {
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -259,7 +269,8 @@ fn emulate_x86_sse2_intrinsic(
"comieq.sd" | "comilt.sd" | "comile.sd" | "comigt.sd" | "comige.sd" | "comineq.sd"
| "ucomieq.sd" | "ucomilt.sd" | "ucomile.sd" | "ucomigt.sd" | "ucomige.sd"
| "ucomineq.sd" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -287,7 +298,7 @@ fn emulate_x86_sse2_intrinsic(
// _mm_cvtsd_si64 and _mm_cvttsd_si64 functions.
// Converts the first component of `op` from f64 to i32/i64.
"cvtsd2si" | "cvttsd2si" | "cvtsd2si64" | "cvttsd2si64" => {
- let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (op, _) = this.project_to_simd(op)?;
let op = this.read_immediate(&this.project_index(&op, 0)?)?;
@@ -313,7 +324,8 @@ fn emulate_x86_sse2_intrinsic(
// Converts the first f64/f32 from `right` to f32/f64 and copies
// the remaining elements from `left`
"cvtsd2ss" | "cvtss2sd" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, _) = this.project_to_simd(right)?;
diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs
index ebf3cb5..0fd8c3b 100644
--- a/src/tools/miri/src/shims/x86/sse3.rs
+++ b/src/tools/miri/src/shims/x86/sse3.rs
@@ -26,7 +26,8 @@ fn emulate_x86_sse3_intrinsic(
// Horizontally add/subtract adjacent floating point values
// in `left` and `right`.
"hadd.ps" | "hadd.pd" | "hsub.ps" | "hsub.pd" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let which = match unprefixed_name {
"hadd.ps" | "hadd.pd" => mir::BinOp::Add,
@@ -42,7 +43,7 @@ fn emulate_x86_sse3_intrinsic(
// the data crosses a cache line, but for Miri this is just a regular
// unaligned read.
"ldu.dq" => {
- let [src_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [src_ptr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let src_ptr = this.read_pointer(src_ptr)?;
let dest = dest.force_mplace(this)?;
diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs
index 6797039..7736b5e 100644
--- a/src/tools/miri/src/shims/x86/sse41.rs
+++ b/src/tools/miri/src/shims/x86/sse41.rs
@@ -28,7 +28,8 @@ fn emulate_x86_sse41_intrinsic(
// bits `4..=5` if `imm`, and `i`th bit specifies whether element
// `i` is zeroed.
"insertps" => {
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -63,7 +64,8 @@ fn emulate_x86_sse41_intrinsic(
// Concatenates two 32-bit signed integer vectors and converts
// the result to a 16-bit unsigned integer vector with saturation.
"packusdw" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
packusdw(this, left, right, dest)?;
}
@@ -73,7 +75,8 @@ fn emulate_x86_sse41_intrinsic(
// products, and conditionally stores the sum in `dest` using the low
// 4 bits of `imm`.
"dpps" | "dppd" => {
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
conditional_dot_product(this, left, right, imm, dest)?;
}
@@ -81,14 +84,16 @@ fn emulate_x86_sse41_intrinsic(
// functions. Rounds the first element of `right` according to `rounding`
// and copies the remaining elements from `left`.
"round.ss" => {
- let [left, right, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, rounding] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
round_first::<rustc_apfloat::ieee::Single>(this, left, right, rounding, dest)?;
}
// Used to implement the _mm_floor_ps, _mm_ceil_ps and _mm_round_ps
// functions. Rounds the elements of `op` according to `rounding`.
"round.ps" => {
- let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op, rounding] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
round_all::<rustc_apfloat::ieee::Single>(this, op, rounding, dest)?;
}
@@ -96,14 +101,16 @@ fn emulate_x86_sse41_intrinsic(
// functions. Rounds the first element of `right` according to `rounding`
// and copies the remaining elements from `left`.
"round.sd" => {
- let [left, right, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, rounding] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
round_first::<rustc_apfloat::ieee::Double>(this, left, right, rounding, dest)?;
}
// Used to implement the _mm_floor_pd, _mm_ceil_pd and _mm_round_pd
// functions. Rounds the elements of `op` according to `rounding`.
"round.pd" => {
- let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op, rounding] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
round_all::<rustc_apfloat::ieee::Double>(this, op, rounding, dest)?;
}
@@ -111,7 +118,7 @@ fn emulate_x86_sse41_intrinsic(
// Find the minimum unsinged 16-bit integer in `op` and
// returns its value and position.
"phminposuw" => {
- let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (op, op_len) = this.project_to_simd(op)?;
let (dest, dest_len) = this.project_to_simd(dest)?;
@@ -145,7 +152,8 @@ fn emulate_x86_sse41_intrinsic(
// offsets specified in `imm`.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mpsadbw_epu8
"mpsadbw" => {
- let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
mpsadbw(this, left, right, imm, dest)?;
}
@@ -154,7 +162,7 @@ fn emulate_x86_sse41_intrinsic(
// Tests `(op & mask) == 0`, `(op & mask) == mask` or
// `(op & mask) != 0 && (op & mask) != mask`
"ptestz" | "ptestc" | "ptestnzc" => {
- let [op, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op, mask] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (all_zero, masked_set) = test_bits_masked(this, op, mask)?;
let res = match unprefixed_name {
diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs
index 7e1e148..72c5039 100644
--- a/src/tools/miri/src/shims/x86/sse42.rs
+++ b/src/tools/miri/src/shims/x86/sse42.rs
@@ -222,7 +222,8 @@ fn deconstruct_args<'tcx>(
};
if is_explicit {
- let [str1, len1, str2, len2, imm] = ecx.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [str1, len1, str2, len2, imm] =
+ ecx.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let imm = ecx.read_scalar(imm)?.to_u8()?;
let default_len = default_len::<u32>(imm);
@@ -235,7 +236,7 @@ fn deconstruct_args<'tcx>(
interp_ok((str1, str2, Some((len1, len2)), imm))
} else {
- let [str1, str2, imm] = ecx.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [str1, str2, imm] = ecx.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let imm = ecx.read_scalar(imm)?.to_u8()?;
let array_layout = array_layout_fn(ecx, imm)?;
@@ -385,7 +386,8 @@ fn emulate_x86_sse42_intrinsic(
// search for a null terminator (see `deconstruct_args` for more details).
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=924,925
"pcmpistriz128" | "pcmpistris128" => {
- let [str1, str2, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [str1, str2, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let imm = this.read_scalar(imm)?.to_u8()?;
let str = if unprefixed_name == "pcmpistris128" { str1 } else { str2 };
@@ -405,7 +407,8 @@ fn emulate_x86_sse42_intrinsic(
// than 16 for byte-sized operands or 8 for word-sized operands.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=1046,1047
"pcmpestriz128" | "pcmpestris128" => {
- let [_, len1, _, len2, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [_, len1, _, len2, imm] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let len = if unprefixed_name == "pcmpestris128" { len1 } else { len2 };
let len = this.read_scalar(len)?.to_i32()?;
let imm = this.read_scalar(imm)?.to_u8()?;
@@ -432,7 +435,8 @@ fn emulate_x86_sse42_intrinsic(
return interp_ok(EmulateItemResult::NotSupported);
}
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let left = this.read_scalar(left)?;
let right = this.read_scalar(right)?;
diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs
index 310d6b8..52ad6bd 100644
--- a/src/tools/miri/src/shims/x86/ssse3.rs
+++ b/src/tools/miri/src/shims/x86/ssse3.rs
@@ -25,7 +25,7 @@ fn emulate_x86_ssse3_intrinsic(
// Used to implement the _mm_abs_epi{8,16,32} functions.
// Calculates the absolute value of packed 8/16/32-bit integers.
"pabs.b.128" | "pabs.w.128" | "pabs.d.128" => {
- let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
int_abs(this, op, dest)?;
}
@@ -33,7 +33,8 @@ fn emulate_x86_ssse3_intrinsic(
// Shuffles bytes from `left` using `right` as pattern.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_shuffle_epi8
"pshuf.b.128" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -62,7 +63,8 @@ fn emulate_x86_ssse3_intrinsic(
// integer values in `left` and `right`.
"phadd.w.128" | "phadd.sw.128" | "phadd.d.128" | "phsub.w.128" | "phsub.sw.128"
| "phsub.d.128" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (which, saturating) = match unprefixed_name {
"phadd.w.128" | "phadd.d.128" => (mir::BinOp::Add, false),
@@ -81,7 +83,8 @@ fn emulate_x86_ssse3_intrinsic(
// produces the output at index `i`.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_maddubs_epi16
"pmadd.ub.sw.128" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -116,7 +119,8 @@ fn emulate_x86_ssse3_intrinsic(
// 1 and then taking the bits `1..=16`.
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhrs_epi16
"pmul.hr.sw.128" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
pmulhrsw(this, left, right, dest)?;
}
@@ -126,7 +130,8 @@ fn emulate_x86_ssse3_intrinsic(
// is writen to the corresponding output element.
// Basically, we multiply `left` with `right.signum()`.
"psign.b.128" | "psign.w.128" | "psign.d.128" => {
- let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+ let [left, right] =
+ this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
psign(this, left, right, dest)?;
}
diff --git a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs
index 314ce90..f6ec5be 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs
@@ -10,6 +10,9 @@
use std::thread;
use std::thread::spawn;
+#[path = "../../utils/libc.rs"]
+mod libc_utils;
+
#[track_caller]
fn check_epoll_wait<const N: usize>(epfd: i32, expected_notifications: &[(u32, u64)]) {
let epoll_event = libc::epoll_event { events: 0, u64: 0 };
@@ -69,12 +72,12 @@ fn main() {
unsafe { VAL_ONE = 41 };
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds_a[0], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds_a[0], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
unsafe { VAL_TWO = 51 };
- let res = unsafe { libc::write(fds_b[0], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds_b[0], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
});
thread::yield_now();
diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs
index 1dc3344..e2fd646 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs
@@ -10,6 +10,9 @@
#[path = "../../utils/mod.rs"]
mod utils;
+#[path = "../../utils/libc.rs"]
+mod libc_utils;
+
fn main() {
let path =
utils::prepare_with_content("fail-libc-read-and-uninit-premature-eof.txt", &[1u8, 2, 3]);
@@ -18,8 +21,9 @@ fn main() {
let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY);
assert_ne!(fd, -1);
let mut buf: MaybeUninit<[u8; 4]> = std::mem::MaybeUninit::uninit();
- // Read 4 bytes from a 3-byte file.
- assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::<std::ffi::c_void>(), 4), 3);
+ // Read as much as we can from a 3-byte file.
+ let res = libc_utils::read_all(fd, buf.as_mut_ptr().cast::<std::ffi::c_void>(), 4);
+ assert!(res == 3);
buf.assume_init(); //~ERROR: encountered uninitialized memory, but expected an integer
assert_eq!(libc::close(fd), 0);
}
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
index f6f2e2b..054cb81 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
@@ -75,9 +75,10 @@ fn main() {
});
let thread3 = spawn(move || {
+ // Just a single write, so we only wake up one of them.
let data = "abcde".as_bytes().as_ptr();
let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
- assert_eq!(res, 5);
+ assert!(res > 0 && res <= 5);
});
thread1.join().unwrap();
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs
index b383985..0fecfb8 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs
@@ -4,6 +4,7 @@
// test_race depends on a deterministic schedule.
//@compile-flags: -Zmiri-deterministic-concurrency
//@error-in-other-file: deadlock
+//@require-annotations-for-level: error
use std::thread;
@@ -22,24 +23,26 @@ fn main() {
assert_eq!(res, 0);
let thread1 = thread::spawn(move || {
// Let this thread block on read.
- let mut buf: [u8; 3] = [0; 3];
+ let mut buf: [u8; 1] = [0; 1];
let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
- assert_eq!(res, 3);
- assert_eq!(&buf, "abc".as_bytes());
+ assert_eq!(res, buf.len().cast_signed());
+ assert_eq!(&buf, "a".as_bytes());
});
let thread2 = thread::spawn(move || {
// Let this thread block on read.
- let mut buf: [u8; 3] = [0; 3];
- let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
- //~^ERROR: deadlocked
- assert_eq!(res, 3);
- assert_eq!(&buf, "abc".as_bytes());
+ let mut buf: [u8; 1] = [0; 1];
+ let res = unsafe {
+ libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
+ //~^ERROR: deadlock
+ };
+ assert_eq!(res, buf.len().cast_signed());
+ assert_eq!(&buf, "a".as_bytes());
});
let thread3 = thread::spawn(move || {
// Unblock thread1 by writing something.
- let data = "abc".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
- assert_eq!(res, 3);
+ let data = "a".as_bytes();
+ let res = unsafe { libc::write(fds[0], data.as_ptr() as *const libc::c_void, data.len()) };
+ assert_eq!(res, data.len().cast_signed());
});
thread1.join().unwrap();
thread2.join().unwrap();
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr
index 9f19a60..99d242e 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr
@@ -23,8 +23,8 @@
error: the evaluated program deadlocked
--> tests/fail-dep/libc/socketpair_block_read_twice.rs:LL:CC
|
-LL | let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
- | ^ this thread got stuck here
+LL | libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
+ | ^ this thread got stuck here
|
= note: BACKTRACE on thread `unnamed-ID`:
= note: inside closure at tests/fail-dep/libc/socketpair_block_read_twice.rs:LL:CC
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs
index 7d84d87..048938c 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs
@@ -4,16 +4,20 @@
// test_race depends on a deterministic schedule.
//@compile-flags: -Zmiri-deterministic-concurrency
//@error-in-other-file: deadlock
+//@require-annotations-for-level: error
use std::thread;
+#[path = "../../utils/libc.rs"]
+mod libc_utils;
+
// Test the behaviour of a thread being blocked on write, get unblocked, then blocked again.
// The expected execution is
// 1. Thread 1 blocks.
// 2. Thread 2 blocks.
// 3. Thread 3 unblocks both thread 1 and thread 2.
-// 4. Thread 1 reads.
+// 4. Thread 1 writes.
// 5. Thread 2's `write` can never complete -> deadlocked.
fn main() {
let mut fds = [-1, -1];
@@ -21,27 +25,28 @@ fn main() {
assert_eq!(res, 0);
let arr1: [u8; 212992] = [1; 212992];
// Exhaust the space in the buffer so the subsequent write will block.
- let res = unsafe { libc::write(fds[0], arr1.as_ptr() as *const libc::c_void, 212992) };
+ let res =
+ unsafe { libc_utils::write_all(fds[0], arr1.as_ptr() as *const libc::c_void, 212992) };
assert_eq!(res, 212992);
let thread1 = thread::spawn(move || {
- let data = "abc".as_bytes().as_ptr();
+ let data = "a".as_bytes();
// The write below will be blocked because the buffer is already full.
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
- assert_eq!(res, 3);
+ let res = unsafe { libc::write(fds[0], data.as_ptr() as *const libc::c_void, data.len()) };
+ assert_eq!(res, data.len().cast_signed());
});
let thread2 = thread::spawn(move || {
- let data = "abc".as_bytes().as_ptr();
+ let data = "a".as_bytes();
// The write below will be blocked because the buffer is already full.
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
- //~^ERROR: deadlocked
- assert_eq!(res, 3);
+ let res = unsafe { libc::write(fds[0], data.as_ptr() as *const libc::c_void, data.len()) };
+ //~^ERROR: deadlock
+ assert_eq!(res, data.len().cast_signed());
});
let thread3 = thread::spawn(move || {
// Unblock thread1 by freeing up some space.
- let mut buf: [u8; 3] = [0; 3];
+ let mut buf: [u8; 1] = [0; 1];
let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
- assert_eq!(res, 3);
- assert_eq!(buf, [1, 1, 1]);
+ assert_eq!(res, buf.len().cast_signed());
+ assert_eq!(buf, [1]);
});
thread1.join().unwrap();
thread2.join().unwrap();
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr
index b29cd70..f766500 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr
@@ -23,8 +23,8 @@
error: the evaluated program deadlocked
--> tests/fail-dep/libc/socketpair_block_write_twice.rs:LL:CC
|
-LL | let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
- | ^ this thread got stuck here
+LL | let res = unsafe { libc::write(fds[0], data.as_ptr() as *const libc::c_void, data.len()) };
+ | ^ this thread got stuck here
|
= note: BACKTRACE on thread `unnamed-ID`:
= note: inside closure at tests/fail-dep/libc/socketpair_block_write_twice.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs
index 4468eb2..26f2e73 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs
@@ -17,5 +17,5 @@ fn f(_: S) {}
// These two types have the same size but are still not compatible.
let g = unsafe { std::mem::transmute::<fn(S), fn(A)>(f) };
- g(Default::default()) //~ ERROR: calling a function with argument of type S passing data of type [i32; 4]
+ g(Default::default()) //~ ERROR: type S passing argument of type [i32; 4]
}
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr
index cabefa8..f793abb 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: calling a function with argument of type S passing data of type [i32; 4]
+error: Undefined Behavior: calling a function whose parameter #1 has type S passing argument of type [i32; 4]
--> tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC
|
LL | g(Default::default())
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs
index a1fda32..0cca4a1 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs
@@ -3,5 +3,5 @@ fn f(_: f32) {}
let g = unsafe { std::mem::transmute::<fn(f32), fn(i32)>(f) };
- g(42) //~ ERROR: calling a function with argument of type f32 passing data of type i32
+ g(42) //~ ERROR: type f32 passing argument of type i32
}
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr
index 52cc48d..3651fc9 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: calling a function with argument of type f32 passing data of type i32
+error: Undefined Behavior: calling a function whose parameter #1 has type f32 passing argument of type i32
--> tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC
|
LL | g(42)
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs
index f0ea5cc..053a4a5 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs
@@ -3,5 +3,5 @@ fn f(_: *const [i32]) {}
let g = unsafe { std::mem::transmute::<fn(*const [i32]), fn(*const i32)>(f) };
- g(&42 as *const i32) //~ ERROR: calling a function with argument of type *const [i32] passing data of type *const i32
+ g(&42 as *const i32) //~ ERROR: type *const [i32] passing argument of type *const i32
}
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr
index 2fbb040..88345a0 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: calling a function with argument of type *const [i32] passing data of type *const i32
+error: Undefined Behavior: calling a function whose parameter #1 has type *const [i32] passing argument of type *const i32
--> tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC
|
LL | g(&42 as *const i32)
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs
index c590048..f3dffcc 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs
@@ -12,5 +12,5 @@ fn main() {
let fnptr: fn(S2) = callee;
let fnptr: fn(S1) = unsafe { std::mem::transmute(fnptr) };
fnptr(S1(NonZero::new(1).unwrap()));
- //~^ ERROR: calling a function with argument of type S2 passing data of type S1
+ //~^ ERROR: type S2 passing argument of type S1
}
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr
index 2c1ac0e..4765839 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: calling a function with argument of type S2 passing data of type S1
+error: Undefined Behavior: calling a function whose parameter #1 has type S2 passing argument of type S1
--> tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC
|
LL | fnptr(S1(NonZero::new(1).unwrap()));
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs
index 0fdab49..05b645c 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs
@@ -5,5 +5,5 @@ fn f() -> u32 {
let g = unsafe { std::mem::transmute::<fn() -> u32, fn()>(f) };
- g() //~ ERROR: calling a function with return type u32 passing return place of type ()
+ g() //~ ERROR: type u32 passing return place of type ()
}
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs
index 20384f0..ca43c06 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs
@@ -3,5 +3,5 @@ fn f(_: (i32, i32)) {}
let g = unsafe { std::mem::transmute::<fn((i32, i32)), fn(i32)>(f) };
- g(42) //~ ERROR: calling a function with argument of type (i32, i32) passing data of type i32
+ g(42) //~ ERROR: type (i32, i32) passing argument of type i32
}
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr
index e45ad12..2ed9ac2 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: calling a function with argument of type (i32, i32) passing data of type i32
+error: Undefined Behavior: calling a function whose parameter #1 has type (i32, i32) passing argument of type i32
--> tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC
|
LL | g(42)
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs
index 80f357b..dedcaac 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs
@@ -7,5 +7,5 @@ fn f(_: simd::u32x8) {}
// These two vector types have the same size but are still not compatible.
let g = unsafe { std::mem::transmute::<fn(simd::u32x8), fn(simd::u64x4)>(f) };
- g(Default::default()) //~ ERROR: calling a function with argument of type std::simd::Simd<u32, 8> passing data of type std::simd::Simd<u64, 4>
+ g(Default::default()) //~ ERROR: type std::simd::Simd<u32, 8> passing argument of type std::simd::Simd<u64, 4>
}
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr
index bad2495..b13e8d9 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: calling a function with argument of type std::simd::Simd<u32, 8> passing data of type std::simd::Simd<u64, 4>
+error: Undefined Behavior: calling a function whose parameter #1 has type std::simd::Simd<u32, 8> passing argument of type std::simd::Simd<u64, 4>
--> tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC
|
LL | g(Default::default())
diff --git a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs
new file mode 100644
index 0000000..1e10f68
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs
@@ -0,0 +1,39 @@
+unsafe extern "C" fn ctor() -> i32 {
+ //~^ERROR: calling a function with return type i32 passing return place of type ()
+ 0
+}
+
+#[rustfmt::skip]
+macro_rules! ctor {
+ ($ident:ident = $ctor:ident) => {
+ #[cfg_attr(
+ all(any(
+ target_os = "linux",
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "haiku",
+ target_os = "illumos",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "solaris",
+ target_os = "none",
+ target_family = "wasm",
+ )),
+ link_section = ".init_array"
+ )]
+ #[cfg_attr(windows, link_section = ".CRT$XCU")]
+ #[cfg_attr(
+ any(target_os = "macos", target_os = "ios"),
+ // We do not set the `mod_init_funcs` flag here since ctor/inventory also do not do
+ // that. See <https://github.com/rust-lang/miri/pull/4459#discussion_r2200115629>.
+ link_section = "__DATA,__mod_init_func"
+ )]
+ #[used]
+ static $ident: unsafe extern "C" fn() -> i32 = $ctor;
+ };
+}
+
+ctor! { CTOR = ctor }
+
+fn main() {}
diff --git a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr
new file mode 100644
index 0000000..664bfbd
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr
@@ -0,0 +1,12 @@
+error: Undefined Behavior: calling a function with return type i32 passing return place of type ()
+ |
+ = note: Undefined Behavior occurred here
+ = note: (no span available)
+ = 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
+ = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+ = help: if you think this code should be accepted anyway, please report an issue with Miri
+ = note: BACKTRACE:
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/shims/input_arg_mismatch.rs b/src/tools/miri/tests/fail/shims/input_arg_mismatch.rs
index eb8de04..7769977 100644
--- a/src/tools/miri/tests/fail/shims/input_arg_mismatch.rs
+++ b/src/tools/miri/tests/fail/shims/input_arg_mismatch.rs
@@ -16,6 +16,6 @@ fn main() {
} as u32;
let _ = unsafe {
close(fd);
- //~^ ERROR: calling a function with argument of type i32 passing data of type u32
+ //~^ ERROR: type i32 passing argument of type u32
};
}
diff --git a/src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr b/src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr
index ce00b62..ec27fd5 100644
--- a/src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr
+++ b/src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32
+error: Undefined Behavior: calling a function whose parameter #1 has type i32 passing argument of type u32
--> tests/fail/shims/input_arg_mismatch.rs:LL:CC
|
LL | close(fd);
diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs
index 6df132d..36bd1e9 100644
--- a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs
+++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs
@@ -6,7 +6,7 @@ fn main() {
// the error should point to `become g(x)`,
// but tail calls mess up the backtrace it seems like...
f(0);
- //~^ error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32
+ //~^ error: type i32 passing argument of type u32
}
fn f(x: u32) {
diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr
index fbb0d3d..cabea5d 100644
--- a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr
+++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32
+error: Undefined Behavior: calling a function whose parameter #1 has type i32 passing argument of type u32
--> tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC
|
LL | f(0);
diff --git a/src/tools/miri/tests/genmc/pass/test_cxx_build.rs b/src/tools/miri/tests/genmc/pass/test_cxx_build.rs
new file mode 100644
index 0000000..f621bd9
--- /dev/null
+++ b/src/tools/miri/tests/genmc/pass/test_cxx_build.rs
@@ -0,0 +1,8 @@
+//@compile-flags: -Zmiri-genmc
+
+#![no_main]
+
+#[unsafe(no_mangle)]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
+ 0
+}
diff --git a/src/tools/miri/tests/genmc/pass/test_cxx_build.stderr b/src/tools/miri/tests/genmc/pass/test_cxx_build.stderr
new file mode 100644
index 0000000..4b7aa82
--- /dev/null
+++ b/src/tools/miri/tests/genmc/pass/test_cxx_build.stderr
@@ -0,0 +1,5 @@
+warning: borrow tracking has been disabled, it is not (yet) supported in GenMC mode.
+C++: GenMC handle created!
+Miri: GenMC handle creation successful!
+C++: GenMC handle destroyed!
+Miri: Dropping GenMC handle successful!
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
index 54ebfa9..c972064 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
@@ -6,6 +6,9 @@
use std::thread;
use std::thread::spawn;
+#[path = "../../utils/libc.rs"]
+mod libc_utils;
+
// This is a set of testcases for blocking epoll.
fn main() {
@@ -97,7 +100,7 @@ fn test_epoll_block_then_unblock() {
let thread1 = spawn(move || {
thread::yield_now();
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
});
check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 10);
@@ -130,7 +133,7 @@ fn test_notification_after_timeout() {
// Trigger epoll notification after timeout.
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
// Check the result of the notification.
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs
index dc3ab28..7130790 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs
@@ -2,6 +2,9 @@
use std::convert::TryInto;
+#[path = "../../utils/libc.rs"]
+mod libc_utils;
+
fn main() {
test_epoll_socketpair();
test_epoll_socketpair_both_sides();
@@ -64,7 +67,7 @@ fn test_epoll_socketpair() {
// Write to fd[0]
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
// Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP
@@ -85,7 +88,7 @@ fn test_epoll_socketpair() {
// Write some more to fd[0].
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
// This did not change the readiness of fd[1]. And yet, we're seeing the event reported
@@ -153,7 +156,7 @@ fn test_epoll_ctl_del() {
// Write to fd[0]
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
// Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET
@@ -182,7 +185,7 @@ fn test_two_epoll_instance() {
// Write to the socketpair.
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
// Register one side of the socketpair with EPOLLIN | EPOLLOUT | EPOLLET.
@@ -224,7 +227,7 @@ fn test_two_same_fd_in_same_epoll_instance() {
// Write to the socketpair.
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
//Two notification should be received.
@@ -243,7 +246,7 @@ fn test_epoll_eventfd() {
// Write to the eventfd instance.
let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes();
- let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
+ let res = unsafe { libc_utils::write_all(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
assert_eq!(res, 8);
// Create an epoll instance.
@@ -282,7 +285,7 @@ fn test_epoll_socketpair_both_sides() {
// Write to fds[1].
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
//Two notification should be received.
@@ -297,7 +300,8 @@ fn test_epoll_socketpair_both_sides() {
// Read from fds[0].
let mut buf: [u8; 5] = [0; 5];
- let res = unsafe { libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+ let res =
+ unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
assert_eq!(res, 5);
assert_eq!(buf, "abcde".as_bytes());
@@ -325,7 +329,7 @@ fn test_closed_fd() {
// Write to the eventfd instance.
let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes();
- let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
+ let res = unsafe { libc_utils::write_all(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
assert_eq!(res, 8);
// Close the eventfd.
@@ -371,7 +375,8 @@ fn test_not_fully_closed_fd() {
// Write to the eventfd instance to produce notification.
let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes();
- let res = unsafe { libc::write(newfd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
+ let res =
+ unsafe { libc_utils::write_all(newfd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
assert_eq!(res, 8);
// Close the dupped fd.
@@ -391,7 +396,7 @@ fn test_event_overwrite() {
// Write to the eventfd instance.
let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes();
- let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
+ let res = unsafe { libc_utils::write_all(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
assert_eq!(res, 8);
// Create an epoll instance.
@@ -445,7 +450,7 @@ fn test_socketpair_read() {
// Write 5 bytes to fds[1].
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
//Two notification should be received.
@@ -460,7 +465,8 @@ fn test_socketpair_read() {
// Read 3 bytes from fds[0].
let mut buf: [u8; 3] = [0; 3];
- let res = unsafe { libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+ let res =
+ unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
assert_eq!(res, 3);
assert_eq!(buf, "abc".as_bytes());
@@ -478,7 +484,8 @@ fn test_socketpair_read() {
// Read until the buffer is empty.
let mut buf: [u8; 2] = [0; 2];
- let res = unsafe { libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+ let res =
+ unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
assert_eq!(res, 2);
assert_eq!(buf, "de".as_bytes());
@@ -510,8 +517,9 @@ fn test_no_notification_for_unregister_flag() {
// Write to fd[1].
let data = "abcde".as_bytes().as_ptr();
- let res: i32 =
- unsafe { libc::write(fds[1], data as *const libc::c_void, 5).try_into().unwrap() };
+ let res: i32 = unsafe {
+ libc_utils::write_all(fds[1], data as *const libc::c_void, 5).try_into().unwrap()
+ };
assert_eq!(res, 5);
// Check result from epoll_wait. Since we didn't register EPOLLIN flag, the notification won't
@@ -546,7 +554,7 @@ fn test_socketpair_epollerr() {
// Write to fd[0]
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
// Close fds[1].
@@ -717,6 +725,6 @@ fn test_issue_3858() {
// Write to the eventfd instance.
let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes();
- let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
+ let res = unsafe { libc_utils::write_all(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
assert_eq!(res, 8);
}
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
index 0ff48c3..86cf2a0 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
@@ -14,6 +14,9 @@
#[path = "../../utils/mod.rs"]
mod utils;
+#[path = "../../utils/libc.rs"]
+mod libc_utils;
+
fn main() {
test_dup();
test_dup_stdout_stderr();
@@ -74,8 +77,8 @@ fn test_dup_stdout_stderr() {
unsafe {
let new_stdout = libc::fcntl(1, libc::F_DUPFD, 0);
let new_stderr = libc::fcntl(2, libc::F_DUPFD, 0);
- libc::write(new_stdout, bytes.as_ptr() as *const libc::c_void, bytes.len());
- libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len());
+ libc_utils::write_all(new_stdout, bytes.as_ptr() as *const libc::c_void, bytes.len());
+ libc_utils::write_all(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len());
}
}
@@ -92,16 +95,24 @@ fn test_dup() {
let new_fd2 = libc::dup2(fd, 8);
let mut first_buf = [0u8; 4];
- libc::read(fd, first_buf.as_mut_ptr() as *mut libc::c_void, 4);
- assert_eq!(&first_buf, b"dup ");
+ let first_len = libc::read(fd, first_buf.as_mut_ptr() as *mut libc::c_void, 4);
+ assert!(first_len > 0);
+ let first_len = first_len as usize;
+ assert_eq!(first_buf[..first_len], bytes[..first_len]);
+ let remaining_bytes = &bytes[first_len..];
let mut second_buf = [0u8; 4];
- libc::read(new_fd, second_buf.as_mut_ptr() as *mut libc::c_void, 4);
- assert_eq!(&second_buf, b"and ");
+ let second_len = libc::read(new_fd, second_buf.as_mut_ptr() as *mut libc::c_void, 4);
+ assert!(second_len > 0);
+ let second_len = second_len as usize;
+ assert_eq!(second_buf[..second_len], remaining_bytes[..second_len]);
+ let remaining_bytes = &remaining_bytes[second_len..];
let mut third_buf = [0u8; 4];
- libc::read(new_fd2, third_buf.as_mut_ptr() as *mut libc::c_void, 4);
- assert_eq!(&third_buf, b"dup2");
+ let third_len = libc::read(new_fd2, third_buf.as_mut_ptr() as *mut libc::c_void, 4);
+ assert!(third_len > 0);
+ let third_len = third_len as usize;
+ assert_eq!(third_buf[..third_len], remaining_bytes[..third_len]);
}
}
@@ -145,7 +156,7 @@ fn test_ftruncate<T: From<i32>>(
let bytes = b"hello";
let path = utils::prepare("miri_test_libc_fs_ftruncate.txt");
let mut file = File::create(&path).unwrap();
- file.write(bytes).unwrap();
+ file.write_all(bytes).unwrap();
file.sync_all().unwrap();
assert_eq!(file.metadata().unwrap().len(), 5);
@@ -402,10 +413,10 @@ fn test_read_and_uninit() {
unsafe {
let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY);
assert_ne!(fd, -1);
- let mut buf: MaybeUninit<[u8; 2]> = std::mem::MaybeUninit::uninit();
- assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::<std::ffi::c_void>(), 2), 2);
+ let mut buf: MaybeUninit<u8> = std::mem::MaybeUninit::uninit();
+ assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::<std::ffi::c_void>(), 1), 1);
let buf = buf.assume_init();
- assert_eq!(buf, [1, 2]);
+ assert_eq!(buf, 1);
assert_eq!(libc::close(fd), 0);
}
remove_file(&path).unwrap();
@@ -413,14 +424,22 @@ fn test_read_and_uninit() {
{
// We test that if we requested to read 4 bytes, but actually read 3 bytes, then
// 3 bytes (not 4) will be overwritten, and remaining byte will be left as-is.
- let path = utils::prepare_with_content("pass-libc-read-and-uninit-2.txt", &[1u8, 2, 3]);
+ let data = [1u8, 2, 3];
+ let path = utils::prepare_with_content("pass-libc-read-and-uninit-2.txt", &data);
let cpath = CString::new(path.clone().into_os_string().into_encoded_bytes()).unwrap();
unsafe {
let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY);
assert_ne!(fd, -1);
let mut buf = [42u8; 5];
- assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::<std::ffi::c_void>(), 4), 3);
- assert_eq!(buf, [1, 2, 3, 42, 42]);
+ let res = libc::read(fd, buf.as_mut_ptr().cast::<std::ffi::c_void>(), 4);
+ assert!(res > 0 && res < 4);
+ for i in 0..buf.len() {
+ assert_eq!(
+ buf[i],
+ if i < res as usize { data[i] } else { 42 },
+ "wrong result at pos {i}"
+ );
+ }
assert_eq!(libc::close(fd), 0);
}
remove_file(&path).unwrap();
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs
index bc755af..ffbcf63 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs
@@ -2,6 +2,10 @@
// test_race depends on a deterministic schedule.
//@compile-flags: -Zmiri-deterministic-concurrency
use std::thread;
+
+#[path = "../../utils/libc.rs"]
+mod libc_utils;
+
fn main() {
test_pipe();
test_pipe_threaded();
@@ -26,21 +30,29 @@ fn test_pipe() {
// Read size == data available in buffer.
let data = "12345".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
let mut buf3: [u8; 5] = [0; 5];
- let res = unsafe { libc::read(fds[0], buf3.as_mut_ptr().cast(), buf3.len() as libc::size_t) };
+ let res = unsafe {
+ libc_utils::read_all(fds[0], buf3.as_mut_ptr().cast(), buf3.len() as libc::size_t)
+ };
assert_eq!(res, 5);
assert_eq!(buf3, "12345".as_bytes());
// Read size > data available in buffer.
- let data = "123".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 3) };
+ let data = "123".as_bytes();
+ let res = unsafe { libc_utils::write_all(fds[1], data.as_ptr() as *const libc::c_void, 3) };
assert_eq!(res, 3);
let mut buf4: [u8; 5] = [0; 5];
let res = unsafe { libc::read(fds[0], buf4.as_mut_ptr().cast(), buf4.len() as libc::size_t) };
- assert_eq!(res, 3);
- assert_eq!(&buf4[0..3], "123".as_bytes());
+ assert!(res > 0 && res <= 3);
+ let res = res as usize;
+ assert_eq!(buf4[..res], data[..res]);
+ if res < 3 {
+ // Drain the rest from the read end.
+ let res = unsafe { libc_utils::read_all(fds[0], buf4[res..].as_mut_ptr().cast(), 3 - res) };
+ assert!(res > 0);
+ }
}
fn test_pipe_threaded() {
@@ -51,7 +63,7 @@ fn test_pipe_threaded() {
let thread1 = thread::spawn(move || {
let mut buf: [u8; 5] = [0; 5];
let res: i64 = unsafe {
- libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
+ libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
.try_into()
.unwrap()
};
@@ -60,7 +72,7 @@ fn test_pipe_threaded() {
});
thread::yield_now();
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
thread1.join().unwrap();
@@ -68,11 +80,12 @@ fn test_pipe_threaded() {
let thread2 = thread::spawn(move || {
thread::yield_now();
let data = "12345".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
});
let mut buf: [u8; 5] = [0; 5];
- let res = unsafe { libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+ let res =
+ unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
assert_eq!(res, 5);
assert_eq!(buf, "12345".as_bytes());
thread2.join().unwrap();
@@ -90,7 +103,7 @@ fn test_race() {
// write() from the main thread will occur before the read() here
// because preemption is disabled and the main thread yields after write().
let res: i32 = unsafe {
- libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
+ libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
.try_into()
.unwrap()
};
@@ -101,7 +114,7 @@ fn test_race() {
});
unsafe { VAL = 1 };
let data = "a".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 1) };
+ let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 1) };
assert_eq!(res, 1);
thread::yield_now();
thread1.join().unwrap();
@@ -186,11 +199,12 @@ fn test_pipe_fcntl_threaded() {
// the socket is now "non-blocking", the shim needs to deal correctly
// with threads that were blocked before the socket was made non-blocking.
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
});
// The `read` below will block.
- let res = unsafe { libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+ let res =
+ unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
thread1.join().unwrap();
assert_eq!(res, 5);
}
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
index c36f6b1..9c211ff 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
@@ -6,6 +6,10 @@
#![allow(static_mut_refs)]
use std::thread;
+
+#[path = "../../utils/libc.rs"]
+mod libc_utils;
+
fn main() {
test_socketpair();
test_socketpair_threaded();
@@ -22,54 +26,71 @@ fn test_socketpair() {
// Read size == data available in buffer.
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
let mut buf: [u8; 5] = [0; 5];
- let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+ let res =
+ unsafe { libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
assert_eq!(res, 5);
assert_eq!(buf, "abcde".as_bytes());
// Read size > data available in buffer.
- let data = "abc".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
+ let data = "abc".as_bytes();
+ let res = unsafe { libc_utils::write_all(fds[0], data.as_ptr() as *const libc::c_void, 3) };
assert_eq!(res, 3);
let mut buf2: [u8; 5] = [0; 5];
let res = unsafe { libc::read(fds[1], buf2.as_mut_ptr().cast(), buf2.len() as libc::size_t) };
- assert_eq!(res, 3);
- assert_eq!(&buf2[0..3], "abc".as_bytes());
+ assert!(res > 0 && res <= 3);
+ let res = res as usize;
+ assert_eq!(buf2[..res], data[..res]);
+ if res < 3 {
+ // Drain the rest from the read end.
+ let res = unsafe { libc_utils::read_all(fds[1], buf2[res..].as_mut_ptr().cast(), 3 - res) };
+ assert!(res > 0);
+ }
// Test read and write from another direction.
// Read size == data available in buffer.
let data = "12345".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
let mut buf3: [u8; 5] = [0; 5];
- let res = unsafe { libc::read(fds[0], buf3.as_mut_ptr().cast(), buf3.len() as libc::size_t) };
+ let res = unsafe {
+ libc_utils::read_all(fds[0], buf3.as_mut_ptr().cast(), buf3.len() as libc::size_t)
+ };
assert_eq!(res, 5);
assert_eq!(buf3, "12345".as_bytes());
// Read size > data available in buffer.
- let data = "123".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 3) };
+ let data = "123".as_bytes();
+ let res = unsafe { libc_utils::write_all(fds[1], data.as_ptr() as *const libc::c_void, 3) };
assert_eq!(res, 3);
let mut buf4: [u8; 5] = [0; 5];
let res = unsafe { libc::read(fds[0], buf4.as_mut_ptr().cast(), buf4.len() as libc::size_t) };
- assert_eq!(res, 3);
- assert_eq!(&buf4[0..3], "123".as_bytes());
+ assert!(res > 0 && res <= 3);
+ let res = res as usize;
+ assert_eq!(buf4[..res], data[..res]);
+ if res < 3 {
+ // Drain the rest from the read end.
+ let res = unsafe { libc_utils::read_all(fds[0], buf4[res..].as_mut_ptr().cast(), 3 - res) };
+ assert!(res > 0);
+ }
// Test when happens when we close one end, with some data in the buffer.
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
+ let res = unsafe { libc_utils::write_all(fds[0], data.as_ptr() as *const libc::c_void, 3) };
assert_eq!(res, 3);
unsafe { libc::close(fds[0]) };
// Reading the other end should return that data, then EOF.
let mut buf: [u8; 5] = [0; 5];
- let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+ let res =
+ unsafe { libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
assert_eq!(res, 3);
assert_eq!(&buf[0..3], "123".as_bytes());
- let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+ let res =
+ unsafe { libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
assert_eq!(res, 0); // 0-sized read: EOF.
// Writing the other end should emit EPIPE.
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 1) };
+ let res = unsafe { libc_utils::write_all(fds[1], data.as_ptr() as *const libc::c_void, 1) };
assert_eq!(res, -1);
assert_eq!(std::io::Error::last_os_error().raw_os_error(), Some(libc::EPIPE));
}
@@ -82,7 +103,7 @@ fn test_socketpair_threaded() {
let thread1 = thread::spawn(move || {
let mut buf: [u8; 5] = [0; 5];
let res: i64 = unsafe {
- libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
+ libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
.try_into()
.unwrap()
};
@@ -91,7 +112,7 @@ fn test_socketpair_threaded() {
});
thread::yield_now();
let data = "abcde".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
thread1.join().unwrap();
@@ -99,11 +120,12 @@ fn test_socketpair_threaded() {
let thread2 = thread::spawn(move || {
thread::yield_now();
let data = "12345".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
+ let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
});
let mut buf: [u8; 5] = [0; 5];
- let res = unsafe { libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+ let res =
+ unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
assert_eq!(res, 5);
assert_eq!(buf, "12345".as_bytes());
thread2.join().unwrap();
@@ -119,7 +141,7 @@ fn test_race() {
// write() from the main thread will occur before the read() here
// because preemption is disabled and the main thread yields after write().
let res: i32 = unsafe {
- libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
+ libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
.try_into()
.unwrap()
};
@@ -130,7 +152,7 @@ fn test_race() {
});
unsafe { VAL = 1 };
let data = "a".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 1) };
+ let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 1) };
assert_eq!(res, 1);
thread::yield_now();
thread1.join().unwrap();
@@ -144,14 +166,16 @@ fn test_blocking_read() {
let thread1 = thread::spawn(move || {
// Let this thread block on read.
let mut buf: [u8; 3] = [0; 3];
- let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+ let res = unsafe {
+ libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
+ };
assert_eq!(res, 3);
assert_eq!(&buf, "abc".as_bytes());
});
let thread2 = thread::spawn(move || {
// Unblock thread1 by doing writing something.
let data = "abc".as_bytes().as_ptr();
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
+ let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 3) };
assert_eq!(res, 3);
});
thread1.join().unwrap();
@@ -165,18 +189,21 @@ fn test_blocking_write() {
assert_eq!(res, 0);
let arr1: [u8; 212992] = [1; 212992];
// Exhaust the space in the buffer so the subsequent write will block.
- let res = unsafe { libc::write(fds[0], arr1.as_ptr() as *const libc::c_void, 212992) };
+ let res =
+ unsafe { libc_utils::write_all(fds[0], arr1.as_ptr() as *const libc::c_void, 212992) };
assert_eq!(res, 212992);
let thread1 = thread::spawn(move || {
let data = "abc".as_bytes().as_ptr();
// The write below will be blocked because the buffer is already full.
- let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
+ let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 3) };
assert_eq!(res, 3);
});
let thread2 = thread::spawn(move || {
// Unblock thread1 by freeing up some space.
let mut buf: [u8; 3] = [0; 3];
- let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+ let res = unsafe {
+ libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
+ };
assert_eq!(res, 3);
assert_eq!(buf, [1, 1, 1]);
});
diff --git a/src/tools/miri/tests/pass/shims/ctor.rs b/src/tools/miri/tests/pass/shims/ctor.rs
index b997d23..a0fcdb1 100644
--- a/src/tools/miri/tests/pass/shims/ctor.rs
+++ b/src/tools/miri/tests/pass/shims/ctor.rs
@@ -2,13 +2,13 @@
static COUNT: AtomicUsize = AtomicUsize::new(0);
-unsafe extern "C" fn ctor() {
- COUNT.fetch_add(1, Ordering::Relaxed);
+unsafe extern "C" fn ctor<const N: usize>() {
+ COUNT.fetch_add(N, Ordering::Relaxed);
}
#[rustfmt::skip]
macro_rules! ctor {
- ($ident:ident = $ctor:ident) => {
+ ($ident:ident: $ty:ty = $ctor:expr) => {
#[cfg_attr(
all(any(
target_os = "linux",
@@ -33,14 +33,13 @@ macro_rules! ctor {
link_section = "__DATA,__mod_init_func"
)]
#[used]
- static $ident: unsafe extern "C" fn() = $ctor;
+ static $ident: $ty = $ctor;
};
}
-ctor! { CTOR1 = ctor }
-ctor! { CTOR2 = ctor }
-ctor! { CTOR3 = ctor }
+ctor! { CTOR1: unsafe extern "C" fn() = ctor::<1> }
+ctor! { CTOR2: [unsafe extern "C" fn(); 2] = [ctor::<2>, ctor::<3>] }
fn main() {
- assert_eq!(COUNT.load(Ordering::Relaxed), 3, "ctors did not run");
+ assert_eq!(COUNT.load(Ordering::Relaxed), 6, "ctors did not run");
}
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index 9d57257..e7f11c5 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -17,6 +17,10 @@
fn main() {
test_path_conversion();
test_file();
+ // Partial reads/writes are apparently not a thing on Windows.
+ if cfg!(not(windows)) {
+ test_file_partial_reads_writes();
+ }
test_file_create_new();
test_metadata();
test_seek();
@@ -53,7 +57,7 @@ fn test_file() {
file.write(&mut []).unwrap();
assert_eq!(file.metadata().unwrap().len(), 0);
- file.write(bytes).unwrap();
+ file.write_all(bytes).unwrap();
assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
// Test opening, reading and closing a file.
let mut file = File::open(&path).unwrap();
@@ -66,10 +70,36 @@ fn test_file() {
assert!(!file.is_terminal());
+ // Writing to a file opened for reading should error (and not stop interpretation). std does not
+ // categorize the error so we don't check for details.
+ file.write(&[]).unwrap_err();
+
// Removing file should succeed.
remove_file(&path).unwrap();
}
+fn test_file_partial_reads_writes() {
+ let path = utils::prepare_with_content("miri_test_fs_file.txt", b"abcdefg");
+
+ // Ensure we sometimes do incomplete writes.
+ let got_short_write = (0..16).any(|_| {
+ let _ = remove_file(&path); // FIXME(win, issue #4483): errors if the file already exists
+ let mut file = File::create(&path).unwrap();
+ file.write(&[0; 4]).unwrap() != 4
+ });
+ assert!(got_short_write);
+ // Ensure we sometimes do incomplete reads.
+ let got_short_read = (0..16).any(|_| {
+ let mut file = File::open(&path).unwrap();
+ let mut buf = [0; 4];
+ file.read(&mut buf).unwrap() != 4
+ });
+ assert!(got_short_read);
+
+ // Clean up
+ remove_file(&path).unwrap();
+}
+
fn test_file_clone() {
let bytes = b"Hello, World!\n";
let path = utils::prepare_with_content("miri_test_fs_file_clone.txt", bytes);
diff --git a/src/tools/miri/tests/pass/shims/pipe.rs b/src/tools/miri/tests/pass/shims/pipe.rs
index c47feb8..4915e54 100644
--- a/src/tools/miri/tests/pass/shims/pipe.rs
+++ b/src/tools/miri/tests/pass/shims/pipe.rs
@@ -4,8 +4,8 @@
fn main() {
let (mut ping_rx, mut ping_tx) = pipe().unwrap();
- ping_tx.write(b"hello").unwrap();
+ ping_tx.write_all(b"hello").unwrap();
let mut buf: [u8; 5] = [0; 5];
- ping_rx.read(&mut buf).unwrap();
+ ping_rx.read_exact(&mut buf).unwrap();
assert_eq!(&buf, "hello".as_bytes());
}
diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs
index cb915b1..73fbe2c 100644
--- a/src/tools/miri/tests/ui.rs
+++ b/src/tools/miri/tests/ui.rs
@@ -338,6 +338,20 @@ fn main() -> Result<()> {
ui(Mode::Fail, "tests/native-lib/fail", &target, WithoutDependencies, tmpdir.path())?;
}
+ // We only enable GenMC tests when the `genmc` feature is enabled, but also only on platforms we support:
+ // FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed.
+ // FIXME(genmc,cross-platform): remove `host == target` check once cross-platform support with GenMC is possible.
+ if cfg!(all(
+ feature = "genmc",
+ target_os = "linux",
+ target_pointer_width = "64",
+ target_endian = "little"
+ )) && host == target
+ {
+ ui(Mode::Pass, "tests/genmc/pass", &target, WithDependencies, tmpdir.path())?;
+ ui(Mode::Fail, "tests/genmc/fail", &target, WithDependencies, tmpdir.path())?;
+ }
+
Ok(())
}
diff --git a/src/tools/miri/tests/utils/fs.rs b/src/tools/miri/tests/utils/fs.rs
index 7340908..7d75b3f 100644
--- a/src/tools/miri/tests/utils/fs.rs
+++ b/src/tools/miri/tests/utils/fs.rs
@@ -1,6 +1,6 @@
use std::ffi::OsString;
-use std::fs;
use std::path::PathBuf;
+use std::{fs, io};
use super::miri_extern;
diff --git a/src/tools/miri/tests/utils/libc.rs b/src/tools/miri/tests/utils/libc.rs
new file mode 100644
index 0000000..1a3cd06
--- /dev/null
+++ b/src/tools/miri/tests/utils/libc.rs
@@ -0,0 +1,44 @@
+//! Utils that need libc.
+#![allow(dead_code)]
+
+pub unsafe fn read_all(
+ fd: libc::c_int,
+ buf: *mut libc::c_void,
+ count: libc::size_t,
+) -> libc::ssize_t {
+ assert!(count > 0);
+ let mut read_so_far = 0;
+ while read_so_far < count {
+ let res = libc::read(fd, buf.add(read_so_far), count - read_so_far);
+ if res < 0 {
+ return res;
+ }
+ if res == 0 {
+ // EOF
+ break;
+ }
+ read_so_far += res as libc::size_t;
+ }
+ return read_so_far as libc::ssize_t;
+}
+
+pub unsafe fn write_all(
+ fd: libc::c_int,
+ buf: *const libc::c_void,
+ count: libc::size_t,
+) -> libc::ssize_t {
+ assert!(count > 0);
+ let mut written_so_far = 0;
+ while written_so_far < count {
+ let res = libc::write(fd, buf.add(written_so_far), count - written_so_far);
+ if res < 0 {
+ return res;
+ }
+ if res == 0 {
+ // EOF?
+ break;
+ }
+ written_so_far += res as libc::size_t;
+ }
+ return written_so_far as libc::ssize_t;
+}
diff --git a/src/tools/miri/tests/x86_64-unknown-kernel.json b/src/tools/miri/tests/x86_64-unknown-kernel.json
index 8da67d3..a5eaceb 100644
--- a/src/tools/miri/tests/x86_64-unknown-kernel.json
+++ b/src/tools/miri/tests/x86_64-unknown-kernel.json
@@ -2,7 +2,7 @@
"llvm-target": "x86_64-unknown-none",
"target-endian": "little",
"target-pointer-width": "64",
- "target-c-int-width": "32",
+ "target-c-int-width": 32,
"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",
"arch": "x86_64",
"os": "none",
diff --git a/src/tools/miropt-test-tools/Cargo.toml b/src/tools/miropt-test-tools/Cargo.toml
index 09b4c7d..3eb5020 100644
--- a/src/tools/miropt-test-tools/Cargo.toml
+++ b/src/tools/miropt-test-tools/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "miropt-test-tools"
version = "0.1.0"
-edition = "2021"
+edition = "2024"
[dependencies]
diff --git a/src/tools/miropt-test-tools/src/lib.rs b/src/tools/miropt-test-tools/src/lib.rs
index 41b53d2..10769c9 100644
--- a/src/tools/miropt-test-tools/src/lib.rs
+++ b/src/tools/miropt-test-tools/src/lib.rs
@@ -34,7 +34,7 @@ fn output_file_suffix(testfile: &Path, bit_width: u32, panic_strategy: PanicStra
let mut suffix = String::new();
if each_bit_width {
- suffix.push_str(&format!(".{}bit", bit_width));
+ suffix.push_str(&format!(".{bit_width}bit"));
}
if each_panic_strategy {
match panic_strategy {
@@ -51,7 +51,7 @@ pub fn files_for_miropt_test(
panic_strategy: PanicStrategy,
) -> MiroptTest {
let mut out = Vec::new();
- let test_file_contents = fs::read_to_string(&testfile).unwrap();
+ let test_file_contents = fs::read_to_string(testfile).unwrap();
let test_dir = testfile.parent().unwrap();
let test_crate = testfile.file_stem().unwrap().to_str().unwrap().replace('-', "_");
@@ -76,10 +76,10 @@ pub fn files_for_miropt_test(
if test_name.ends_with(".diff") {
let trimmed = test_name.trim_end_matches(".diff");
- passes.push(trimmed.split('.').last().unwrap().to_owned());
- let test_against = format!("{}.after.mir", trimmed);
- from_file = format!("{}.before.mir", trimmed);
- expected_file = format!("{}{}.diff", trimmed, suffix);
+ passes.push(trimmed.split('.').next_back().unwrap().to_owned());
+ let test_against = format!("{trimmed}.after.mir");
+ from_file = format!("{trimmed}.before.mir");
+ expected_file = format!("{trimmed}{suffix}.diff");
assert!(test_names.next().is_none(), "two mir pass names specified for MIR diff");
to_file = Some(test_against);
} else if let Some(first_pass) = test_names.next() {
@@ -92,10 +92,9 @@ pub fn files_for_miropt_test(
}
assert!(test_names.next().is_none(), "three mir pass names specified for MIR diff");
- expected_file =
- format!("{}{}.{}-{}.diff", test_name, suffix, first_pass, second_pass);
- let second_file = format!("{}.{}.mir", test_name, second_pass);
- from_file = format!("{}.{}.mir", test_name, first_pass);
+ expected_file = format!("{test_name}{suffix}.{first_pass}-{second_pass}.diff");
+ let second_file = format!("{test_name}.{second_pass}.mir");
+ from_file = format!("{test_name}.{first_pass}.mir");
to_file = Some(second_file);
} else {
// Allow-list for file extensions that can be produced by MIR dumps.
@@ -112,7 +111,7 @@ pub fn files_for_miropt_test(
)
}
- expected_file = format!("{}{}.{}", test_name_wo_ext, suffix, test_name_ext);
+ expected_file = format!("{test_name_wo_ext}{suffix}.{test_name_ext}");
from_file = test_name.to_string();
assert!(test_names.next().is_none(), "two mir pass names specified for MIR dump");
to_file = None;
@@ -123,7 +122,7 @@ pub fn files_for_miropt_test(
);
};
if !expected_file.starts_with(&test_crate) {
- expected_file = format!("{}.{}", test_crate, expected_file);
+ expected_file = format!("{test_crate}.{expected_file}");
}
let expected_file = test_dir.join(expected_file);
diff --git a/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml b/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml
new file mode 100644
index 0000000..2a842f3
--- /dev/null
+++ b/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml
@@ -0,0 +1,20 @@
+name: rustc-pull
+
+on:
+ workflow_dispatch:
+ schedule:
+ # Run at 04:00 UTC every Monday and Thursday
+ - cron: '0 4 * * 1,4'
+
+jobs:
+ pull:
+ if: github.repository == 'rust-lang/rust-analyzer'
+ uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@main
+ with:
+ zulip-stream-id: 185405
+ zulip-bot-email: "rust-analyzer-ci-bot@rust-lang.zulipchat.com"
+ pr-base-branch: master
+ branch-name: rustc-pull
+ secrets:
+ zulip-api-token: ${{ secrets.ZULIP_API_TOKEN }}
+ token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index c471234..7d03300 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -396,15 +396,6 @@
]
[[package]]
-name = "directories"
-version = "6.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
-dependencies = [
- "dirs-sys",
-]
-
-[[package]]
name = "dirs"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1268,7 +1259,7 @@
"expect-test",
"intern",
"parser",
- "ra-ap-rustc_lexer 0.122.0",
+ "ra-ap-rustc_lexer 0.123.0",
"rustc-hash 2.1.1",
"smallvec",
"span",
@@ -1504,7 +1495,7 @@
"drop_bomb",
"edition",
"expect-test",
- "ra-ap-rustc_lexer 0.122.0",
+ "ra-ap-rustc_lexer 0.123.0",
"rustc-literal-escaper",
"stdx",
"tracing",
@@ -1614,7 +1605,7 @@
"object",
"paths",
"proc-macro-test",
- "ra-ap-rustc_lexer 0.122.0",
+ "ra-ap-rustc_lexer 0.123.0",
"span",
"syntax-bridge",
"tt",
@@ -1688,6 +1679,7 @@
"serde_json",
"span",
"stdx",
+ "temp-dir",
"toolchain",
"tracing",
"triomphe",
@@ -1756,9 +1748,9 @@
[[package]]
name = "ra-ap-rustc_abi"
-version = "0.122.0"
+version = "0.123.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb01e1fec578003c85481c1cad4ff8cd8195b07c2dc85ae3f716108507ae15d5"
+checksum = "f18c877575c259d127072e9bfc41d985202262fb4d6bfdae3d1252147c2562c2"
dependencies = [
"bitflags 2.9.1",
"ra-ap-rustc_hashes",
@@ -1768,18 +1760,18 @@
[[package]]
name = "ra-ap-rustc_hashes"
-version = "0.122.0"
+version = "0.123.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0ec056e72a472ffef8761ce96ece6c626eb07368c09d0105b6df30d27d07673"
+checksum = "2439ed1df3472443133b66949f81080dff88089b42f825761455463709ee1cad"
dependencies = [
"rustc-stable-hash",
]
[[package]]
name = "ra-ap-rustc_index"
-version = "0.122.0"
+version = "0.123.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fcdd1001db0295e59052e9f53aeda588bbe81e362534f4687d41bd44777b5a7"
+checksum = "57a24fe0be21be1f8ebc21dcb40129214fb4cefb0f2753f3d46b6dbe656a1a45"
dependencies = [
"ra-ap-rustc_index_macros",
"smallvec",
@@ -1787,9 +1779,9 @@
[[package]]
name = "ra-ap-rustc_index_macros"
-version = "0.122.0"
+version = "0.123.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "728d64dd98e25530b32e3f7c7c1e844e52722b269360daa1cdeba9dff9727a26"
+checksum = "844a27ddcad0116facae2df8e741fd788662cf93dc13029cd864f2b8013b81f9"
dependencies = [
"proc-macro2",
"quote",
@@ -1809,9 +1801,9 @@
[[package]]
name = "ra-ap-rustc_lexer"
-version = "0.122.0"
+version = "0.123.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "415f0821f512608d825b3215489a6a6a2c18ed9f0045953d514e7ec23d4b90ab"
+checksum = "2b734cfcb577d09877799a22742f1bd398be6c00bc428d9de56d48d11ece5771"
dependencies = [
"memchr",
"unicode-properties",
@@ -1830,9 +1822,9 @@
[[package]]
name = "ra-ap-rustc_pattern_analysis"
-version = "0.122.0"
+version = "0.123.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4657fcfdfe06e2a02ec8180d4e7c95aecf4811ba50367e363d1a2300b7623284"
+checksum = "75b0ee1f059b9dea0818c6c7267478926eee95ba4c7dcf89c8db32fa165d3904"
dependencies = [
"ra-ap-rustc_index",
"rustc-hash 2.1.1",
@@ -2294,6 +2286,12 @@
]
[[package]]
+name = "temp-dir"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83176759e9416cf81ee66cb6508dbfe9c96f20b8b56265a39917551c23c70964"
+
+[[package]]
name = "tenthash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2592,7 +2590,7 @@
dependencies = [
"arrayvec",
"intern",
- "ra-ap-rustc_lexer 0.122.0",
+ "ra-ap-rustc_lexer 0.123.0",
"stdx",
"text-size",
]
@@ -3105,7 +3103,6 @@
version = "0.1.0"
dependencies = [
"anyhow",
- "directories",
"edition",
"either",
"flate2",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 700c116..e7cf021 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -89,11 +89,11 @@
vfs = { path = "./crates/vfs", version = "0.0.0" }
edition = { path = "./crates/edition", version = "0.0.0" }
-ra-ap-rustc_lexer = { version = "0.122", default-features = false }
+ra-ap-rustc_lexer = { version = "0.123", default-features = false }
ra-ap-rustc_parse_format = { version = "0.121", default-features = false }
-ra-ap-rustc_index = { version = "0.122", default-features = false }
-ra-ap-rustc_abi = { version = "0.122", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.122", default-features = false }
+ra-ap-rustc_index = { version = "0.123", default-features = false }
+ra-ap-rustc_abi = { version = "0.123", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.123", default-features = false }
# local crates that aren't published to crates.io. These should not have versions.
@@ -156,6 +156,7 @@
"const_generics",
] }
smol_str = "0.3.2"
+temp-dir = "0.1.16"
text-size = "1.1.1"
tracing = "0.1.41"
tracing-tree = "0.4.0"
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 8c9393b..0bf4fbd 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -30,6 +30,7 @@
pub enum ProcMacroLoadingError {
Disabled,
FailedToBuild,
+ ExpectedProcMacroArtifact,
MissingDylibPath,
NotYetBuilt,
NoProcMacros,
@@ -39,7 +40,8 @@ impl ProcMacroLoadingError {
pub fn is_hard_error(&self) -> bool {
match self {
ProcMacroLoadingError::Disabled | ProcMacroLoadingError::NotYetBuilt => false,
- ProcMacroLoadingError::FailedToBuild
+ ProcMacroLoadingError::ExpectedProcMacroArtifact
+ | ProcMacroLoadingError::FailedToBuild
| ProcMacroLoadingError::MissingDylibPath
| ProcMacroLoadingError::NoProcMacros
| ProcMacroLoadingError::ProcMacroSrvError(_) => true,
@@ -51,10 +53,16 @@ impl Error for ProcMacroLoadingError {}
impl fmt::Display for ProcMacroLoadingError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
+ ProcMacroLoadingError::ExpectedProcMacroArtifact => {
+ write!(f, "proc-macro crate did not build proc-macro artifact")
+ }
ProcMacroLoadingError::Disabled => write!(f, "proc-macro expansion is disabled"),
ProcMacroLoadingError::FailedToBuild => write!(f, "proc-macro failed to build"),
ProcMacroLoadingError::MissingDylibPath => {
- write!(f, "proc-macro crate build data is missing a dylib path")
+ write!(
+ f,
+ "proc-macro crate built but the dylib path is missing, this indicates a problem with your build system."
+ )
}
ProcMacroLoadingError::NotYetBuilt => write!(f, "proc-macro not yet built"),
ProcMacroLoadingError::NoProcMacros => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
index d3dfc05..5695ab7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
@@ -16,7 +16,7 @@
use cfg::{CfgExpr, CfgOptions};
use either::Either;
-use hir_expand::{ExpandError, InFile, MacroCallId, mod_path::ModPath, name::Name};
+use hir_expand::{InFile, MacroCallId, mod_path::ModPath, name::Name};
use la_arena::{Arena, ArenaMap};
use rustc_hash::FxHashMap;
use smallvec::SmallVec;
@@ -281,7 +281,6 @@ struct FormatTemplate {
#[derive(Debug, Eq, PartialEq)]
pub enum ExpressionStoreDiagnostics {
InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions },
- MacroError { node: InFile<MacroCallPtr>, err: ExpandError },
UnresolvedMacroCall { node: InFile<MacroCallPtr>, path: ModPath },
UnreachableLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name },
AwaitOutsideOfAsync { node: InFile<AstPtr<ast::AwaitExpr>>, location: String },
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
index 4e87774..abd1382 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
@@ -960,37 +960,28 @@ fn lower_type_bound(
impl_trait_lower_fn: ImplTraitLowerFn<'_>,
) -> TypeBound {
match node.kind() {
- ast::TypeBoundKind::PathType(path_type) => {
- let m = match node.question_mark_token() {
- Some(_) => TraitBoundModifier::Maybe,
- None => TraitBoundModifier::None,
- };
- self.lower_path_type(&path_type, impl_trait_lower_fn)
- .map(|p| {
- TypeBound::Path(self.alloc_path(p, AstPtr::new(&path_type).upcast()), m)
- })
- .unwrap_or(TypeBound::Error)
- }
- ast::TypeBoundKind::ForType(for_type) => {
- let lt_refs = match for_type.generic_param_list() {
+ ast::TypeBoundKind::PathType(binder, path_type) => {
+ let binder = match binder.and_then(|it| it.generic_param_list()) {
Some(gpl) => gpl
.lifetime_params()
.flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(<.text())))
.collect(),
None => ThinVec::default(),
};
- let path = for_type.ty().and_then(|ty| match &ty {
- ast::Type::PathType(path_type) => {
- self.lower_path_type(path_type, impl_trait_lower_fn).map(|p| (p, ty))
- }
- _ => None,
- });
- match path {
- Some((p, ty)) => {
- TypeBound::ForLifetime(lt_refs, self.alloc_path(p, AstPtr::new(&ty)))
- }
- None => TypeBound::Error,
- }
+ let m = match node.question_mark_token() {
+ Some(_) => TraitBoundModifier::Maybe,
+ None => TraitBoundModifier::None,
+ };
+ self.lower_path_type(&path_type, impl_trait_lower_fn)
+ .map(|p| {
+ let path = self.alloc_path(p, AstPtr::new(&path_type).upcast());
+ if binder.is_empty() {
+ TypeBound::Path(path, m)
+ } else {
+ TypeBound::ForLifetime(binder, path)
+ }
+ })
+ .unwrap_or(TypeBound::Error)
}
ast::TypeBoundKind::Use(gal) => TypeBound::Use(
gal.use_bound_generic_args()
@@ -1981,13 +1972,7 @@ fn collect_macro_call<T, U>(
return collector(self, None);
}
};
- if record_diagnostics {
- if let Some(err) = res.err {
- self.store
- .diagnostics
- .push(ExpressionStoreDiagnostics::MacroError { node: macro_call_ptr, err });
- }
- }
+ // No need to push macro and parsing errors as they'll be recreated from `macro_calls()`.
match res.value {
Some((mark, expansion)) => {
@@ -1997,10 +1982,6 @@ fn collect_macro_call<T, U>(
self.store.expansions.insert(macro_call_ptr, macro_file);
}
- if record_diagnostics {
- // FIXME: Report parse errors here
- }
-
let id = collector(self, expansion.map(|it| it.tree()));
self.expander.exit(mark);
id
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs
index 02a1d27..c570df4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs
@@ -180,17 +180,18 @@ fn lower_where_predicates(
continue;
};
- let lifetimes: Option<Box<_>> = pred.generic_param_list().map(|param_list| {
- // Higher-Ranked Trait Bounds
- param_list
- .lifetime_params()
- .map(|lifetime_param| {
- lifetime_param
- .lifetime()
- .map_or_else(Name::missing, |lt| Name::new_lifetime(<.text()))
- })
- .collect()
- });
+ let lifetimes: Option<Box<_>> =
+ pred.for_binder().and_then(|it| it.generic_param_list()).map(|param_list| {
+ // Higher-Ranked Trait Bounds
+ param_list
+ .lifetime_params()
+ .map(|lifetime_param| {
+ lifetime_param
+ .lifetime()
+ .map_or_else(Name::missing, |lt| Name::new_lifetime(<.text()))
+ })
+ .collect()
+ });
for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
self.lower_type_bound_as_predicate(ec, bound, lifetimes.as_deref(), target);
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/path.rs
index 19c7ce0..55e738b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/path.rs
@@ -27,7 +27,7 @@ pub enum Path {
}
// This type is being used a lot, make sure it doesn't grow unintentionally.
-#[cfg(target_arch = "x86_64")]
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
const _: () = {
assert!(size_of::<Path>() == 24);
assert!(size_of::<Option<Path>>() == 24);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
index eacc3f3..da0f058 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
@@ -148,7 +148,7 @@ pub enum TypeRef {
Error,
}
-#[cfg(target_arch = "x86_64")]
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
const _: () = assert!(size_of::<TypeRef>() == 24);
pub type TypeRefId = Idx<TypeRef>;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index 5ae6bf6..cc531f0 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -175,8 +175,9 @@ fn validate_call(
});
}
- let receiver_ty = self.infer[*receiver].clone();
- checker.prev_receiver_ty = Some(receiver_ty);
+ if let Some(receiver_ty) = self.infer.type_of_expr_with_adjust(*receiver) {
+ checker.prev_receiver_ty = Some(receiver_ty.clone());
+ }
}
}
@@ -187,7 +188,9 @@ fn validate_match(
arms: &[MatchArm],
db: &dyn HirDatabase,
) {
- let scrut_ty = &self.infer[scrutinee_expr];
+ let Some(scrut_ty) = self.infer.type_of_expr_with_adjust(scrutinee_expr) else {
+ return;
+ };
if scrut_ty.contains_unknown() {
return;
}
@@ -200,7 +203,7 @@ fn validate_match(
// Note: Skipping the entire diagnostic rather than just not including a faulty match arm is
// preferred to avoid the chance of false positives.
for arm in arms {
- let Some(pat_ty) = self.infer.type_of_pat.get(arm.pat) else {
+ let Some(pat_ty) = self.infer.type_of_pat_with_adjust(arm.pat) else {
return;
};
if pat_ty.contains_unknown() {
@@ -328,7 +331,7 @@ fn validate_block(&mut self, db: &dyn HirDatabase, expr: &Expr) {
continue;
}
let Some(initializer) = initializer else { continue };
- let ty = &self.infer[initializer];
+ let Some(ty) = self.infer.type_of_expr_with_adjust(initializer) else { continue };
if ty.contains_unknown() {
continue;
}
@@ -433,44 +436,44 @@ fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr, db: &dyn HirDa
Statement::Expr { expr, .. } => Some(*expr),
_ => None,
});
- if let Some(last_then_expr) = last_then_expr {
- let last_then_expr_ty = &self.infer[last_then_expr];
- if last_then_expr_ty.is_never() {
- // Only look at sources if the then branch diverges and we have an else branch.
- let source_map = db.body_with_source_map(self.owner).1;
- let Ok(source_ptr) = source_map.expr_syntax(id) else {
- return;
- };
- let root = source_ptr.file_syntax(db);
- let either::Left(ast::Expr::IfExpr(if_expr)) =
- source_ptr.value.to_node(&root)
- else {
- return;
- };
- let mut top_if_expr = if_expr;
- loop {
- let parent = top_if_expr.syntax().parent();
- let has_parent_expr_stmt_or_stmt_list =
- parent.as_ref().is_some_and(|node| {
- ast::ExprStmt::can_cast(node.kind())
- | ast::StmtList::can_cast(node.kind())
- });
- if has_parent_expr_stmt_or_stmt_list {
- // Only emit diagnostic if parent or direct ancestor is either
- // an expr stmt or a stmt list.
- break;
- }
- let Some(parent_if_expr) = parent.and_then(ast::IfExpr::cast) else {
- // Bail if parent is neither an if expr, an expr stmt nor a stmt list.
- return;
- };
- // Check parent if expr.
- top_if_expr = parent_if_expr;
+ if let Some(last_then_expr) = last_then_expr
+ && let Some(last_then_expr_ty) =
+ self.infer.type_of_expr_with_adjust(last_then_expr)
+ && last_then_expr_ty.is_never()
+ {
+ // Only look at sources if the then branch diverges and we have an else branch.
+ let source_map = db.body_with_source_map(self.owner).1;
+ let Ok(source_ptr) = source_map.expr_syntax(id) else {
+ return;
+ };
+ let root = source_ptr.file_syntax(db);
+ let either::Left(ast::Expr::IfExpr(if_expr)) = source_ptr.value.to_node(&root)
+ else {
+ return;
+ };
+ let mut top_if_expr = if_expr;
+ loop {
+ let parent = top_if_expr.syntax().parent();
+ let has_parent_expr_stmt_or_stmt_list =
+ parent.as_ref().is_some_and(|node| {
+ ast::ExprStmt::can_cast(node.kind())
+ | ast::StmtList::can_cast(node.kind())
+ });
+ if has_parent_expr_stmt_or_stmt_list {
+ // Only emit diagnostic if parent or direct ancestor is either
+ // an expr stmt or a stmt list.
+ break;
}
-
- self.diagnostics
- .push(BodyValidationDiagnostic::RemoveUnnecessaryElse { if_expr: id })
+ let Some(parent_if_expr) = parent.and_then(ast::IfExpr::cast) else {
+ // Bail if parent is neither an if expr, an expr stmt nor a stmt list.
+ return;
+ };
+ // Check parent if expr.
+ top_if_expr = parent_if_expr;
}
+
+ self.diagnostics
+ .push(BodyValidationDiagnostic::RemoveUnnecessaryElse { if_expr: id })
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index e880438..7c39afa 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -561,6 +561,32 @@ pub fn type_of_expr_or_pat(&self, id: ExprOrPatId) -> Option<&Ty> {
ExprOrPatId::PatId(id) => self.type_of_pat.get(id),
}
}
+ pub fn type_of_expr_with_adjust(&self, id: ExprId) -> Option<&Ty> {
+ match self.expr_adjustments.get(&id).and_then(|adjustments| {
+ adjustments
+ .iter()
+ .filter(|adj| {
+ // https://github.com/rust-lang/rust/blob/67819923ac8ea353aaa775303f4c3aacbf41d010/compiler/rustc_mir_build/src/thir/cx/expr.rs#L140
+ !matches!(
+ adj,
+ Adjustment {
+ kind: Adjust::NeverToAny,
+ target,
+ } if target.is_never()
+ )
+ })
+ .next_back()
+ }) {
+ Some(adjustment) => Some(&adjustment.target),
+ None => self.type_of_expr.get(id),
+ }
+ }
+ pub fn type_of_pat_with_adjust(&self, id: PatId) -> Option<&Ty> {
+ match self.pat_adjustments.get(&id).and_then(|adjustments| adjustments.last()) {
+ adjusted @ Some(_) => adjusted,
+ None => self.type_of_pat.get(id),
+ }
+ }
pub fn is_erroneous(&self) -> bool {
self.has_errors && self.type_of_expr.iter().count() == 0
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
index 236f316..3f310c2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
@@ -85,16 +85,6 @@ pub fn layout_of_adt_query(
let d = db.const_eval_discriminant(e.enum_variants(db).variants[id.0].0).ok()?;
Some((id, d))
}),
- // FIXME: The current code for niche-filling relies on variant indices
- // instead of actual discriminants, so enums with
- // explicit discriminants (RFC #2363) would misbehave and we should disable
- // niche optimization for them.
- // The code that do it in rustc:
- // repr.inhibit_enum_layout_opt() || def
- // .variants()
- // .iter_enumerated()
- // .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32()))
- repr.inhibit_enum_layout_opt(),
!matches!(def, AdtId::EnumId(..))
&& variants
.iter()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index f32b6af..d61e7de 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -590,9 +590,14 @@ pub(crate) fn lower_type_bound<'b>(
.resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
let pointee_sized = LangItem::PointeeSized
.resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
- if meta_sized.is_some_and(|it| it == trait_ref.hir_trait_id()) {
+ let destruct = LangItem::Destruct
+ .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
+ let hir_trait_id = trait_ref.hir_trait_id();
+ if meta_sized.is_some_and(|it| it == hir_trait_id)
+ || destruct.is_some_and(|it| it == hir_trait_id)
+ {
// Ignore this bound
- } else if pointee_sized.is_some_and(|it| it == trait_ref.hir_trait_id()) {
+ } else if pointee_sized.is_some_and(|it| it == hir_trait_id) {
// Regard this as `?Sized` bound
ctx.ty_ctx().unsized_types.insert(self_ty);
} else {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index 238753e..c4c17a9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -2349,3 +2349,37 @@ fn test() {
"#]],
);
}
+
+#[test]
+fn rust_destruct_option_clone() {
+ check_types(
+ r#"
+//- minicore: option, drop
+fn test(o: &Option<i32>) {
+ o.my_clone();
+ //^^^^^^^^^^^^ Option<i32>
+}
+pub trait MyClone: Sized {
+ fn my_clone(&self) -> Self;
+}
+impl<T> const MyClone for Option<T>
+where
+ T: ~const MyClone + ~const Destruct,
+{
+ fn my_clone(&self) -> Self {
+ match self {
+ Some(x) => Some(x.my_clone()),
+ None => None,
+ }
+ }
+}
+impl const MyClone for i32 {
+ fn my_clone(&self) -> Self {
+ *self
+ }
+}
+#[lang = "destruct"]
+pub trait Destruct {}
+"#,
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 1b2b769..4ddb04b 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -1922,10 +1922,6 @@ pub fn diagnostics<'db>(
Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints);
}
- source_map
- .macro_calls()
- .for_each(|(_ast_id, call_id)| macro_call_diagnostics(db, call_id, acc));
-
expr_store_diagnostics(db, acc, &source_map);
let infer = db.infer(self.into());
@@ -2130,9 +2126,9 @@ pub fn diagnostics<'db>(
}
}
-fn expr_store_diagnostics(
- db: &dyn HirDatabase,
- acc: &mut Vec<AnyDiagnostic<'_>>,
+fn expr_store_diagnostics<'db>(
+ db: &'db dyn HirDatabase,
+ acc: &mut Vec<AnyDiagnostic<'db>>,
source_map: &ExpressionStoreSourceMap,
) {
for diag in source_map.diagnostics() {
@@ -2140,30 +2136,6 @@ fn expr_store_diagnostics(
ExpressionStoreDiagnostics::InactiveCode { node, cfg, opts } => {
InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into()
}
- ExpressionStoreDiagnostics::MacroError { node, err } => {
- let RenderedExpandError { message, error, kind } = err.render_to_string(db);
-
- let editioned_file_id = EditionedFileId::from_span(db, err.span().anchor.file_id);
- let precise_location = if editioned_file_id == node.file_id {
- Some(
- err.span().range
- + db.ast_id_map(editioned_file_id.into())
- .get_erased(err.span().anchor.ast_id)
- .text_range()
- .start(),
- )
- } else {
- None
- };
- MacroError {
- node: (node).map(|it| it.into()),
- precise_location,
- message,
- error,
- kind,
- }
- .into()
- }
ExpressionStoreDiagnostics::UnresolvedMacroCall { node, path } => UnresolvedMacroCall {
macro_call: (*node).map(|ast_ptr| ast_ptr.into()),
precise_location: None,
@@ -2182,6 +2154,10 @@ fn expr_store_diagnostics(
}
});
}
+
+ source_map
+ .macro_calls()
+ .for_each(|(_ast_id, call_id)| macro_call_diagnostics(db, call_id, acc));
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Function {
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index ecc6e5f..0b554a9 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -441,7 +441,7 @@ fn field_subst(
) -> Option<GenericSubstitution<'db>> {
let body = self.store()?;
if let Expr::Field { expr: object_expr, name: _ } = body[field_expr] {
- let (adt, subst) = type_of_expr_including_adjust(infer, object_expr)?.as_adt()?;
+ let (adt, subst) = infer.type_of_expr_with_adjust(object_expr)?.as_adt()?;
return Some(GenericSubstitution::new(
adt.into(),
subst.clone(),
@@ -1780,10 +1780,3 @@ pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> H
let ctx = span_map.span_at(name.value.text_range().start()).ctx;
HygieneId::new(ctx.opaque_and_semitransparent(db))
}
-
-fn type_of_expr_including_adjust(infer: &InferenceResult, id: ExprId) -> Option<&Ty> {
- match infer.expr_adjustment(id).and_then(|adjustments| adjustments.last()) {
- Some(adjustment) => Some(&adjustment.target),
- None => Some(&infer[id]),
- }
-}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index 9f9d219..ab183ac 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -2,6 +2,7 @@
use syntax::{
Edition,
ast::{self, AstNode, make},
+ syntax_editor::{Position, SyntaxEditor},
};
use crate::{
@@ -147,45 +148,78 @@ fn add_missing_impl_members_inner(
let target = impl_def.syntax().text_range();
acc.add(AssistId::quick_fix(assist_id), label, target, |edit| {
- let new_impl_def = edit.make_mut(impl_def.clone());
- let first_new_item = add_trait_assoc_items_to_impl(
+ let new_item = add_trait_assoc_items_to_impl(
&ctx.sema,
ctx.config,
&missing_items,
trait_,
- &new_impl_def,
+ &impl_def,
&target_scope,
);
+ let Some((first_new_item, other_items)) = new_item.split_first() else {
+ return;
+ };
+
+ let mut first_new_item = if let DefaultMethods::No = mode
+ && let ast::AssocItem::Fn(func) = &first_new_item
+ && let Some(body) = try_gen_trait_body(
+ ctx,
+ func,
+ trait_ref,
+ &impl_def,
+ target_scope.krate().edition(ctx.sema.db),
+ )
+ && let Some(func_body) = func.body()
+ {
+ let mut func_editor = SyntaxEditor::new(first_new_item.syntax().clone_subtree());
+ func_editor.replace(func_body.syntax(), body.syntax());
+ ast::AssocItem::cast(func_editor.finish().new_root().clone())
+ } else {
+ Some(first_new_item.clone())
+ };
+
+ let new_assoc_items = first_new_item
+ .clone()
+ .into_iter()
+ .chain(other_items.iter().cloned())
+ .map(either::Either::Right)
+ .collect::<Vec<_>>();
+
+ let mut editor = edit.make_editor(impl_def.syntax());
+ if let Some(assoc_item_list) = impl_def.assoc_item_list() {
+ let items = new_assoc_items.into_iter().filter_map(either::Either::right).collect();
+ assoc_item_list.add_items(&mut editor, items);
+ } else {
+ let assoc_item_list = make::assoc_item_list(Some(new_assoc_items)).clone_for_update();
+ editor.insert_all(
+ Position::after(impl_def.syntax()),
+ vec![make::tokens::whitespace(" ").into(), assoc_item_list.syntax().clone().into()],
+ );
+ first_new_item = assoc_item_list.assoc_items().next();
+ }
+
if let Some(cap) = ctx.config.snippet_cap {
let mut placeholder = None;
if let DefaultMethods::No = mode {
- if let ast::AssocItem::Fn(func) = &first_new_item {
- if try_gen_trait_body(
- ctx,
- func,
- trait_ref,
- &impl_def,
- target_scope.krate().edition(ctx.sema.db),
- )
- .is_none()
+ if let Some(ast::AssocItem::Fn(func)) = &first_new_item {
+ if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
+ && m.syntax().text() == "todo!()"
{
- if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
- {
- if m.syntax().text() == "todo!()" {
- placeholder = Some(m);
- }
- }
+ placeholder = Some(m);
}
}
}
if let Some(macro_call) = placeholder {
- edit.add_placeholder_snippet(cap, macro_call);
- } else {
- edit.add_tabstop_before(cap, first_new_item);
+ let placeholder = edit.make_placeholder_snippet(cap);
+ editor.add_annotation(macro_call.syntax(), placeholder);
+ } else if let Some(first_new_item) = first_new_item {
+ let tabstop = edit.make_tabstop_before(cap);
+ editor.add_annotation(first_new_item.syntax(), tabstop);
};
};
+ edit.add_file_edits(ctx.vfs_file_id(), editor);
})
}
@@ -195,7 +229,7 @@ fn try_gen_trait_body(
trait_ref: hir::TraitRef<'_>,
impl_def: &ast::Impl,
edition: Edition,
-) -> Option<()> {
+) -> Option<ast::BlockExpr> {
let trait_path = make::ext::ident_path(
&trait_ref.trait_().name(ctx.db()).display(ctx.db(), edition).to_string(),
);
@@ -322,7 +356,7 @@ fn foo(&self) {
}
#[test]
- fn test_impl_def_without_braces() {
+ fn test_impl_def_without_braces_macro() {
check_assist(
add_missing_impl_members,
r#"
@@ -341,6 +375,33 @@ fn foo(&self) {
}
#[test]
+ fn test_impl_def_without_braces_tabstop_first_item() {
+ check_assist(
+ add_missing_impl_members,
+ r#"
+trait Foo {
+ type Output;
+ fn foo(&self);
+}
+struct S;
+impl Foo for S { $0 }"#,
+ r#"
+trait Foo {
+ type Output;
+ fn foo(&self);
+}
+struct S;
+impl Foo for S {
+ $0type Output;
+
+ fn foo(&self) {
+ todo!()
+ }
+}"#,
+ );
+ }
+
+ #[test]
fn fill_in_type_params_1() {
check_assist(
add_missing_impl_members,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
index bcd06c1..d7b7e8d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
@@ -228,8 +228,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
closure_body,
Some(ast::ElseBranch::Block(make.block_expr(None, Some(none_path)))),
)
- .indent(mcall.indent_level())
- .clone_for_update();
+ .indent(mcall.indent_level());
editor.replace(mcall.syntax().clone(), if_expr.syntax().clone());
editor.add_mappings(make.finish_with_mappings());
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
index 71a61f2..2ea032f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
@@ -13,7 +13,6 @@
edit::{AstNodeEdit, IndentLevel},
make,
},
- ted,
};
use crate::{
@@ -117,7 +116,7 @@ fn if_expr_to_guarded_return(
then_block.syntax().last_child_or_token().filter(|t| t.kind() == T!['}'])?;
- let then_block_items = then_block.dedent(IndentLevel(1)).clone_for_update();
+ let then_block_items = then_block.dedent(IndentLevel(1));
let end_of_then = then_block_items.syntax().last_child_or_token()?;
let end_of_then = if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
@@ -132,7 +131,6 @@ fn if_expr_to_guarded_return(
"Convert to guarded return",
target,
|edit| {
- let if_expr = edit.make_mut(if_expr);
let if_indent_level = IndentLevel::from_node(if_expr.syntax());
let replacement = match if_let_pat {
None => {
@@ -143,7 +141,7 @@ fn if_expr_to_guarded_return(
let cond = invert_boolean_expression_legacy(cond_expr);
make::expr_if(cond, then_branch, None).indent(if_indent_level)
};
- new_expr.syntax().clone_for_update()
+ new_expr.syntax().clone()
}
Some(pat) => {
// If-let.
@@ -154,7 +152,7 @@ fn if_expr_to_guarded_return(
ast::make::tail_only_block_expr(early_expression),
);
let let_else_stmt = let_else_stmt.indent(if_indent_level);
- let_else_stmt.syntax().clone_for_update()
+ let_else_stmt.syntax().clone()
}
};
@@ -168,8 +166,9 @@ fn if_expr_to_guarded_return(
.take_while(|i| *i != end_of_then),
)
.collect();
-
- ted::replace_with_many(if_expr.syntax(), then_statements)
+ let mut editor = edit.make_editor(if_expr.syntax());
+ editor.replace_with_many(if_expr.syntax(), then_statements);
+ edit.add_file_edits(ctx.vfs_file_id(), editor);
},
)
}
@@ -214,7 +213,6 @@ fn let_stmt_to_guarded_return(
"Convert to guarded return",
target,
|edit| {
- let let_stmt = edit.make_mut(let_stmt);
let let_indent_level = IndentLevel::from_node(let_stmt.syntax());
let replacement = {
@@ -225,10 +223,11 @@ fn let_stmt_to_guarded_return(
ast::make::tail_only_block_expr(early_expression),
);
let let_else_stmt = let_else_stmt.indent(let_indent_level);
- let_else_stmt.syntax().clone_for_update()
+ let_else_stmt.syntax().clone()
};
-
- ted::replace(let_stmt.syntax(), replacement)
+ let mut editor = edit.make_editor(let_stmt.syntax());
+ editor.replace(let_stmt.syntax(), replacement);
+ edit.add_file_edits(ctx.vfs_file_id(), editor);
},
)
}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs
index 54699a9..cdc0e96 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs
@@ -8,8 +8,7 @@
AstNode, AstToken, NodeOrToken,
SyntaxKind::WHITESPACE,
T,
- ast::{self, make},
- ted,
+ ast::{self, make, syntax_factory::SyntaxFactory},
};
// Assist: extract_expressions_from_format_string
@@ -58,8 +57,6 @@ pub(crate) fn extract_expressions_from_format_string(
"Extract format expressions",
tt.syntax().text_range(),
|edit| {
- let tt = edit.make_mut(tt);
-
// Extract existing arguments in macro
let tokens = tt.token_trees_and_tokens().collect_vec();
@@ -131,8 +128,10 @@ pub(crate) fn extract_expressions_from_format_string(
}
// Insert new args
- let new_tt = make::token_tree(tt_delimiter, new_tt_bits).clone_for_update();
- ted::replace(tt.syntax(), new_tt.syntax());
+ let make = SyntaxFactory::with_mappings();
+ let new_tt = make.token_tree(tt_delimiter, new_tt_bits);
+ let mut editor = edit.make_editor(tt.syntax());
+ editor.replace(tt.syntax(), new_tt.syntax());
if let Some(cap) = ctx.config.snippet_cap {
// Add placeholder snippets over placeholder args
@@ -145,15 +144,19 @@ pub(crate) fn extract_expressions_from_format_string(
};
if stdx::always!(placeholder.kind() == T![_]) {
- edit.add_placeholder_snippet_token(cap, placeholder);
+ let annotation = edit.make_placeholder_snippet(cap);
+ editor.add_annotation(placeholder, annotation);
}
}
// Add the final tabstop after the format literal
if let Some(NodeOrToken::Token(literal)) = new_tt.token_trees_and_tokens().nth(1) {
- edit.add_tabstop_after_token(cap, literal);
+ let annotation = edit.make_tabstop_after(cap);
+ editor.add_annotation(literal, annotation);
}
}
+ editor.add_mappings(make.finish_with_mappings());
+ edit.add_file_edits(ctx.vfs_file_id(), editor);
},
);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index b9c4228..9095b18 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -16,8 +16,9 @@
SyntaxKind::*,
SyntaxNode, T,
ast::{
- self, AstNode, HasAttrs, HasGenericParams, HasName, HasVisibility, edit::IndentLevel,
- edit_in_place::Indent, make,
+ self, AstNode, HasAttrs, HasGenericParams, HasName, HasVisibility,
+ edit::{AstNodeEdit, IndentLevel},
+ make,
},
match_ast, ted,
};
@@ -110,20 +111,30 @@ pub(crate) fn extract_struct_from_enum_variant(
let generics = generic_params.as_ref().map(|generics| generics.clone_for_update());
// resolve GenericArg in field_list to actual type
- let field_list = field_list.clone_for_update();
- if let Some((target_scope, source_scope)) =
+ let field_list = if let Some((target_scope, source_scope)) =
ctx.sema.scope(enum_ast.syntax()).zip(ctx.sema.scope(field_list.syntax()))
{
- PathTransform::generic_transformation(&target_scope, &source_scope)
- .apply(field_list.syntax());
- }
+ let field_list = field_list.reset_indent();
+ let field_list =
+ PathTransform::generic_transformation(&target_scope, &source_scope)
+ .apply(field_list.syntax());
+ match_ast! {
+ match field_list {
+ ast::RecordFieldList(field_list) => Either::Left(field_list),
+ ast::TupleFieldList(field_list) => Either::Right(field_list),
+ _ => unreachable!(),
+ }
+ }
+ } else {
+ field_list.clone_for_update()
+ };
let def =
create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast);
let enum_ast = variant.parent_enum();
let indent = enum_ast.indent_level();
- def.reindent_to(indent);
+ let def = def.indent(indent);
ted::insert_all(
ted::Position::before(enum_ast.syntax()),
@@ -279,7 +290,7 @@ fn create_struct_def(
field_list.clone().into()
}
};
- field_list.reindent_to(IndentLevel::single());
+ let field_list = field_list.indent(IndentLevel::single());
let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
index 31e84e9..db2d316 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
@@ -7,7 +7,9 @@
NodeOrToken, SyntaxKind, SyntaxNode, T,
algo::ancestors_at_offset,
ast::{
- self, AstNode, edit::IndentLevel, edit_in_place::Indent, make,
+ self, AstNode,
+ edit::{AstNodeEdit, IndentLevel},
+ make,
syntax_factory::SyntaxFactory,
},
syntax_editor::Position,
@@ -253,12 +255,11 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
// `expr_replace` is a descendant of `to_wrap`, so we just replace it with `name_expr`.
editor.replace(expr_replace, name_expr.syntax());
make.block_expr([new_stmt], Some(to_wrap.clone()))
- };
+ }
+ // fixup indentation of block
+ .indent_with_mapping(indent_to, &make);
editor.replace(to_wrap.syntax(), block.syntax());
-
- // fixup indentation of block
- block.indent(indent_to);
}
}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index ca66cb6..6063898 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -114,9 +114,13 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
let source_scope = ctx.sema.scope(v.syntax());
let target_scope = ctx.sema.scope(strukt.syntax());
if let (Some(s), Some(t)) = (source_scope, target_scope) {
- PathTransform::generic_transformation(&t, &s).apply(v.syntax());
+ ast::Fn::cast(
+ PathTransform::generic_transformation(&t, &s).apply(v.syntax()),
+ )
+ .unwrap_or(v)
+ } else {
+ v
}
- v
}
None => return,
};
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index 848c638..e96250f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -255,7 +255,6 @@ fn generate_impl(
delegee: &Delegee,
edition: Edition,
) -> Option<ast::Impl> {
- let delegate: ast::Impl;
let db = ctx.db();
let ast_strukt = &strukt.strukt;
let strukt_ty = make::ty_path(make::ext::ident_path(&strukt.name.to_string()));
@@ -266,7 +265,7 @@ fn generate_impl(
let bound_def = ctx.sema.source(delegee.to_owned())?.value;
let bound_params = bound_def.generic_param_list();
- delegate = make::impl_trait(
+ let delegate = make::impl_trait(
delegee.is_unsafe(db),
bound_params.clone(),
bound_params.map(|params| params.to_generic_args()),
@@ -304,7 +303,7 @@ fn generate_impl(
let target_scope = ctx.sema.scope(strukt.strukt.syntax())?;
let source_scope = ctx.sema.scope(bound_def.syntax())?;
let transform = PathTransform::generic_transformation(&target_scope, &source_scope);
- transform.apply(delegate.syntax());
+ ast::Impl::cast(transform.apply(delegate.syntax()))
}
Delegee::Impls(trait_, old_impl) => {
let old_impl = ctx.sema.source(old_impl.to_owned())?.value;
@@ -358,20 +357,28 @@ fn generate_impl(
// 2.3) Instantiate generics with `transform_impl`, this step also
// remove unused params.
- let mut trait_gen_args = old_impl.trait_()?.generic_arg_list();
- if let Some(trait_args) = &mut trait_gen_args {
- *trait_args = trait_args.clone_for_update();
- transform_impl(ctx, ast_strukt, &old_impl, &transform_args, trait_args.syntax())?;
- }
+ let trait_gen_args = old_impl.trait_()?.generic_arg_list().and_then(|trait_args| {
+ let trait_args = &mut trait_args.clone_for_update();
+ if let Some(new_args) = transform_impl(
+ ctx,
+ ast_strukt,
+ &old_impl,
+ &transform_args,
+ trait_args.clone_subtree(),
+ ) {
+ *trait_args = new_args.clone_subtree();
+ Some(new_args)
+ } else {
+ None
+ }
+ });
let type_gen_args = strukt_params.clone().map(|params| params.to_generic_args());
-
let path_type =
make::ty(&trait_.name(db).display_no_db(edition).to_smolstr()).clone_for_update();
- transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type.syntax())?;
-
+ let path_type = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type)?;
// 3) Generate delegate trait impl
- delegate = make::impl_trait(
+ let delegate = make::impl_trait(
trait_.is_unsafe(db),
trait_gen_params,
trait_gen_args,
@@ -385,7 +392,6 @@ fn generate_impl(
None,
)
.clone_for_update();
-
// Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths
let qualified_path_type =
make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
@@ -398,7 +404,7 @@ fn generate_impl(
.filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
{
let item = item.clone_for_update();
- transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item.syntax())?;
+ let item = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item)?;
let assoc = process_assoc_item(item, qualified_path_type.clone(), field_name)?;
delegate_assoc_items.add_item(assoc);
@@ -408,19 +414,18 @@ fn generate_impl(
if let Some(wc) = delegate.where_clause() {
remove_useless_where_clauses(&delegate.trait_()?, &delegate.self_ty()?, wc);
}
+ Some(delegate)
}
}
-
- Some(delegate)
}
-fn transform_impl(
+fn transform_impl<N: ast::AstNode>(
ctx: &AssistContext<'_>,
strukt: &ast::Struct,
old_impl: &ast::Impl,
args: &Option<GenericArgList>,
- syntax: &syntax::SyntaxNode,
-) -> Option<()> {
+ syntax: N,
+) -> Option<N> {
let source_scope = ctx.sema.scope(old_impl.self_ty()?.syntax())?;
let target_scope = ctx.sema.scope(strukt.syntax())?;
let hir_old_impl = ctx.sema.to_impl_def(old_impl)?;
@@ -437,8 +442,7 @@ fn transform_impl(
},
);
- transform.apply(syntax);
- Some(())
+ N::cast(transform.apply(syntax.syntax()))
}
fn remove_instantiated_params(
@@ -570,9 +574,7 @@ fn rename_strukt_args<N>(
let scope = ctx.sema.scope(item.syntax())?;
let transform = PathTransform::adt_transformation(&scope, &scope, hir_adt, args.clone());
- transform.apply(item.syntax());
-
- Some(item)
+ N::cast(transform.apply(item.syntax()))
}
fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_>) -> Option<()> {
@@ -767,7 +769,7 @@ fn func_assoc_item(
)
.clone_for_update();
- Some(AssocItem::Fn(func.indent(edit::IndentLevel(1)).clone_for_update()))
+ Some(AssocItem::Fn(func.indent(edit::IndentLevel(1))))
}
fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option<AssocItem> {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index 78ae815..3290a70 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -743,17 +743,30 @@ fn fn_generic_params(
let where_preds: Vec<ast::WherePred> =
where_preds.into_iter().map(|it| it.node.clone_for_update()).collect();
- // 4. Rewrite paths
- if let Some(param) = generic_params.first() {
- let source_scope = ctx.sema.scope(param.syntax())?;
- let target_scope = ctx.sema.scope(&target.parent())?;
- if source_scope.module() != target_scope.module() {
+ let (generic_params, where_preds): (Vec<ast::GenericParam>, Vec<ast::WherePred>) =
+ if let Some(param) = generic_params.first()
+ && let source_scope = ctx.sema.scope(param.syntax())?
+ && let target_scope = ctx.sema.scope(&target.parent())?
+ && source_scope.module() != target_scope.module()
+ {
+ // 4. Rewrite paths
let transform = PathTransform::generic_transformation(&target_scope, &source_scope);
let generic_params = generic_params.iter().map(|it| it.syntax());
let where_preds = where_preds.iter().map(|it| it.syntax());
- transform.apply_all(generic_params.chain(where_preds));
- }
- }
+ transform
+ .apply_all(generic_params.chain(where_preds))
+ .into_iter()
+ .filter_map(|it| {
+ if let Some(it) = ast::GenericParam::cast(it.clone()) {
+ Some(either::Either::Left(it))
+ } else {
+ ast::WherePred::cast(it).map(either::Either::Right)
+ }
+ })
+ .partition_map(|it| it)
+ } else {
+ (generic_params, where_preds)
+ };
let generic_param_list = make::generic_param_list(generic_params);
let where_clause =
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
index 14601ca..31cadcf 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
@@ -1,12 +1,17 @@
use syntax::{
- ast::{self, AstNode, HasName, edit_in_place::Indent, make},
+ ast::{self, AstNode, HasGenericParams, HasName, edit_in_place::Indent, make},
syntax_editor::{Position, SyntaxEditor},
};
-use crate::{AssistContext, AssistId, Assists, utils};
+use crate::{
+ AssistContext, AssistId, Assists,
+ utils::{self, DefaultMethods, IgnoreAssocItems},
+};
-fn insert_impl(editor: &mut SyntaxEditor, impl_: &ast::Impl, nominal: &ast::Adt) {
+fn insert_impl(editor: &mut SyntaxEditor, impl_: &ast::Impl, nominal: &impl Indent) {
let indent = nominal.indent_level();
+
+ impl_.indent(indent);
editor.insert_all(
Position::after(nominal.syntax()),
vec![
@@ -120,6 +125,126 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
)
}
+// Assist: generate_impl_trait
+//
+// Adds this trait impl for a type.
+//
+// ```
+// trait $0Foo {
+// fn foo(&self) -> i32;
+// }
+// ```
+// ->
+// ```
+// trait Foo {
+// fn foo(&self) -> i32;
+// }
+//
+// impl Foo for ${1:_} {
+// fn foo(&self) -> i32 {
+// $0todo!()
+// }
+// }
+// ```
+pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+ let name = ctx.find_node_at_offset::<ast::Name>()?;
+ let trait_ = ast::Trait::cast(name.syntax().parent()?)?;
+ let target_scope = ctx.sema.scope(trait_.syntax())?;
+ let hir_trait = ctx.sema.to_def(&trait_)?;
+
+ let target = trait_.syntax().text_range();
+ acc.add(
+ AssistId::generate("generate_impl_trait"),
+ format!("Generate `{name}` impl for type"),
+ target,
+ |edit| {
+ let mut editor = edit.make_editor(trait_.syntax());
+
+ let holder_arg = ast::GenericArg::TypeArg(make::type_arg(make::ty_placeholder()));
+ let missing_items = utils::filter_assoc_items(
+ &ctx.sema,
+ &hir_trait.items(ctx.db()),
+ DefaultMethods::No,
+ IgnoreAssocItems::DocHiddenAttrPresent,
+ );
+
+ let trait_gen_args = trait_.generic_param_list().map(|list| {
+ make::generic_arg_list(list.generic_params().map(|_| holder_arg.clone()))
+ });
+
+ let make_impl_ = |body| {
+ make::impl_trait(
+ trait_.unsafe_token().is_some(),
+ None,
+ trait_gen_args.clone(),
+ None,
+ None,
+ false,
+ make::ty(&name.text()),
+ make::ty_placeholder(),
+ None,
+ None,
+ body,
+ )
+ .clone_for_update()
+ };
+
+ let impl_ = if missing_items.is_empty() {
+ make_impl_(None)
+ } else {
+ let impl_ = make_impl_(None);
+ let assoc_items = utils::add_trait_assoc_items_to_impl(
+ &ctx.sema,
+ ctx.config,
+ &missing_items,
+ hir_trait,
+ &impl_,
+ &target_scope,
+ );
+ let assoc_items = assoc_items.into_iter().map(either::Either::Right).collect();
+ let assoc_item_list = make::assoc_item_list(Some(assoc_items));
+ make_impl_(Some(assoc_item_list))
+ };
+
+ if let Some(cap) = ctx.config.snippet_cap {
+ if let Some(generics) = impl_.trait_().and_then(|it| it.generic_arg_list()) {
+ for generic in generics.generic_args() {
+ let placeholder = edit.make_placeholder_snippet(cap);
+ editor.add_annotation(generic.syntax(), placeholder);
+ }
+ }
+
+ if let Some(ty) = impl_.self_ty() {
+ let placeholder = edit.make_placeholder_snippet(cap);
+ editor.add_annotation(ty.syntax(), placeholder);
+ }
+
+ if let Some(expr) =
+ impl_.assoc_item_list().and_then(|it| it.assoc_items().find_map(extract_expr))
+ {
+ let tabstop = edit.make_tabstop_before(cap);
+ editor.add_annotation(expr.syntax(), tabstop);
+ } else if let Some(l_curly) =
+ impl_.assoc_item_list().and_then(|it| it.l_curly_token())
+ {
+ let tabstop = edit.make_tabstop_after(cap);
+ editor.add_annotation(l_curly, tabstop);
+ }
+ }
+
+ insert_impl(&mut editor, &impl_, &trait_);
+ edit.add_file_edits(ctx.vfs_file_id(), editor);
+ },
+ )
+}
+
+fn extract_expr(item: ast::AssocItem) -> Option<ast::Expr> {
+ let ast::AssocItem::Fn(f) = item else {
+ return None;
+ };
+ f.body()?.tail_expr()
+}
+
#[cfg(test)]
mod tests {
use crate::tests::{check_assist, check_assist_target};
@@ -492,4 +617,209 @@ impl ${1:_} for Bar {$0}
"#,
);
}
+
+ #[test]
+ fn test_add_impl_trait() {
+ check_assist(
+ generate_impl_trait,
+ r#"
+ trait $0Foo {
+ fn foo(&self) -> i32;
+
+ fn bar(&self) -> i32 {
+ self.foo()
+ }
+ }
+ "#,
+ r#"
+ trait Foo {
+ fn foo(&self) -> i32;
+
+ fn bar(&self) -> i32 {
+ self.foo()
+ }
+ }
+
+ impl Foo for ${1:_} {
+ fn foo(&self) -> i32 {
+ $0todo!()
+ }
+ }
+ "#,
+ );
+ }
+
+ #[test]
+ fn test_add_impl_trait_use_generic() {
+ check_assist(
+ generate_impl_trait,
+ r#"
+ trait $0Foo<T> {
+ fn foo(&self) -> T;
+
+ fn bar(&self) -> T {
+ self.foo()
+ }
+ }
+ "#,
+ r#"
+ trait Foo<T> {
+ fn foo(&self) -> T;
+
+ fn bar(&self) -> T {
+ self.foo()
+ }
+ }
+
+ impl Foo<${1:_}> for ${2:_} {
+ fn foo(&self) -> _ {
+ $0todo!()
+ }
+ }
+ "#,
+ );
+ check_assist(
+ generate_impl_trait,
+ r#"
+ trait $0Foo<T, U> {
+ fn foo(&self) -> T;
+
+ fn bar(&self) -> T {
+ self.foo()
+ }
+ }
+ "#,
+ r#"
+ trait Foo<T, U> {
+ fn foo(&self) -> T;
+
+ fn bar(&self) -> T {
+ self.foo()
+ }
+ }
+
+ impl Foo<${1:_}, ${2:_}> for ${3:_} {
+ fn foo(&self) -> _ {
+ $0todo!()
+ }
+ }
+ "#,
+ );
+ }
+
+ #[test]
+ fn test_add_impl_trait_docs() {
+ check_assist(
+ generate_impl_trait,
+ r#"
+ /// foo
+ trait $0Foo {
+ /// foo method
+ fn foo(&self) -> i32;
+
+ fn bar(&self) -> i32 {
+ self.foo()
+ }
+ }
+ "#,
+ r#"
+ /// foo
+ trait Foo {
+ /// foo method
+ fn foo(&self) -> i32;
+
+ fn bar(&self) -> i32 {
+ self.foo()
+ }
+ }
+
+ impl Foo for ${1:_} {
+ fn foo(&self) -> i32 {
+ $0todo!()
+ }
+ }
+ "#,
+ );
+ }
+
+ #[test]
+ fn test_add_impl_trait_assoc_types() {
+ check_assist(
+ generate_impl_trait,
+ r#"
+ trait $0Foo {
+ type Output;
+
+ fn foo(&self) -> Self::Output;
+ }
+ "#,
+ r#"
+ trait Foo {
+ type Output;
+
+ fn foo(&self) -> Self::Output;
+ }
+
+ impl Foo for ${1:_} {
+ type Output;
+
+ fn foo(&self) -> Self::Output {
+ $0todo!()
+ }
+ }
+ "#,
+ );
+ }
+
+ #[test]
+ fn test_add_impl_trait_indent() {
+ check_assist(
+ generate_impl_trait,
+ r#"
+ mod foo {
+ mod bar {
+ trait $0Foo {
+ type Output;
+
+ fn foo(&self) -> Self::Output;
+ }
+ }
+ }
+ "#,
+ r#"
+ mod foo {
+ mod bar {
+ trait Foo {
+ type Output;
+
+ fn foo(&self) -> Self::Output;
+ }
+
+ impl Foo for ${1:_} {
+ type Output;
+
+ fn foo(&self) -> Self::Output {
+ $0todo!()
+ }
+ }
+ }
+ }
+ "#,
+ );
+ }
+
+ #[test]
+ fn test_add_impl_trait_empty() {
+ check_assist(
+ generate_impl_trait,
+ r#"
+ trait $0Foo {}
+ "#,
+ r#"
+ trait Foo {}
+
+ impl Foo for ${1:_} {$0}
+ "#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
index dc26ec7..9c4bcdd 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
@@ -94,7 +94,7 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
})?;
let _ = process_ref_mut(&fn_);
- let assoc_list = make::assoc_item_list().clone_for_update();
+ let assoc_list = make::assoc_item_list(None).clone_for_update();
ted::replace(impl_def.assoc_item_list()?.syntax(), assoc_list.syntax());
impl_def.get_or_create_assoc_item_list().add_item(syntax::ast::AssocItem::Fn(fn_));
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
index 51c2f65..5bda122 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
@@ -4,12 +4,12 @@
};
use syntax::{
ast::{self, AstNode, HasName, HasVisibility, StructKind, edit_in_place::Indent, make},
- ted,
+ syntax_editor::Position,
};
use crate::{
AssistContext, AssistId, Assists,
- utils::{find_struct_impl, generate_impl},
+ utils::{find_struct_impl, generate_impl_with_item},
};
// Assist: generate_new
@@ -149,7 +149,53 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
.clone_for_update();
fn_.indent(1.into());
- if let Some(cap) = ctx.config.snippet_cap {
+ let mut editor = builder.make_editor(strukt.syntax());
+
+ // Get the node for set annotation
+ let contain_fn = if let Some(impl_def) = impl_def {
+ fn_.indent(impl_def.indent_level());
+
+ if let Some(l_curly) = impl_def.assoc_item_list().and_then(|list| list.l_curly_token())
+ {
+ editor.insert_all(
+ Position::after(l_curly),
+ vec![
+ make::tokens::whitespace(&format!("\n{}", impl_def.indent_level() + 1))
+ .into(),
+ fn_.syntax().clone().into(),
+ make::tokens::whitespace("\n").into(),
+ ],
+ );
+ fn_.syntax().clone()
+ } else {
+ let items = vec![either::Either::Right(ast::AssocItem::Fn(fn_))];
+ let list = make::assoc_item_list(Some(items));
+ editor.insert(Position::after(impl_def.syntax()), list.syntax());
+ list.syntax().clone()
+ }
+ } else {
+ // Generate a new impl to add the method to
+ let indent_level = strukt.indent_level();
+ let body = vec![either::Either::Right(ast::AssocItem::Fn(fn_))];
+ let list = make::assoc_item_list(Some(body));
+ let impl_def = generate_impl_with_item(&ast::Adt::Struct(strukt.clone()), Some(list));
+
+ impl_def.indent(strukt.indent_level());
+
+ // Insert it after the adt
+ editor.insert_all(
+ Position::after(strukt.syntax()),
+ vec![
+ make::tokens::whitespace(&format!("\n\n{indent_level}")).into(),
+ impl_def.syntax().clone().into(),
+ ],
+ );
+ impl_def.syntax().clone()
+ };
+
+ if let Some(fn_) = contain_fn.descendants().find_map(ast::Fn::cast)
+ && let Some(cap) = ctx.config.snippet_cap
+ {
match strukt.kind() {
StructKind::Tuple(_) => {
let struct_args = fn_
@@ -168,8 +214,8 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
for (struct_arg, fn_param) in struct_args.zip(fn_params.params()) {
if let Some(fn_pat) = fn_param.pat() {
let fn_pat = fn_pat.syntax().clone();
- builder
- .add_placeholder_snippet_group(cap, vec![struct_arg, fn_pat]);
+ let placeholder = builder.make_placeholder_snippet(cap);
+ editor.add_annotation_all(vec![struct_arg, fn_pat], placeholder)
}
}
}
@@ -179,36 +225,12 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
// Add a tabstop before the name
if let Some(name) = fn_.name() {
- builder.add_tabstop_before(cap, name);
+ let tabstop_before = builder.make_tabstop_before(cap);
+ editor.add_annotation(name.syntax(), tabstop_before);
}
}
- // Get the mutable version of the impl to modify
- let impl_def = if let Some(impl_def) = impl_def {
- fn_.indent(impl_def.indent_level());
- builder.make_mut(impl_def)
- } else {
- // Generate a new impl to add the method to
- let impl_def = generate_impl(&ast::Adt::Struct(strukt.clone()));
- let indent_level = strukt.indent_level();
- fn_.indent(indent_level);
-
- // Insert it after the adt
- let strukt = builder.make_mut(strukt.clone());
-
- ted::insert_all_raw(
- ted::Position::after(strukt.syntax()),
- vec![
- make::tokens::whitespace(&format!("\n\n{indent_level}")).into(),
- impl_def.syntax().clone().into(),
- ],
- );
-
- impl_def
- };
-
- // Add the `new` method at the start of the impl
- impl_def.get_or_create_assoc_item_list().add_item_at_start(fn_.into());
+ builder.add_file_edits(ctx.vfs_file_id(), editor);
})
}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
index 154b502..92a4bd3 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
@@ -3,7 +3,7 @@
use syntax::{
AstNode, SyntaxKind, T,
ast::{
- self, HasGenericParams, HasName,
+ self, HasGenericParams, HasName, HasVisibility,
edit_in_place::{HasVisibilityEdit, Indent},
make,
},
@@ -164,6 +164,12 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
/// `E0449` Trait items always share the visibility of their trait
fn remove_items_visibility(item: &ast::AssocItem) {
if let Some(has_vis) = ast::AnyHasVisibility::cast(item.syntax().clone()) {
+ if let Some(vis) = has_vis.visibility()
+ && let Some(token) = vis.syntax().next_sibling_or_token()
+ && token.kind() == SyntaxKind::WHITESPACE
+ {
+ ted::remove(token);
+ }
has_vis.set_visibility(None);
}
}
@@ -333,11 +339,11 @@ pub fn a_func() -> Option<()> {
struct Foo;
trait NewTrait {
- fn a_func() -> Option<()>;
+ fn a_func() -> Option<()>;
}
impl NewTrait for Foo {
- fn a_func() -> Option<()> {
+ fn a_func() -> Option<()> {
Some(())
}
}"#,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
index b7b8bc6..1549b41 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
@@ -537,8 +537,13 @@ fn inline(
if let Some(generic_arg_list) = generic_arg_list.clone() {
if let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))
{
- PathTransform::function_call(target, source, function, generic_arg_list)
- .apply(body.syntax());
+ body.reindent_to(IndentLevel(0));
+ if let Some(new_body) = ast::BlockExpr::cast(
+ PathTransform::function_call(target, source, function, generic_arg_list)
+ .apply(body.syntax()),
+ ) {
+ body = new_body;
+ }
}
}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index 806c8fb..45bb6ce 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -5,12 +5,12 @@
SyntaxKind::WHITESPACE,
T,
ast::{self, AstNode, HasName, make},
- ted::{self, Position},
+ syntax_editor::{Position, SyntaxEditor},
};
use crate::{
AssistConfig, AssistId,
- assist_context::{AssistContext, Assists, SourceChangeBuilder},
+ assist_context::{AssistContext, Assists},
utils::{
DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items,
gen_trait_fn_body, generate_trait_impl,
@@ -126,98 +126,56 @@ fn add_assist(
let label = format!("Convert to manual `impl {replace_trait_path} for {annotated_name}`");
acc.add(AssistId::refactor("replace_derive_with_manual_impl"), label, target, |builder| {
- let insert_after = ted::Position::after(builder.make_mut(adt.clone()).syntax());
+ let insert_after = Position::after(adt.syntax());
let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false);
- let impl_def_with_items = impl_def_from_trait(
+ let impl_def = impl_def_from_trait(
&ctx.sema,
ctx.config,
adt,
&annotated_name,
trait_,
replace_trait_path,
+ impl_is_unsafe,
);
- update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
+
+ let mut editor = builder.make_editor(attr.syntax());
+ update_attribute(&mut editor, old_derives, old_tree, old_trait_path, attr);
let trait_path = make::ty_path(replace_trait_path.clone());
- match (ctx.config.snippet_cap, impl_def_with_items) {
- (None, None) => {
- let impl_def = generate_trait_impl(adt, trait_path);
- if impl_is_unsafe {
- ted::insert(
- Position::first_child_of(impl_def.syntax()),
- make::token(T![unsafe]),
- );
- }
+ let (impl_def, first_assoc_item) = if let Some(impl_def) = impl_def {
+ (
+ impl_def.clone(),
+ impl_def.assoc_item_list().and_then(|list| list.assoc_items().next()),
+ )
+ } else {
+ (generate_trait_impl(impl_is_unsafe, adt, trait_path), None)
+ };
- ted::insert_all(
- insert_after,
- vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
- );
- }
- (None, Some((impl_def, _))) => {
- if impl_is_unsafe {
- ted::insert(
- Position::first_child_of(impl_def.syntax()),
- make::token(T![unsafe]),
- );
- }
- ted::insert_all(
- insert_after,
- vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
- );
- }
- (Some(cap), None) => {
- let impl_def = generate_trait_impl(adt, trait_path);
-
- if impl_is_unsafe {
- ted::insert(
- Position::first_child_of(impl_def.syntax()),
- make::token(T![unsafe]),
- );
- }
-
- if let Some(l_curly) = impl_def.assoc_item_list().and_then(|it| it.l_curly_token())
+ if let Some(cap) = ctx.config.snippet_cap {
+ if let Some(first_assoc_item) = first_assoc_item {
+ if let ast::AssocItem::Fn(ref func) = first_assoc_item
+ && let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
+ && m.syntax().text() == "todo!()"
{
- builder.add_tabstop_after_token(cap, l_curly);
- }
-
- ted::insert_all(
- insert_after,
- vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
- );
- }
- (Some(cap), Some((impl_def, first_assoc_item))) => {
- let mut added_snippet = false;
-
- if impl_is_unsafe {
- ted::insert(
- Position::first_child_of(impl_def.syntax()),
- make::token(T![unsafe]),
- );
- }
-
- if let ast::AssocItem::Fn(ref func) = first_assoc_item {
- if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) {
- if m.syntax().text() == "todo!()" {
- // Make the `todo!()` a placeholder
- builder.add_placeholder_snippet(cap, m);
- added_snippet = true;
- }
- }
- }
-
- if !added_snippet {
+ // Make the `todo!()` a placeholder
+ builder.add_placeholder_snippet(cap, m);
+ } else {
// If we haven't already added a snippet, add a tabstop before the generated function
builder.add_tabstop_before(cap, first_assoc_item);
}
-
- ted::insert_all(
- insert_after,
- vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
- );
+ } else if let Some(l_curly) =
+ impl_def.assoc_item_list().and_then(|it| it.l_curly_token())
+ {
+ builder.add_tabstop_after_token(cap, l_curly);
}
- };
+ }
+
+ editor.insert_all(
+ insert_after,
+ vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+ );
+ builder.add_file_edits(ctx.vfs_file_id(), editor);
})
}
@@ -228,7 +186,8 @@ fn impl_def_from_trait(
annotated_name: &ast::Name,
trait_: Option<hir::Trait>,
trait_path: &ast::Path,
-) -> Option<(ast::Impl, ast::AssocItem)> {
+ impl_is_unsafe: bool,
+) -> Option<ast::Impl> {
let trait_ = trait_?;
let target_scope = sema.scope(annotated_name.syntax())?;
@@ -245,21 +204,43 @@ fn impl_def_from_trait(
if trait_items.is_empty() {
return None;
}
- let impl_def = generate_trait_impl(adt, make::ty_path(trait_path.clone()));
+ let impl_def = generate_trait_impl(impl_is_unsafe, adt, make::ty_path(trait_path.clone()));
- let first_assoc_item =
+ let assoc_items =
add_trait_assoc_items_to_impl(sema, config, &trait_items, trait_, &impl_def, &target_scope);
+ let assoc_item_list = if let Some((first, other)) =
+ assoc_items.split_first().map(|(first, other)| (first.clone_subtree(), other))
+ {
+ let first_item = if let ast::AssocItem::Fn(ref func) = first
+ && let Some(body) = gen_trait_fn_body(func, trait_path, adt, None)
+ && let Some(func_body) = func.body()
+ {
+ let mut editor = SyntaxEditor::new(first.syntax().clone());
+ editor.replace(func_body.syntax(), body.syntax());
+ ast::AssocItem::cast(editor.finish().new_root().clone())
+ } else {
+ Some(first.clone())
+ };
+ let items = first_item
+ .into_iter()
+ .chain(other.iter().cloned())
+ .map(either::Either::Right)
+ .collect();
+ make::assoc_item_list(Some(items))
+ } else {
+ make::assoc_item_list(None)
+ }
+ .clone_for_update();
- // Generate a default `impl` function body for the derived trait.
- if let ast::AssocItem::Fn(ref func) = first_assoc_item {
- let _ = gen_trait_fn_body(func, trait_path, adt, None);
- };
-
- Some((impl_def, first_assoc_item))
+ let impl_def = impl_def.clone_subtree();
+ let mut editor = SyntaxEditor::new(impl_def.syntax().clone());
+ editor.replace(impl_def.assoc_item_list()?.syntax(), assoc_item_list.syntax());
+ let impl_def = ast::Impl::cast(editor.finish().new_root().clone())?;
+ Some(impl_def)
}
fn update_attribute(
- builder: &mut SourceChangeBuilder,
+ editor: &mut SyntaxEditor,
old_derives: &[ast::Path],
old_tree: &ast::TokenTree,
old_trait_path: &ast::Path,
@@ -272,8 +253,6 @@ fn update_attribute(
let has_more_derives = !new_derives.is_empty();
if has_more_derives {
- let old_tree = builder.make_mut(old_tree.clone());
-
// Make the paths into flat lists of tokens in a vec
let tt = new_derives.iter().map(|path| path.syntax().clone()).map(|node| {
node.descendants_with_tokens()
@@ -288,18 +267,17 @@ fn update_attribute(
let tt = tt.collect::<Vec<_>>();
let new_tree = make::token_tree(T!['('], tt).clone_for_update();
- ted::replace(old_tree.syntax(), new_tree.syntax());
+ editor.replace(old_tree.syntax(), new_tree.syntax());
} else {
// Remove the attr and any trailing whitespace
- let attr = builder.make_mut(attr.clone());
if let Some(line_break) =
attr.syntax().next_sibling_or_token().filter(|t| t.kind() == WHITESPACE)
{
- ted::remove(line_break)
+ editor.delete(line_break)
}
- ted::remove(attr.syntax())
+ editor.delete(attr.syntax())
}
}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index cde0d87..4682c04 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -302,6 +302,7 @@ pub(crate) fn all() -> &'static [Handler] {
generate_function::generate_function,
generate_impl::generate_impl,
generate_impl::generate_trait_impl,
+ generate_impl::generate_impl_trait,
generate_is_empty_from_len::generate_is_empty_from_len,
generate_mut_trait_impl::generate_mut_trait_impl,
generate_new::generate_new,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index fc1c692..91348be 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -1881,6 +1881,29 @@ impl<T: Clone> Ctx<T> {$0}
}
#[test]
+fn doctest_generate_impl_trait() {
+ check_doc_test(
+ "generate_impl_trait",
+ r#####"
+trait $0Foo {
+ fn foo(&self) -> i32;
+}
+"#####,
+ r#####"
+trait Foo {
+ fn foo(&self) -> i32;
+}
+
+impl Foo for ${1:_} {
+ fn foo(&self) -> i32 {
+ $0todo!()
+ }
+}
+"#####,
+ )
+}
+
+#[test]
fn doctest_generate_is_empty_from_len() {
check_doc_test(
"generate_is_empty_from_len",
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index fbce1d3..15c7a6a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -23,10 +23,11 @@
ast::{
self, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
edit::{AstNodeEdit, IndentLevel},
- edit_in_place::{AttrsOwnerEdit, Indent, Removable},
+ edit_in_place::{AttrsOwnerEdit, Removable},
make,
syntax_factory::SyntaxFactory,
},
+ syntax_editor::SyntaxEditor,
ted,
};
@@ -178,6 +179,7 @@ fn has_def_name(item: &InFile<ast::AssocItem>) -> bool {
/// [`filter_assoc_items()`]), clones each item for update and applies path transformation to it,
/// then inserts into `impl_`. Returns the modified `impl_` and the first associated item that got
/// inserted.
+#[must_use]
pub fn add_trait_assoc_items_to_impl(
sema: &Semantics<'_, RootDatabase>,
config: &AssistConfig,
@@ -185,71 +187,66 @@ pub fn add_trait_assoc_items_to_impl(
trait_: hir::Trait,
impl_: &ast::Impl,
target_scope: &hir::SemanticsScope<'_>,
-) -> ast::AssocItem {
+) -> Vec<ast::AssocItem> {
let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1;
- let items = original_items.iter().map(|InFile { file_id, value: original_item }| {
- let cloned_item = {
- if let Some(macro_file) = file_id.macro_file() {
- let span_map = sema.db.expansion_span_map(macro_file);
- let item_prettified = prettify_macro_expansion(
- sema.db,
- original_item.syntax().clone(),
- &span_map,
- target_scope.krate().into(),
- );
- if let Some(formatted) = ast::AssocItem::cast(item_prettified) {
- return formatted;
- } else {
- stdx::never!("formatted `AssocItem` could not be cast back to `AssocItem`");
+ original_items
+ .iter()
+ .map(|InFile { file_id, value: original_item }| {
+ let mut cloned_item = {
+ if let Some(macro_file) = file_id.macro_file() {
+ let span_map = sema.db.expansion_span_map(macro_file);
+ let item_prettified = prettify_macro_expansion(
+ sema.db,
+ original_item.syntax().clone(),
+ &span_map,
+ target_scope.krate().into(),
+ );
+ if let Some(formatted) = ast::AssocItem::cast(item_prettified) {
+ return formatted;
+ } else {
+ stdx::never!("formatted `AssocItem` could not be cast back to `AssocItem`");
+ }
}
+ original_item.clone_for_update()
}
- original_item.clone_for_update()
- };
+ .reset_indent();
- if let Some(source_scope) = sema.scope(original_item.syntax()) {
- // FIXME: Paths in nested macros are not handled well. See
- // `add_missing_impl_members::paths_in_nested_macro_should_get_transformed` test.
- let transform =
- PathTransform::trait_impl(target_scope, &source_scope, trait_, impl_.clone());
- transform.apply(cloned_item.syntax());
- }
- cloned_item.remove_attrs_and_docs();
- cloned_item.reindent_to(new_indent_level);
- cloned_item
- });
-
- let assoc_item_list = impl_.get_or_create_assoc_item_list();
-
- let mut first_item = None;
- for item in items {
- first_item.get_or_insert_with(|| item.clone());
- match &item {
- ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
- let body = AstNodeEdit::indent(
- &make::block_expr(
- None,
- Some(match config.expr_fill_default {
- ExprFillDefaultMode::Todo => make::ext::expr_todo(),
- ExprFillDefaultMode::Underscore => make::ext::expr_underscore(),
- ExprFillDefaultMode::Default => make::ext::expr_todo(),
- }),
- ),
- new_indent_level,
- );
- ted::replace(fn_.get_or_create_body().syntax(), body.clone_for_update().syntax())
+ if let Some(source_scope) = sema.scope(original_item.syntax()) {
+ // FIXME: Paths in nested macros are not handled well. See
+ // `add_missing_impl_members::paths_in_nested_macro_should_get_transformed` test.
+ let transform =
+ PathTransform::trait_impl(target_scope, &source_scope, trait_, impl_.clone());
+ cloned_item = ast::AssocItem::cast(transform.apply(cloned_item.syntax())).unwrap();
}
- ast::AssocItem::TypeAlias(type_alias) => {
- if let Some(type_bound_list) = type_alias.type_bound_list() {
- type_bound_list.remove()
+ cloned_item.remove_attrs_and_docs();
+ cloned_item
+ })
+ .map(|item| {
+ match &item {
+ ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
+ let body = AstNodeEdit::indent(
+ &make::block_expr(
+ None,
+ Some(match config.expr_fill_default {
+ ExprFillDefaultMode::Todo => make::ext::expr_todo(),
+ ExprFillDefaultMode::Underscore => make::ext::expr_underscore(),
+ ExprFillDefaultMode::Default => make::ext::expr_todo(),
+ }),
+ ),
+ IndentLevel::single(),
+ );
+ ted::replace(fn_.get_or_create_body().syntax(), body.syntax());
}
+ ast::AssocItem::TypeAlias(type_alias) => {
+ if let Some(type_bound_list) = type_alias.type_bound_list() {
+ type_bound_list.remove()
+ }
+ }
+ _ => {}
}
- _ => {}
- }
-
- assoc_item_list.add_item(item)
- }
-
- first_item.unwrap()
+ AstNodeEdit::indent(&item, new_indent_level)
+ })
+ .collect()
}
pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
@@ -334,7 +331,7 @@ fn invert_special_case(make: &SyntaxFactory, expr: &ast::Expr) -> Option<ast::Ex
fn invert_special_case_legacy(expr: &ast::Expr) -> Option<ast::Expr> {
match expr {
ast::Expr::BinExpr(bin) => {
- let bin = bin.clone_for_update();
+ let bin = bin.clone_subtree();
let op_token = bin.op_token()?;
let rev_token = match op_token.kind() {
T![==] => T![!=],
@@ -350,8 +347,9 @@ fn invert_special_case_legacy(expr: &ast::Expr) -> Option<ast::Expr> {
);
}
};
- ted::replace(op_token, make::token(rev_token));
- Some(bin.into())
+ let mut bin_editor = SyntaxEditor::new(bin.syntax().clone());
+ bin_editor.replace(op_token, make::token(rev_token));
+ ast::Expr::cast(bin_editor.finish().new_root().clone())
}
ast::Expr::MethodCallExpr(mce) => {
let receiver = mce.receiver()?;
@@ -664,16 +662,23 @@ fn generate_impl_text_inner(
/// Generates the corresponding `impl Type {}` including type and lifetime
/// parameters.
+pub(crate) fn generate_impl_with_item(
+ adt: &ast::Adt,
+ body: Option<ast::AssocItemList>,
+) -> ast::Impl {
+ generate_impl_inner(false, adt, None, true, body)
+}
+
pub(crate) fn generate_impl(adt: &ast::Adt) -> ast::Impl {
- generate_impl_inner(adt, None, true)
+ generate_impl_inner(false, adt, None, true, None)
}
/// Generates the corresponding `impl <trait> for Type {}` including type
/// and lifetime parameters, with `<trait>` appended to `impl`'s generic parameters' bounds.
///
/// This is useful for traits like `PartialEq`, since `impl<T> PartialEq for U<T>` often requires `T: PartialEq`.
-pub(crate) fn generate_trait_impl(adt: &ast::Adt, trait_: ast::Type) -> ast::Impl {
- generate_impl_inner(adt, Some(trait_), true)
+pub(crate) fn generate_trait_impl(is_unsafe: bool, adt: &ast::Adt, trait_: ast::Type) -> ast::Impl {
+ generate_impl_inner(is_unsafe, adt, Some(trait_), true, None)
}
/// Generates the corresponding `impl <trait> for Type {}` including type
@@ -681,13 +686,15 @@ pub(crate) fn generate_trait_impl(adt: &ast::Adt, trait_: ast::Type) -> ast::Imp
///
/// This is useful for traits like `From<T>`, since `impl<T> From<T> for U<T>` doesn't require `T: From<T>`.
pub(crate) fn generate_trait_impl_intransitive(adt: &ast::Adt, trait_: ast::Type) -> ast::Impl {
- generate_impl_inner(adt, Some(trait_), false)
+ generate_impl_inner(false, adt, Some(trait_), false, None)
}
fn generate_impl_inner(
+ is_unsafe: bool,
adt: &ast::Adt,
trait_: Option<ast::Type>,
trait_is_transitive: bool,
+ body: Option<ast::AssocItemList>,
) -> ast::Impl {
// Ensure lifetime params are before type & const params
let generic_params = adt.generic_param_list().map(|generic_params| {
@@ -727,7 +734,7 @@ fn generate_impl_inner(
let impl_ = match trait_ {
Some(trait_) => make::impl_trait(
- false,
+ is_unsafe,
None,
None,
generic_params,
@@ -737,9 +744,9 @@ fn generate_impl_inner(
ty,
None,
adt.where_clause(),
- None,
+ body,
),
- None => make::impl_(generic_params, generic_args, ty, adt.where_clause(), None),
+ None => make::impl_(generic_params, generic_args, ty, adt.where_clause(), body),
}
.clone_for_update();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
index c58bdd9..87e90e8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
@@ -1,10 +1,7 @@
//! This module contains functions to generate default trait impl function bodies where possible.
use hir::TraitRef;
-use syntax::{
- ast::{self, AstNode, BinaryOp, CmpOp, HasName, LogicOp, edit::AstNodeEdit, make},
- ted,
-};
+use syntax::ast::{self, AstNode, BinaryOp, CmpOp, HasName, LogicOp, edit::AstNodeEdit, make};
/// Generate custom trait bodies without default implementation where possible.
///
@@ -18,21 +15,33 @@ pub(crate) fn gen_trait_fn_body(
trait_path: &ast::Path,
adt: &ast::Adt,
trait_ref: Option<TraitRef<'_>>,
-) -> Option<()> {
+) -> Option<ast::BlockExpr> {
+ let _ = func.body()?;
match trait_path.segment()?.name_ref()?.text().as_str() {
- "Clone" => gen_clone_impl(adt, func),
- "Debug" => gen_debug_impl(adt, func),
- "Default" => gen_default_impl(adt, func),
- "Hash" => gen_hash_impl(adt, func),
- "PartialEq" => gen_partial_eq(adt, func, trait_ref),
- "PartialOrd" => gen_partial_ord(adt, func, trait_ref),
+ "Clone" => {
+ stdx::always!(func.name().is_some_and(|name| name.text() == "clone"));
+ gen_clone_impl(adt)
+ }
+ "Debug" => gen_debug_impl(adt),
+ "Default" => gen_default_impl(adt),
+ "Hash" => {
+ stdx::always!(func.name().is_some_and(|name| name.text() == "hash"));
+ gen_hash_impl(adt)
+ }
+ "PartialEq" => {
+ stdx::always!(func.name().is_some_and(|name| name.text() == "eq"));
+ gen_partial_eq(adt, trait_ref)
+ }
+ "PartialOrd" => {
+ stdx::always!(func.name().is_some_and(|name| name.text() == "partial_cmp"));
+ gen_partial_ord(adt, trait_ref)
+ }
_ => None,
}
}
/// Generate a `Clone` impl based on the fields and members of the target type.
-fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
- stdx::always!(func.name().is_some_and(|name| name.text() == "clone"));
+fn gen_clone_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
fn gen_clone_call(target: ast::Expr) -> ast::Expr {
let method = make::name_ref("clone");
make::expr_method_call(target, method, make::arg_list(None)).into()
@@ -139,12 +148,11 @@ fn gen_clone_call(target: ast::Expr) -> ast::Expr {
}
};
let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
- ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
- Some(())
+ Some(body)
}
/// Generate a `Debug` impl based on the fields and members of the target type.
-fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
+fn gen_debug_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
let annotated_name = adt.name()?;
match adt {
// `Debug` cannot be derived for unions, so no default impl can be provided.
@@ -248,8 +256,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
let body = make::block_expr(None, Some(match_expr.into()));
let body = body.indent(ast::edit::IndentLevel(1));
- ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
- Some(())
+ Some(body)
}
ast::Adt::Struct(strukt) => {
@@ -296,14 +303,13 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
let method = make::name_ref("finish");
let expr = make::expr_method_call(expr, method, make::arg_list(None)).into();
let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
- ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
- Some(())
+ Some(body)
}
}
}
/// Generate a `Debug` impl based on the fields and members of the target type.
-fn gen_default_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
+fn gen_default_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
fn gen_default_call() -> Option<ast::Expr> {
let fn_name = make::ext::path_from_idents(["Default", "default"])?;
Some(make::expr_call(make::expr_path(fn_name), make::arg_list(None)).into())
@@ -342,15 +348,13 @@ fn gen_default_call() -> Option<ast::Expr> {
}
};
let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
- ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
- Some(())
+ Some(body)
}
}
}
/// Generate a `Hash` impl based on the fields and members of the target type.
-fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
- stdx::always!(func.name().is_some_and(|name| name.text() == "hash"));
+fn gen_hash_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
let method = make::name_ref("hash");
let arg = make::expr_path(make::ext::ident_path("state"));
@@ -400,13 +404,11 @@ fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
},
};
- ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
- Some(())
+ Some(body)
}
/// Generate a `PartialEq` impl based on the fields and members of the target type.
-fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef<'_>>) -> Option<()> {
- stdx::always!(func.name().is_some_and(|name| name.text() == "eq"));
+fn gen_partial_eq(adt: &ast::Adt, trait_ref: Option<TraitRef<'_>>) -> Option<ast::BlockExpr> {
fn gen_eq_chain(expr: Option<ast::Expr>, cmp: ast::Expr) -> Option<ast::Expr> {
match expr {
Some(expr) => Some(make::expr_bin_op(expr, BinaryOp::LogicOp(LogicOp::And), cmp)),
@@ -595,12 +597,10 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
},
};
- ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
- Some(())
+ Some(body)
}
-fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef<'_>>) -> Option<()> {
- stdx::always!(func.name().is_some_and(|name| name.text() == "partial_cmp"));
+fn gen_partial_ord(adt: &ast::Adt, trait_ref: Option<TraitRef<'_>>) -> Option<ast::BlockExpr> {
fn gen_partial_eq_match(match_target: ast::Expr) -> Option<ast::Stmt> {
let mut arms = vec![];
@@ -686,8 +686,7 @@ fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
},
};
- ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
- Some(())
+ Some(body)
}
fn make_discriminant() -> Option<ast::Expr> {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 975c2f0..bcf8c0e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -276,7 +276,7 @@ fn get_transformed_assoc_item(
let assoc_item = assoc_item.clone_for_update();
// FIXME: Paths in nested macros are not handled well. See
// `macro_generated_assoc_item2` test.
- transform.apply(assoc_item.syntax());
+ let assoc_item = ast::AssocItem::cast(transform.apply(assoc_item.syntax()))?;
assoc_item.remove_attrs_and_docs();
Some(assoc_item)
}
@@ -301,7 +301,7 @@ fn get_transformed_fn(
let fn_ = fn_.clone_for_update();
// FIXME: Paths in nested macros are not handled well. See
// `macro_generated_assoc_item2` test.
- transform.apply(fn_.syntax());
+ let fn_ = ast::Fn::cast(transform.apply(fn_.syntax()))?;
fn_.remove_attrs_and_docs();
match async_ {
AsyncSugaring::Desugar => {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
index 0ab880b..b7432d8 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
@@ -12,15 +12,16 @@
use syntax::{
NodeOrToken, SyntaxNode,
ast::{self, AstNode, HasGenericArgs, make},
- ted,
+ syntax_editor::{self, SyntaxEditor},
};
-#[derive(Default)]
+#[derive(Default, Debug)]
struct AstSubsts {
types_and_consts: Vec<TypeOrConst>,
lifetimes: Vec<ast::LifetimeArg>,
}
+#[derive(Debug)]
enum TypeOrConst {
Either(ast::TypeArg), // indistinguishable type or const param
Const(ast::ConstArg),
@@ -128,15 +129,18 @@ pub fn generic_transformation(
}
}
- pub fn apply(&self, syntax: &SyntaxNode) {
+ #[must_use]
+ pub fn apply(&self, syntax: &SyntaxNode) -> SyntaxNode {
self.build_ctx().apply(syntax)
}
- pub fn apply_all<'b>(&self, nodes: impl IntoIterator<Item = &'b SyntaxNode>) {
+ #[must_use]
+ pub fn apply_all<'b>(
+ &self,
+ nodes: impl IntoIterator<Item = &'b SyntaxNode>,
+ ) -> Vec<SyntaxNode> {
let ctx = self.build_ctx();
- for node in nodes {
- ctx.apply(node);
- }
+ nodes.into_iter().map(|node| ctx.apply(&node.clone())).collect()
}
fn prettify_target_node(&self, node: SyntaxNode) -> SyntaxNode {
@@ -236,7 +240,7 @@ fn build_ctx(&self) -> Ctx<'a> {
Some((k.name(db).display(db, target_edition).to_string(), v.lifetime()?))
})
.collect();
- let ctx = Ctx {
+ let mut ctx = Ctx {
type_substs,
const_substs,
lifetime_substs,
@@ -272,42 +276,75 @@ fn preorder_rev(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
}
impl Ctx<'_> {
- fn apply(&self, item: &SyntaxNode) {
+ fn apply(&self, item: &SyntaxNode) -> SyntaxNode {
// `transform_path` may update a node's parent and that would break the
// tree traversal. Thus all paths in the tree are collected into a vec
// so that such operation is safe.
- let paths = preorder_rev(item).filter_map(ast::Path::cast).collect::<Vec<_>>();
- for path in paths {
- self.transform_path(path);
- }
-
- preorder_rev(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
+ let item = self.transform_path(item).clone_subtree();
+ let mut editor = SyntaxEditor::new(item.clone());
+ preorder_rev(&item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) {
- ted::replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
+ editor
+ .replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
}
});
+
+ editor.finish().new_root().clone()
}
- fn transform_default_values(&self, defaulted_params: Vec<DefaultedParam>) {
+ fn transform_default_values(&mut self, defaulted_params: Vec<DefaultedParam>) {
// By now the default values are simply copied from where they are declared
// and should be transformed. As any value is allowed to refer to previous
// generic (both type and const) parameters, they should be all iterated left-to-right.
for param in defaulted_params {
- let value = match param {
- Either::Left(k) => self.type_substs.get(&k).unwrap().syntax(),
- Either::Right(k) => self.const_substs.get(&k).unwrap(),
+ let value = match ¶m {
+ Either::Left(k) => self.type_substs.get(k).unwrap().syntax(),
+ Either::Right(k) => self.const_substs.get(k).unwrap(),
};
// `transform_path` may update a node's parent and that would break the
// tree traversal. Thus all paths in the tree are collected into a vec
// so that such operation is safe.
- let paths = preorder_rev(value).filter_map(ast::Path::cast).collect::<Vec<_>>();
- for path in paths {
- self.transform_path(path);
+ let new_value = self.transform_path(value);
+ match param {
+ Either::Left(k) => {
+ self.type_substs.insert(k, ast::Type::cast(new_value.clone()).unwrap());
+ }
+ Either::Right(k) => {
+ self.const_substs.insert(k, new_value.clone());
+ }
}
}
}
- fn transform_path(&self, path: ast::Path) -> Option<()> {
+ fn transform_path(&self, path: &SyntaxNode) -> SyntaxNode {
+ fn find_child_paths(root_path: &SyntaxNode) -> Vec<ast::Path> {
+ let mut result = Vec::new();
+ for child in root_path.children() {
+ if let Some(child_path) = ast::Path::cast(child.clone()) {
+ result.push(child_path);
+ } else {
+ result.extend(find_child_paths(&child));
+ }
+ }
+ result
+ }
+ let root_path = path.clone_subtree();
+ let result = find_child_paths(&root_path);
+ let mut editor = SyntaxEditor::new(root_path.clone());
+ for sub_path in result {
+ let new = self.transform_path(sub_path.syntax());
+ editor.replace(sub_path.syntax(), new);
+ }
+ let update_sub_item = editor.finish().new_root().clone().clone_subtree();
+ let item = find_child_paths(&update_sub_item);
+ let mut editor = SyntaxEditor::new(update_sub_item);
+ for sub_path in item {
+ self.transform_path_(&mut editor, &sub_path);
+ }
+ editor.finish().new_root().clone()
+ }
+
+ fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option<()> {
if path.qualifier().is_some() {
return None;
}
@@ -319,8 +356,7 @@ fn transform_path(&self, path: ast::Path) -> Option<()> {
// don't try to qualify sole `self` either, they are usually locals, but are returned as modules due to namespace clashing
return None;
}
-
- let resolution = self.source_scope.speculative_resolve(&path)?;
+ let resolution = self.source_scope.speculative_resolve(path)?;
match resolution {
hir::PathResolution::TypeParam(tp) => {
@@ -360,12 +396,12 @@ fn transform_path(&self, path: ast::Path) -> Option<()> {
let segment = make::path_segment_ty(subst.clone(), trait_ref);
let qualified = make::path_from_segments(std::iter::once(segment), false);
- ted::replace(path.syntax(), qualified.clone_for_update().syntax());
+ editor.replace(path.syntax(), qualified.clone_for_update().syntax());
} else if let Some(path_ty) = ast::PathType::cast(parent) {
let old = path_ty.syntax();
if old.parent().is_some() {
- ted::replace(old, subst.clone_subtree().clone_for_update().syntax());
+ editor.replace(old, subst.clone_subtree().clone_for_update().syntax());
} else {
// Some `path_ty` has no parent, especially ones made for default value
// of type parameters.
@@ -377,13 +413,13 @@ fn transform_path(&self, path: ast::Path) -> Option<()> {
}
let start = path_ty.syntax().first_child().map(NodeOrToken::Node)?;
let end = path_ty.syntax().last_child().map(NodeOrToken::Node)?;
- ted::replace_all(
+ editor.replace_all(
start..=end,
new.syntax().children().map(NodeOrToken::Node).collect::<Vec<_>>(),
);
}
} else {
- ted::replace(
+ editor.replace(
path.syntax(),
subst.clone_subtree().clone_for_update().syntax(),
);
@@ -409,17 +445,28 @@ fn transform_path(&self, path: ast::Path) -> Option<()> {
};
let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?;
let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update();
+ let mut res_editor = SyntaxEditor::new(res.syntax().clone_subtree());
if let Some(args) = path.segment().and_then(|it| it.generic_arg_list()) {
if let Some(segment) = res.segment() {
- let old = segment.get_or_create_generic_arg_list();
- ted::replace(old.syntax(), args.clone_subtree().syntax().clone_for_update())
+ if let Some(old) = segment.generic_arg_list() {
+ res_editor.replace(
+ old.syntax(),
+ args.clone_subtree().syntax().clone_for_update(),
+ )
+ } else {
+ res_editor.insert(
+ syntax_editor::Position::last_child_of(segment.syntax()),
+ args.clone_subtree().syntax().clone_for_update(),
+ );
+ }
}
}
- ted::replace(path.syntax(), res.syntax())
+ let res = res_editor.finish().new_root().clone();
+ editor.replace(path.syntax().clone(), res);
}
hir::PathResolution::ConstParam(cp) => {
if let Some(subst) = self.const_substs.get(&cp) {
- ted::replace(path.syntax(), subst.clone_subtree().clone_for_update());
+ editor.replace(path.syntax(), subst.clone_subtree().clone_for_update());
}
}
hir::PathResolution::SelfType(imp) => {
@@ -456,13 +503,13 @@ fn transform_path(&self, path: ast::Path) -> Option<()> {
mod_path_to_ast(&found_path, self.target_edition).qualifier()
{
let res = make::path_concat(qual, path_ty.path()?).clone_for_update();
- ted::replace(path.syntax(), res.syntax());
+ editor.replace(path.syntax(), res.syntax());
return Some(());
}
}
}
- ted::replace(path.syntax(), ast_ty.syntax());
+ editor.replace(path.syntax(), ast_ty.syntax());
}
hir::PathResolution::Local(_)
| hir::PathResolution::Def(_)
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
index f20b6de..e31367f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
@@ -131,4 +131,28 @@ fn foo(v: Enum<()>) {
"#,
);
}
+
+ #[test]
+ fn regression_20259() {
+ check_diagnostics(
+ r#"
+//- minicore: deref
+use core::ops::Deref;
+
+struct Foo<T>(T);
+
+impl<T> Deref for Foo<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+fn test(x: Foo<(i32, bool)>) {
+ let (_a, _b): &(i32, bool) = &x;
+}
+"#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
index 698fd14..1901bcc 100755
--- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
@@ -73,11 +73,13 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
}
if fn_node.body().is_some() {
+ // Get the actual start of the function (excluding doc comments)
+ let fn_start = fn_node
+ .fn_token()
+ .map(|token| token.text_range().start())
+ .unwrap_or(node.text_range().start());
res.push(Fold {
- range: TextRange::new(
- node.text_range().start(),
- node.text_range().end(),
- ),
+ range: TextRange::new(fn_start, node.text_range().end()),
kind: FoldKind::Function,
});
continue;
@@ -688,4 +690,21 @@ fn fold_generics() {
"#,
)
}
+
+ #[test]
+ fn test_fold_doc_comments_with_multiline_paramlist_function() {
+ check(
+ r#"
+<fold comment>/// A very very very very very very very very very very very very very very very
+/// very very very long description</fold>
+<fold function>fn foo<fold arglist>(
+ very_long_parameter_name: u32,
+ another_very_long_parameter_name: u32,
+ third_very_long_param: u32,
+)</fold> <fold block>{
+ todo!()
+}</fold></fold>
+"#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs
index 0069452..49fec0a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs
@@ -77,17 +77,18 @@ pub(super) fn fn_ptr_hints(
return None;
}
- let parent_for_type = func
+ let parent_for_binder = func
.syntax()
.ancestors()
.skip(1)
.take_while(|it| matches!(it.kind(), SyntaxKind::PAREN_TYPE | SyntaxKind::FOR_TYPE))
- .find_map(ast::ForType::cast);
+ .find_map(ast::ForType::cast)
+ .and_then(|it| it.for_binder());
let param_list = func.param_list()?;
- let generic_param_list = parent_for_type.as_ref().and_then(|it| it.generic_param_list());
+ let generic_param_list = parent_for_binder.as_ref().and_then(|it| it.generic_param_list());
let ret_type = func.ret_type();
- let for_kw = parent_for_type.as_ref().and_then(|it| it.for_token());
+ let for_kw = parent_for_binder.as_ref().and_then(|it| it.for_token());
hints_(
acc,
ctx,
@@ -143,15 +144,16 @@ pub(super) fn fn_path_hints(
// FIXME: Support general path types
let (param_list, ret_type) = func.path().as_ref().and_then(path_as_fn)?;
- let parent_for_type = func
+ let parent_for_binder = func
.syntax()
.ancestors()
.skip(1)
.take_while(|it| matches!(it.kind(), SyntaxKind::PAREN_TYPE | SyntaxKind::FOR_TYPE))
- .find_map(ast::ForType::cast);
+ .find_map(ast::ForType::cast)
+ .and_then(|it| it.for_binder());
- let generic_param_list = parent_for_type.as_ref().and_then(|it| it.generic_param_list());
- let for_kw = parent_for_type.as_ref().and_then(|it| it.for_token());
+ let generic_param_list = parent_for_binder.as_ref().and_then(|it| it.generic_param_list());
+ let for_kw = parent_for_binder.as_ref().and_then(|it| it.for_token());
hints_(
acc,
ctx,
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index fb84e8e..a07c647 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -12,6 +12,7 @@
source_change::SourceChangeBuilder,
};
use itertools::Itertools;
+use std::fmt::Write;
use stdx::{always, never};
use syntax::{AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize, ast};
@@ -459,35 +460,22 @@ fn rename_self_to_param(
}
fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: String) -> Option<TextEdit> {
- fn target_type_name(impl_def: &ast::Impl) -> Option<String> {
- if let Some(ast::Type::PathType(p)) = impl_def.self_ty() {
- return Some(p.path()?.segment()?.name_ref()?.text().to_string());
- }
- None
+ let mut replacement_text = new_name;
+ replacement_text.push_str(": ");
+
+ if self_param.amp_token().is_some() {
+ replacement_text.push('&');
+ }
+ if let Some(lifetime) = self_param.lifetime() {
+ write!(replacement_text, "{lifetime} ").unwrap();
+ }
+ if self_param.amp_token().and(self_param.mut_token()).is_some() {
+ replacement_text.push_str("mut ");
}
- match self_param.syntax().ancestors().find_map(ast::Impl::cast) {
- Some(impl_def) => {
- let type_name = target_type_name(&impl_def)?;
+ replacement_text.push_str("Self");
- let mut replacement_text = new_name;
- replacement_text.push_str(": ");
- match (self_param.amp_token(), self_param.mut_token()) {
- (Some(_), None) => replacement_text.push('&'),
- (Some(_), Some(_)) => replacement_text.push_str("&mut "),
- (_, _) => (),
- };
- replacement_text.push_str(type_name.as_str());
-
- Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text))
- }
- None => {
- cov_mark::hit!(rename_self_outside_of_methods);
- let mut replacement_text = new_name;
- replacement_text.push_str(": _");
- Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text))
- }
- }
+ Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text))
}
#[cfg(test)]
@@ -2069,7 +2057,7 @@ fn f(&mut $0self) -> i32 {
struct Foo { i: i32 }
impl Foo {
- fn f(foo: &mut Foo) -> i32 {
+ fn f(foo: &mut Self) -> i32 {
foo.i
}
}
@@ -2095,7 +2083,33 @@ fn f($0self) -> i32 {
struct Foo { i: i32 }
impl Foo {
- fn f(foo: Foo) -> i32 {
+ fn f(foo: Self) -> i32 {
+ foo.i
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn test_owned_self_to_parameter_with_lifetime() {
+ cov_mark::check!(rename_self_to_param);
+ check(
+ "foo",
+ r#"
+struct Foo<'a> { i: &'a i32 }
+
+impl<'a> Foo<'a> {
+ fn f(&'a $0self) -> i32 {
+ self.i
+ }
+}
+"#,
+ r#"
+struct Foo<'a> { i: &'a i32 }
+
+impl<'a> Foo<'a> {
+ fn f(foo: &'a Self) -> i32 {
foo.i
}
}
@@ -2105,7 +2119,6 @@ fn f(foo: Foo) -> i32 {
#[test]
fn test_self_outside_of_methods() {
- cov_mark::check!(rename_self_outside_of_methods);
check(
"foo",
r#"
@@ -2114,7 +2127,7 @@ fn f($0self) -> i32 {
}
"#,
r#"
-fn f(foo: _) -> i32 {
+fn f(foo: Self) -> i32 {
foo.i
}
"#,
@@ -2159,7 +2172,7 @@ fn f(&self) -> i32 {
struct Foo { i: i32 }
impl Foo {
- fn f(foo: &Foo) -> i32 {
+ fn f(foo: &Self) -> i32 {
let self_var = 1;
foo.i
}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
index 7665656..ed8a91c 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
@@ -572,9 +572,7 @@ fn closure_expr(p: &mut Parser<'_>) -> CompletedMarker {
// test closure_binder
// fn main() { for<'a> || (); }
if p.at(T![for]) {
- let b = p.start();
types::for_binder(p);
- b.complete(p, CLOSURE_BINDER);
}
// test const_closure
// fn main() { let cl = const || _ = 0; }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
index 55c5dc4..cb1b59f 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
@@ -13,7 +13,7 @@ pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) {
// test_err generic_param_list_recover
// fn f<T: Clone,, U:, V>() {}
-fn generic_param_list(p: &mut Parser<'_>) {
+pub(super) fn generic_param_list(p: &mut Parser<'_>) {
assert!(p.at(T![<]));
let m = p.start();
delimited(
@@ -147,7 +147,15 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
let has_paren = p.eat(T!['(']);
match p.current() {
LIFETIME_IDENT => lifetime(p),
- T![for] => types::for_type(p, false),
+ // test for_binder_bound
+ // fn foo<T: for<'a> [const] async Trait>() {}
+ T![for] => {
+ types::for_binder(p);
+ if path_type_bound(p).is_err() {
+ m.abandon(p);
+ return false;
+ }
+ }
// test precise_capturing
// fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {}
@@ -180,44 +188,8 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
p.bump_any();
types::for_type(p, false)
}
- current => {
- match current {
- T![?] => p.bump_any(),
- T![~] => {
- p.bump_any();
- p.expect(T![const]);
- }
- T!['['] => {
- p.bump_any();
- p.expect(T![const]);
- p.expect(T![']']);
- }
- // test const_trait_bound
- // const fn foo(_: impl const Trait) {}
- T![const] => {
- p.bump_any();
- }
- // test async_trait_bound
- // fn async_foo(_: impl async Fn(&i32)) {}
- T![async] => {
- p.bump_any();
- }
- _ => (),
- }
- if paths::is_use_path_start(p) {
- types::path_type_bounds(p, false);
- // test_err type_bounds_macro_call_recovery
- // fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {}
- if p.at(T![!]) {
- let m = p.start();
- p.bump(T![!]);
- p.error("unexpected `!` in type path, macro calls are not allowed here");
- if p.at_ts(TokenSet::new(&[T!['{'], T!['['], T!['(']])) {
- items::token_tree(p);
- }
- m.complete(p, ERROR);
- }
- } else {
+ _ => {
+ if path_type_bound(p).is_err() {
m.abandon(p);
return false;
}
@@ -231,6 +203,43 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
true
}
+fn path_type_bound(p: &mut Parser<'_>) -> Result<(), ()> {
+ if p.eat(T![~]) {
+ p.expect(T![const]);
+ } else if p.eat(T!['[']) {
+ // test maybe_const_trait_bound
+ // const fn foo(_: impl [const] Trait) {}
+ p.expect(T![const]);
+ p.expect(T![']']);
+ } else {
+ // test const_trait_bound
+ // const fn foo(_: impl const Trait) {}
+ p.eat(T![const]);
+ }
+ // test async_trait_bound
+ // fn async_foo(_: impl async Fn(&i32)) {}
+ p.eat(T![async]);
+ p.eat(T![?]);
+
+ if paths::is_use_path_start(p) {
+ types::path_type_bounds(p, false);
+ // test_err type_bounds_macro_call_recovery
+ // fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {}
+ if p.at(T![!]) {
+ let m = p.start();
+ p.bump(T![!]);
+ p.error("unexpected `!` in type path, macro calls are not allowed here");
+ if p.at_ts(TokenSet::new(&[T!['{'], T!['['], T!['(']])) {
+ items::token_tree(p);
+ }
+ m.complete(p, ERROR);
+ }
+ Ok(())
+ } else {
+ Err(())
+ }
+}
+
// test where_clause
// fn foo()
// where
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
index 908440b..a7e97c5 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
@@ -249,13 +249,14 @@ fn fn_ptr_type(p: &mut Parser<'_>) {
}
pub(super) fn for_binder(p: &mut Parser<'_>) {
- assert!(p.at(T![for]));
+ let m = p.start();
p.bump(T![for]);
if p.at(T![<]) {
- generic_params::opt_generic_param_list(p);
+ generic_params::generic_param_list(p);
} else {
p.error("expected `<`");
}
+ m.complete(p, FOR_BINDER);
}
// test for_type
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
index 12a13ca..3a8041d 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -185,7 +185,6 @@ pub enum SyntaxKind {
BREAK_EXPR,
CALL_EXPR,
CAST_EXPR,
- CLOSURE_BINDER,
CLOSURE_EXPR,
CONST,
CONST_ARG,
@@ -203,6 +202,7 @@ pub enum SyntaxKind {
FN_PTR_TYPE,
FORMAT_ARGS_ARG,
FORMAT_ARGS_EXPR,
+ FOR_BINDER,
FOR_EXPR,
FOR_TYPE,
GENERIC_ARG_LIST,
@@ -358,7 +358,6 @@ pub const fn text(self) -> &'static str {
| BREAK_EXPR
| CALL_EXPR
| CAST_EXPR
- | CLOSURE_BINDER
| CLOSURE_EXPR
| CONST
| CONST_ARG
@@ -376,6 +375,7 @@ pub const fn text(self) -> &'static str {
| FN_PTR_TYPE
| FORMAT_ARGS_ARG
| FORMAT_ARGS_EXPR
+ | FOR_BINDER
| FOR_EXPR
| FOR_TYPE
| GENERIC_ARG_LIST
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
index cef7b0e..c642e1a 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
@@ -253,6 +253,10 @@ fn fn_pointer_unnamed_arg() {
run_and_expect_no_errors("test_data/parser/inline/ok/fn_pointer_unnamed_arg.rs");
}
#[test]
+ fn for_binder_bound() {
+ run_and_expect_no_errors("test_data/parser/inline/ok/for_binder_bound.rs");
+ }
+ #[test]
fn for_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/for_expr.rs"); }
#[test]
fn for_range_from() {
@@ -402,6 +406,10 @@ fn match_arms_outer_attributes() {
#[test]
fn match_guard() { run_and_expect_no_errors("test_data/parser/inline/ok/match_guard.rs"); }
#[test]
+ fn maybe_const_trait_bound() {
+ run_and_expect_no_errors("test_data/parser/inline/ok/maybe_const_trait_bound.rs");
+ }
+ #[test]
fn metas() { run_and_expect_no_errors("test_data/parser/inline/ok/metas.rs"); }
#[test]
fn method_call_expr() {
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast
index 025c12e..2fd1725 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast
@@ -37,7 +37,7 @@
WHITESPACE " "
TYPE_BOUND
L_PAREN "("
- FOR_TYPE
+ FOR_BINDER
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
@@ -45,18 +45,18 @@
LIFETIME
LIFETIME_IDENT "'a"
R_ANGLE ">"
- WHITESPACE " "
- PATH_TYPE
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "Trait"
- GENERIC_ARG_LIST
- L_ANGLE "<"
- LIFETIME_ARG
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
R_PAREN ")"
R_ANGLE ">"
PARAM_LIST
@@ -124,7 +124,7 @@
WHITESPACE " "
TYPE_BOUND
L_PAREN "("
- FOR_TYPE
+ FOR_BINDER
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
@@ -132,18 +132,18 @@
LIFETIME
LIFETIME_IDENT "'a"
R_ANGLE ">"
- WHITESPACE " "
- PATH_TYPE
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "Trait"
- GENERIC_ARG_LIST
- L_ANGLE "<"
- LIFETIME_ARG
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
R_PAREN ")"
ERROR
R_ANGLE ">"
@@ -186,7 +186,7 @@
TUPLE_EXPR
L_PAREN "("
CLOSURE_EXPR
- CLOSURE_BINDER
+ FOR_BINDER
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
@@ -243,13 +243,14 @@
PAREN_TYPE
L_PAREN "("
FOR_TYPE
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
PATH_TYPE
PATH
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast
index 674c8d5..3768a55 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast
@@ -12,13 +12,14 @@
WHERE_KW "where"
WHITESPACE " "
WHERE_PRED
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE "\n"
BLOCK_EXPR
STMT_LIST
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast
index cb4fb16..9c4ee6f 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast
@@ -8,13 +8,14 @@
EQ "="
WHITESPACE " "
FOR_TYPE
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
REF_TYPE
AMP "&"
@@ -37,13 +38,14 @@
EQ "="
WHITESPACE " "
FOR_TYPE
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
TUPLE_TYPE
L_PAREN "("
@@ -70,13 +72,14 @@
EQ "="
WHITESPACE " "
FOR_TYPE
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
SLICE_TYPE
L_BRACK "["
@@ -97,22 +100,24 @@
EQ "="
WHITESPACE " "
FOR_TYPE
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
- WHITESPACE " "
- FOR_TYPE
+ FOR_BINDER
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
LIFETIME_PARAM
LIFETIME
- LIFETIME_IDENT "'b"
+ LIFETIME_IDENT "'a"
R_ANGLE ">"
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ R_ANGLE ">"
WHITESPACE " "
FN_PTR_TYPE
FN_KW "fn"
@@ -164,31 +169,34 @@
WHERE_KW "where"
WHITESPACE "\n "
WHERE_PRED
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
- WHITESPACE " "
- FOR_TYPE
+ FOR_BINDER
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
LIFETIME_PARAM
LIFETIME
- LIFETIME_IDENT "'b"
+ LIFETIME_IDENT "'a"
R_ANGLE ">"
- WHITESPACE " "
- FOR_TYPE
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_BINDER
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
LIFETIME_PARAM
LIFETIME
- LIFETIME_IDENT "'c"
+ LIFETIME_IDENT "'b"
R_ANGLE ">"
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'c"
+ R_ANGLE ">"
WHITESPACE " "
FN_PTR_TYPE
FN_KW "fn"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rast
index c04dbe1..c96ccf7 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rast
@@ -14,7 +14,7 @@
WHITESPACE " "
EXPR_STMT
CLOSURE_EXPR
- CLOSURE_BINDER
+ FOR_BINDER
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rast
index dcc66dc..6578809 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rast
@@ -103,7 +103,7 @@
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
- FOR_TYPE
+ FOR_BINDER
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
@@ -111,12 +111,12 @@
LIFETIME
LIFETIME_IDENT "'a"
R_ANGLE ">"
- WHITESPACE " "
- PATH_TYPE
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "Path"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Path"
SEMICOLON ";"
WHITESPACE "\n"
TYPE_ALIAS
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/for_binder_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/for_binder_bound.rast
new file mode 100644
index 0000000..17dbbf3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/for_binder_bound.rast
@@ -0,0 +1,45 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ L_BRACK "["
+ CONST_KW "const"
+ R_BRACK "]"
+ WHITESPACE " "
+ ASYNC_KW "async"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/for_binder_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/for_binder_bound.rs
new file mode 100644
index 0000000..427cf55
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/for_binder_bound.rs
@@ -0,0 +1 @@
+fn foo<T: for<'a> [const] async Trait>() {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/for_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/for_type.rast
index 7600457..5862305 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/for_type.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/for_type.rast
@@ -8,13 +8,14 @@
EQ "="
WHITESPACE " "
FOR_TYPE
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
FN_PTR_TYPE
FN_KW "fn"
@@ -39,13 +40,14 @@
EQ "="
WHITESPACE " "
FOR_TYPE
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
FN_PTR_TYPE
UNSAFE_KW "unsafe"
@@ -86,13 +88,14 @@
EQ "="
WHITESPACE " "
FOR_TYPE
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
PATH_TYPE
PATH
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lambda_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lambda_expr.rast
index ea401d2..bf24a57 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lambda_expr.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lambda_expr.rast
@@ -202,7 +202,7 @@
WHITESPACE "\n "
EXPR_STMT
CLOSURE_EXPR
- CLOSURE_BINDER
+ FOR_BINDER
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
@@ -223,7 +223,7 @@
WHITESPACE "\n "
EXPR_STMT
CLOSURE_EXPR
- CLOSURE_BINDER
+ FOR_BINDER
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/maybe_const_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/maybe_const_trait_bound.rast
new file mode 100644
index 0000000..8d12f81
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/maybe_const_trait_bound.rast
@@ -0,0 +1,36 @@
+SOURCE_FILE
+ FN
+ CONST_KW "const"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ IMPL_TRAIT_TYPE
+ IMPL_KW "impl"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ L_BRACK "["
+ CONST_KW "const"
+ R_BRACK "]"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/maybe_const_trait_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/maybe_const_trait_bound.rs
new file mode 100644
index 0000000..e1da920
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/maybe_const_trait_bound.rs
@@ -0,0 +1 @@
+const fn foo(_: impl [const] Trait) {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/no_dyn_trait_leading_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/no_dyn_trait_leading_for.rast
index 30a2842..6afa061 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/no_dyn_trait_leading_for.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/no_dyn_trait_leading_for.rast
@@ -11,13 +11,14 @@
TYPE_BOUND_LIST
TYPE_BOUND
FOR_TYPE
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
PATH_TYPE
PATH
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rast
index 56e2d10..cb29615 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rast
@@ -29,10 +29,11 @@
TYPE_BOUND
QUESTION "?"
FOR_TYPE
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ R_ANGLE ">"
WHITESPACE " "
PATH_TYPE
PATH
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast
index 0cc365e..b10b953 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast
@@ -18,13 +18,14 @@
WHERE_KW "where"
WHITESPACE "\n "
WHERE_PRED
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
PATH_TYPE
PATH
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rast
index 86f6af9..dcaf58f 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rast
@@ -36,7 +36,7 @@
PLUS "+"
WHITESPACE " "
TYPE_BOUND
- FOR_TYPE
+ FOR_BINDER
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
@@ -44,18 +44,18 @@
LIFETIME
LIFETIME_IDENT "'de"
R_ANGLE ">"
- WHITESPACE " "
- PATH_TYPE
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "Deserialize"
- GENERIC_ARG_LIST
- L_ANGLE "<"
- LIFETIME_ARG
- LIFETIME
- LIFETIME_IDENT "'de"
- R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Deserialize"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'de"
+ R_ANGLE ">"
WHITESPACE " "
PLUS "+"
WHITESPACE " "
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast
index 8bf1090..5cef4df 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast
@@ -18,13 +18,14 @@
WHERE_KW "where"
WHITESPACE "\n "
WHERE_PRED
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
PATH_TYPE
PATH
@@ -81,13 +82,14 @@
WHERE_KW "where"
WHITESPACE "\n "
WHERE_PRED
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
REF_TYPE
AMP "&"
@@ -135,13 +137,14 @@
WHERE_KW "where"
WHITESPACE "\n "
WHERE_PRED
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
PAREN_TYPE
L_PAREN "("
@@ -206,13 +209,14 @@
WHERE_KW "where"
WHITESPACE "\n "
WHERE_PRED
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
SLICE_TYPE
L_BRACK "["
@@ -276,13 +280,14 @@
WHERE_KW "where"
WHITESPACE "\n "
WHERE_PRED
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
WHITESPACE " "
PATH_TYPE
PATH
@@ -349,22 +354,24 @@
WHERE_KW "where"
WHITESPACE "\n "
WHERE_PRED
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
- WHITESPACE " "
- FOR_TYPE
+ FOR_BINDER
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
LIFETIME_PARAM
LIFETIME
- LIFETIME_IDENT "'b"
+ LIFETIME_IDENT "'a"
R_ANGLE ">"
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_BINDER
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ R_ANGLE ">"
WHITESPACE " "
FN_PTR_TYPE
FN_KW "fn"
diff --git a/src/tools/rust-analyzer/crates/project-model/Cargo.toml b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
index 27fe9f7..0dbb309 100644
--- a/src/tools/rust-analyzer/crates/project-model/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
@@ -20,6 +20,7 @@
serde_json.workspace = true
serde.workspace = true
serde_derive.workspace = true
+temp-dir.workspace = true
tracing.workspace = true
triomphe.workspace = true
la-arena.workspace = true
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
index 499caa6..5bea74b 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
@@ -16,11 +16,13 @@
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
use rustc_hash::{FxHashMap, FxHashSet};
use serde::Deserialize as _;
+use stdx::never;
use toolchain::Tool;
use crate::{
CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, ManifestPath, Package, Sysroot,
- TargetKind, utf8_stdout,
+ TargetKind, cargo_config_file::make_lockfile_copy,
+ cargo_workspace::MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH, utf8_stdout,
};
/// Output of the build script and proc-macro building steps for a workspace.
@@ -30,6 +32,15 @@ pub struct WorkspaceBuildScripts {
error: Option<String>,
}
+#[derive(Debug, Clone, Default, PartialEq, Eq)]
+pub enum ProcMacroDylibPath {
+ Path(AbsPathBuf),
+ DylibNotFound,
+ NotProcMacro,
+ #[default]
+ NotBuilt,
+}
+
/// Output of the build script and proc-macro building step for a concrete package.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub(crate) struct BuildScriptOutput {
@@ -43,7 +54,7 @@ pub(crate) struct BuildScriptOutput {
/// Directory where a build script might place its output.
pub(crate) out_dir: Option<AbsPathBuf>,
/// Path to the proc-macro library file if this package exposes proc-macros.
- pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>,
+ pub(crate) proc_macro_dylib_path: ProcMacroDylibPath,
}
impl BuildScriptOutput {
@@ -51,7 +62,10 @@ fn is_empty(&self) -> bool {
self.cfgs.is_empty()
&& self.envs.is_empty()
&& self.out_dir.is_none()
- && self.proc_macro_dylib_path.is_none()
+ && matches!(
+ self.proc_macro_dylib_path,
+ ProcMacroDylibPath::NotBuilt | ProcMacroDylibPath::NotProcMacro
+ )
}
}
@@ -67,7 +81,7 @@ pub(crate) fn run_for_workspace(
let current_dir = workspace.workspace_root();
let allowed_features = workspace.workspace_features();
- let cmd = Self::build_command(
+ let (_guard, cmd) = Self::build_command(
config,
&allowed_features,
workspace.manifest_path(),
@@ -88,7 +102,7 @@ pub(crate) fn run_once(
) -> io::Result<Vec<WorkspaceBuildScripts>> {
assert_eq!(config.invocation_strategy, InvocationStrategy::Once);
- let cmd = Self::build_command(
+ let (_guard, cmd) = Self::build_command(
config,
&Default::default(),
// This is not gonna be used anyways, so just construct a dummy here
@@ -126,6 +140,8 @@ pub(crate) fn run_once(
|package, cb| {
if let Some(&(package, workspace)) = by_id.get(package) {
cb(&workspaces[workspace][package].name, &mut res[workspace].outputs[package]);
+ } else {
+ never!("Received compiler message for unknown package: {}", package);
}
},
progress,
@@ -140,12 +156,9 @@ pub(crate) fn run_once(
if tracing::enabled!(tracing::Level::INFO) {
for (idx, workspace) in workspaces.iter().enumerate() {
for package in workspace.packages() {
- let package_build_data = &mut res[idx].outputs[package];
+ let package_build_data: &mut BuildScriptOutput = &mut res[idx].outputs[package];
if !package_build_data.is_empty() {
- tracing::info!(
- "{}: {package_build_data:?}",
- workspace[package].manifest.parent(),
- );
+ tracing::info!("{}: {package_build_data:?}", workspace[package].manifest,);
}
}
}
@@ -198,10 +211,33 @@ pub(crate) fn rustc_crates(
let path = dir_entry.path();
let extension = path.extension()?;
if extension == std::env::consts::DLL_EXTENSION {
- let name = path.file_stem()?.to_str()?.split_once('-')?.0.to_owned();
- let path = AbsPathBuf::try_from(Utf8PathBuf::from_path_buf(path).ok()?)
- .ok()?;
- return Some((name, path));
+ let name = path
+ .file_stem()?
+ .to_str()?
+ .split_once('-')?
+ .0
+ .trim_start_matches("lib")
+ .to_owned();
+ let path = match Utf8PathBuf::from_path_buf(path) {
+ Ok(path) => path,
+ Err(path) => {
+ tracing::warn!(
+ "Proc-macro dylib path contains non-UTF8 characters: {:?}",
+ path.display()
+ );
+ return None;
+ }
+ };
+ return match AbsPathBuf::try_from(path) {
+ Ok(path) => Some((name, path)),
+ Err(path) => {
+ tracing::error!(
+ "proc-macro dylib path is not absolute: {:?}",
+ path
+ );
+ None
+ }
+ };
}
}
None
@@ -209,28 +245,24 @@ pub(crate) fn rustc_crates(
.collect();
for p in rustc.packages() {
let package = &rustc[p];
- if package
- .targets
- .iter()
- .any(|&it| matches!(rustc[it].kind, TargetKind::Lib { is_proc_macro: true }))
- {
- if let Some((_, path)) = proc_macro_dylibs
- .iter()
- .find(|(name, _)| *name.trim_start_matches("lib") == package.name)
- {
- bs.outputs[p].proc_macro_dylib_path = Some(path.clone());
+ bs.outputs[p].proc_macro_dylib_path =
+ if package.targets.iter().any(|&it| {
+ matches!(rustc[it].kind, TargetKind::Lib { is_proc_macro: true })
+ }) {
+ match proc_macro_dylibs.iter().find(|(name, _)| *name == package.name) {
+ Some((_, path)) => ProcMacroDylibPath::Path(path.clone()),
+ _ => ProcMacroDylibPath::DylibNotFound,
+ }
+ } else {
+ ProcMacroDylibPath::NotProcMacro
}
- }
}
if tracing::enabled!(tracing::Level::INFO) {
for package in rustc.packages() {
let package_build_data = &bs.outputs[package];
if !package_build_data.is_empty() {
- tracing::info!(
- "{}: {package_build_data:?}",
- rustc[package].manifest.parent(),
- );
+ tracing::info!("{}: {package_build_data:?}", rustc[package].manifest,);
}
}
}
@@ -263,6 +295,12 @@ fn run_per_ws(
|package, cb| {
if let Some(&package) = by_id.get(package) {
cb(&workspace[package].name, &mut outputs[package]);
+ } else {
+ never!(
+ "Received compiler message for unknown package: {}\n {}",
+ package,
+ by_id.keys().join(", ")
+ );
}
},
progress,
@@ -272,10 +310,7 @@ fn run_per_ws(
for package in workspace.packages() {
let package_build_data = &outputs[package];
if !package_build_data.is_empty() {
- tracing::info!(
- "{}: {package_build_data:?}",
- workspace[package].manifest.parent(),
- );
+ tracing::info!("{}: {package_build_data:?}", workspace[package].manifest,);
}
}
}
@@ -348,15 +383,23 @@ fn run_command(
progress(format!(
"building compile-time-deps: proc-macro {name} built"
));
- if message.target.kind.contains(&cargo_metadata::TargetKind::ProcMacro)
+ if data.proc_macro_dylib_path == ProcMacroDylibPath::NotBuilt {
+ data.proc_macro_dylib_path = ProcMacroDylibPath::NotProcMacro;
+ }
+ if !matches!(data.proc_macro_dylib_path, ProcMacroDylibPath::Path(_))
+ && message
+ .target
+ .kind
+ .contains(&cargo_metadata::TargetKind::ProcMacro)
{
- // Skip rmeta file
- if let Some(filename) =
- message.filenames.iter().find(|file| is_dylib(file))
- {
- let filename = AbsPath::assert(filename);
- data.proc_macro_dylib_path = Some(filename.to_owned());
- }
+ data.proc_macro_dylib_path =
+ match message.filenames.iter().find(|file| is_dylib(file)) {
+ Some(filename) => {
+ let filename = AbsPath::assert(filename);
+ ProcMacroDylibPath::Path(filename.to_owned())
+ }
+ None => ProcMacroDylibPath::DylibNotFound,
+ };
}
});
}
@@ -393,14 +436,15 @@ fn build_command(
current_dir: &AbsPath,
sysroot: &Sysroot,
toolchain: Option<&semver::Version>,
- ) -> io::Result<Command> {
+ ) -> io::Result<(Option<temp_dir::TempDir>, Command)> {
match config.run_build_script_command.as_deref() {
Some([program, args @ ..]) => {
let mut cmd = toolchain::command(program, current_dir, &config.extra_env);
cmd.args(args);
- Ok(cmd)
+ Ok((None, cmd))
}
_ => {
+ let mut requires_unstable_options = false;
let mut cmd = sysroot.tool(Tool::Cargo, current_dir, &config.extra_env);
cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]);
@@ -416,7 +460,19 @@ fn build_command(
if let Some(target) = &config.target {
cmd.args(["--target", target]);
}
-
+ let mut temp_dir_guard = None;
+ if toolchain
+ .is_some_and(|v| *v >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH)
+ {
+ let lockfile_path =
+ <_ as AsRef<Utf8Path>>::as_ref(manifest_path).with_extension("lock");
+ if let Some((temp_dir, target_lockfile)) = make_lockfile_copy(&lockfile_path) {
+ requires_unstable_options = true;
+ temp_dir_guard = Some(temp_dir);
+ cmd.arg("--lockfile-path");
+ cmd.arg(target_lockfile.as_str());
+ }
+ }
match &config.features {
CargoFeatures::All => {
cmd.arg("--all-features");
@@ -438,6 +494,7 @@ fn build_command(
}
if manifest_path.is_rust_manifest() {
+ requires_unstable_options = true;
cmd.arg("-Zscript");
}
@@ -457,8 +514,7 @@ fn build_command(
toolchain.is_some_and(|v| *v >= COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION);
if cargo_comp_time_deps_available {
- cmd.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly");
- cmd.arg("-Zunstable-options");
+ requires_unstable_options = true;
cmd.arg("--compile-time-deps");
// we can pass this unconditionally, because we won't actually build the
// binaries, and as such, this will succeed even on targets without libtest
@@ -481,7 +537,11 @@ fn build_command(
cmd.env("RA_RUSTC_WRAPPER", "1");
}
}
- Ok(cmd)
+ if requires_unstable_options {
+ cmd.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly");
+ cmd.arg("-Zunstable-options");
+ }
+ Ok((temp_dir_guard, cmd))
}
}
}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs
index 7966f74..a1e7ed0 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs
@@ -1,4 +1,5 @@
//! Read `.cargo/config.toml` as a JSON object
+use paths::{Utf8Path, Utf8PathBuf};
use rustc_hash::FxHashMap;
use toolchain::Tool;
@@ -32,3 +33,24 @@ pub(crate) fn read(
Some(json)
}
+
+pub(crate) fn make_lockfile_copy(
+ lockfile_path: &Utf8Path,
+) -> Option<(temp_dir::TempDir, Utf8PathBuf)> {
+ let temp_dir = temp_dir::TempDir::with_prefix("rust-analyzer").ok()?;
+ let target_lockfile = temp_dir.path().join("Cargo.lock").try_into().ok()?;
+ match std::fs::copy(lockfile_path, &target_lockfile) {
+ Ok(_) => {
+ tracing::debug!("Copied lock file from `{}` to `{}`", lockfile_path, target_lockfile);
+ Some((temp_dir, target_lockfile))
+ }
+ // lockfile does not yet exist, so we can just create a new one in the temp dir
+ Err(e) if e.kind() == std::io::ErrorKind::NotFound => Some((temp_dir, target_lockfile)),
+ Err(e) => {
+ tracing::warn!(
+ "Failed to copy lock file from `{lockfile_path}` to `{target_lockfile}`: {e}",
+ );
+ None
+ }
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index daadcd9..e613fd5 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -15,16 +15,18 @@
use stdx::process::spawn_with_streaming_output;
use toolchain::Tool;
+use crate::cargo_config_file::make_lockfile_copy;
use crate::{CfgOverrides, InvocationStrategy};
use crate::{ManifestPath, Sysroot};
-const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH: semver::Version = semver::Version {
- major: 1,
- minor: 82,
- patch: 0,
- pre: semver::Prerelease::EMPTY,
- build: semver::BuildMetadata::EMPTY,
-};
+pub(crate) const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH: semver::Version =
+ semver::Version {
+ major: 1,
+ minor: 82,
+ patch: 0,
+ pre: semver::Prerelease::EMPTY,
+ build: semver::BuildMetadata::EMPTY,
+ };
/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
/// workspace. It pretty closely mirrors `cargo metadata` output.
@@ -245,7 +247,7 @@ pub enum TargetKind {
}
impl TargetKind {
- fn new(kinds: &[cargo_metadata::TargetKind]) -> TargetKind {
+ pub fn new(kinds: &[cargo_metadata::TargetKind]) -> TargetKind {
for kind in kinds {
return match kind {
cargo_metadata::TargetKind::Bin => TargetKind::Bin,
@@ -552,7 +554,10 @@ pub fn requires_rustc_private(&self) -> bool {
pub(crate) struct FetchMetadata {
command: cargo_metadata::MetadataCommand,
+ #[expect(dead_code)]
+ manifest_path: ManifestPath,
lockfile_path: Option<Utf8PathBuf>,
+ #[expect(dead_code)]
kind: &'static str,
no_deps: bool,
no_deps_result: anyhow::Result<cargo_metadata::Metadata>,
@@ -596,25 +601,22 @@ pub(crate) fn new(
}
command.current_dir(current_dir);
- let mut needs_nightly = false;
let mut other_options = vec![];
// cargo metadata only supports a subset of flags of what cargo usually accepts, and usually
// the only relevant flags for metadata here are unstable ones, so we pass those along
// but nothing else
let mut extra_args = config.extra_args.iter();
while let Some(arg) = extra_args.next() {
- if arg == "-Z" {
- if let Some(arg) = extra_args.next() {
- needs_nightly = true;
- other_options.push("-Z".to_owned());
- other_options.push(arg.to_owned());
- }
+ if arg == "-Z"
+ && let Some(arg) = extra_args.next()
+ {
+ other_options.push("-Z".to_owned());
+ other_options.push(arg.to_owned());
}
}
let mut lockfile_path = None;
if cargo_toml.is_rust_manifest() {
- needs_nightly = true;
other_options.push("-Zscript".to_owned());
} else if config
.toolchain_version
@@ -632,10 +634,6 @@ pub(crate) fn new(
command.other_options(other_options.clone());
- if needs_nightly {
- command.env("RUSTC_BOOTSTRAP", "1");
- }
-
// Pre-fetch basic metadata using `--no-deps`, which:
// - avoids fetching registries like crates.io,
// - skips dependency resolution and does not modify lockfiles,
@@ -655,7 +653,15 @@ pub(crate) fn new(
}
.with_context(|| format!("Failed to run `{cargo_command:?}`"));
- Self { command, lockfile_path, kind: config.kind, no_deps, no_deps_result, other_options }
+ Self {
+ manifest_path: cargo_toml.clone(),
+ command,
+ lockfile_path,
+ kind: config.kind,
+ no_deps,
+ no_deps_result,
+ other_options,
+ }
}
pub(crate) fn no_deps_metadata(&self) -> Option<&cargo_metadata::Metadata> {
@@ -672,40 +678,34 @@ pub(crate) fn exec(
locked: bool,
progress: &dyn Fn(String),
) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
- let Self { mut command, lockfile_path, kind, no_deps, no_deps_result, mut other_options } =
- self;
+ _ = target_dir;
+ let Self {
+ mut command,
+ manifest_path: _,
+ lockfile_path,
+ kind: _,
+ no_deps,
+ no_deps_result,
+ mut other_options,
+ } = self;
if no_deps {
return no_deps_result.map(|m| (m, None));
}
let mut using_lockfile_copy = false;
- // The manifest is a rust file, so this means its a script manifest
- if let Some(lockfile) = lockfile_path {
- let target_lockfile =
- target_dir.join("rust-analyzer").join("metadata").join(kind).join("Cargo.lock");
- match std::fs::copy(&lockfile, &target_lockfile) {
- Ok(_) => {
- using_lockfile_copy = true;
- other_options.push("--lockfile-path".to_owned());
- other_options.push(target_lockfile.to_string());
- }
- Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
- // There exists no lockfile yet
- using_lockfile_copy = true;
- other_options.push("--lockfile-path".to_owned());
- other_options.push(target_lockfile.to_string());
- }
- Err(e) => {
- tracing::warn!(
- "Failed to copy lock file from `{lockfile}` to `{target_lockfile}`: {e}",
- );
- }
- }
+ let mut _temp_dir_guard;
+ if let Some(lockfile) = lockfile_path
+ && let Some((temp_dir, target_lockfile)) = make_lockfile_copy(&lockfile)
+ {
+ _temp_dir_guard = temp_dir;
+ other_options.push("--lockfile-path".to_owned());
+ other_options.push(target_lockfile.to_string());
+ using_lockfile_copy = true;
}
- if using_lockfile_copy {
+ if using_lockfile_copy || other_options.iter().any(|it| it.starts_with("-Z")) {
+ command.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly");
other_options.push("-Zunstable-options".to_owned());
- command.env("RUSTC_BOOTSTRAP", "1");
}
// No need to lock it if we copied the lockfile, we won't modify the original after all/
// This way cargo cannot error out on us if the lockfile requires updating.
@@ -714,13 +714,11 @@ pub(crate) fn exec(
}
command.other_options(other_options);
- // FIXME: Fetching metadata is a slow process, as it might require
- // calling crates.io. We should be reporting progress here, but it's
- // unclear whether cargo itself supports it.
progress("cargo metadata: started".to_owned());
let res = (|| -> anyhow::Result<(_, _)> {
let mut errored = false;
+ tracing::debug!("Running `{:?}`", command.cargo_command());
let output =
spawn_with_streaming_output(command.cargo_command(), &mut |_| (), &mut |line| {
errored = errored || line.starts_with("error") || line.starts_with("warning");
diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
index 3bf3d06..d39781b 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
@@ -59,7 +59,7 @@ pub enum QueryConfig<'a> {
use rustc_hash::FxHashSet;
pub use crate::{
- build_dependencies::WorkspaceBuildScripts,
+ build_dependencies::{ProcMacroDylibPath, WorkspaceBuildScripts},
cargo_workspace::{
CargoConfig, CargoFeatures, CargoMetadataConfig, CargoWorkspace, Package, PackageData,
PackageDependency, RustLibSource, Target, TargetData, TargetKind,
@@ -139,21 +139,22 @@ fn find_cargo_toml(path: &AbsPath) -> io::Result<Vec<ManifestPath>> {
}
fn find_in_parent_dirs(path: &AbsPath, target_file_name: &str) -> Option<ManifestPath> {
- if path.file_name().unwrap_or_default() == target_file_name {
- if let Ok(manifest) = ManifestPath::try_from(path.to_path_buf()) {
- return Some(manifest);
- }
+ if path.file_name().unwrap_or_default() == target_file_name
+ && let Ok(manifest) = ManifestPath::try_from(path.to_path_buf())
+ {
+ return Some(manifest);
}
let mut curr = Some(path);
while let Some(path) = curr {
let candidate = path.join(target_file_name);
- if fs::metadata(&candidate).is_ok() {
- if let Ok(manifest) = ManifestPath::try_from(candidate) {
- return Some(manifest);
- }
+ if fs::metadata(&candidate).is_ok()
+ && let Ok(manifest) = ManifestPath::try_from(candidate)
+ {
+ return Some(manifest);
}
+
curr = path.parent();
}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index 9781c46..c0a5009 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -143,12 +143,11 @@ pub fn tool(
Some(root) => {
// special case rustc, we can look that up directly in the sysroot's bin folder
// as it should never invoke another cargo binary
- if let Tool::Rustc = tool {
- if let Some(path) =
+ if let Tool::Rustc = tool
+ && let Some(path) =
probe_for_binary(root.join("bin").join(Tool::Rustc.name()).into())
- {
- return toolchain::command(path, current_dir, envs);
- }
+ {
+ return toolchain::command(path, current_dir, envs);
}
let mut cmd = toolchain::command(tool.prefer_proxy(), current_dir, envs);
@@ -291,29 +290,26 @@ pub fn load_workspace(
pub fn set_workspace(&mut self, workspace: RustLibSrcWorkspace) {
self.workspace = workspace;
- if self.error.is_none() {
- if let Some(src_root) = &self.rust_lib_src_root {
- let has_core = match &self.workspace {
- RustLibSrcWorkspace::Workspace(ws) => {
- ws.packages().any(|p| ws[p].name == "core")
- }
- RustLibSrcWorkspace::Json(project_json) => project_json
- .crates()
- .filter_map(|(_, krate)| krate.display_name.clone())
- .any(|name| name.canonical_name().as_str() == "core"),
- RustLibSrcWorkspace::Stitched(stitched) => stitched.by_name("core").is_some(),
- RustLibSrcWorkspace::Empty => true,
+ if self.error.is_none()
+ && let Some(src_root) = &self.rust_lib_src_root
+ {
+ let has_core = match &self.workspace {
+ RustLibSrcWorkspace::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
+ RustLibSrcWorkspace::Json(project_json) => project_json
+ .crates()
+ .filter_map(|(_, krate)| krate.display_name.clone())
+ .any(|name| name.canonical_name().as_str() == "core"),
+ RustLibSrcWorkspace::Stitched(stitched) => stitched.by_name("core").is_some(),
+ RustLibSrcWorkspace::Empty => true,
+ };
+ if !has_core {
+ let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
+ " (env var `RUST_SRC_PATH` is set and may be incorrect, try unsetting it)"
+ } else {
+ ", try running `rustup component add rust-src` to possibly fix this"
};
- if !has_core {
- let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
- " (env var `RUST_SRC_PATH` is set and may be incorrect, try unsetting it)"
- } else {
- ", try running `rustup component add rust-src` to possibly fix this"
- };
- self.error = Some(format!(
- "sysroot at `{src_root}` is missing a `core` library{var_note}",
- ));
- }
+ self.error =
+ Some(format!("sysroot at `{src_root}` is missing a `core` library{var_note}",));
}
}
}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
index 6e06e88..ab69c8e 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
@@ -65,6 +65,7 @@ fn rustc_print_cfg(
let (sysroot, current_dir) = match config {
QueryConfig::Cargo(sysroot, cargo_toml, _) => {
let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env);
+ cmd.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly");
cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS);
if let Some(target) = target {
cmd.args(["--target", target]);
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 677f29e..5b36e10 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -24,7 +24,7 @@
CargoConfig, CargoWorkspace, CfgOverrides, InvocationStrategy, ManifestPath, Package,
ProjectJson, ProjectManifest, RustSourceWorkspaceConfig, Sysroot, TargetData, TargetKind,
WorkspaceBuildScripts,
- build_dependencies::BuildScriptOutput,
+ build_dependencies::{BuildScriptOutput, ProcMacroDylibPath},
cargo_config_file,
cargo_workspace::{CargoMetadataConfig, DepKind, FetchMetadata, PackageData, RustLibSource},
env::{cargo_config_env, inject_cargo_env, inject_cargo_package_env, inject_rustc_tool_env},
@@ -424,12 +424,12 @@ struct Root {
sysroot.set_workspace(loaded_sysroot);
}
- if !cargo.requires_rustc_private() {
- if let Err(e) = &mut rustc {
- // We don't need the rustc sources here,
- // so just discard the error.
- _ = e.take();
- }
+ if !cargo.requires_rustc_private()
+ && let Err(e) = &mut rustc
+ {
+ // We don't need the rustc sources here,
+ // so just discard the error.
+ _ = e.take();
}
Ok(ProjectWorkspace {
@@ -1163,17 +1163,15 @@ fn project_json_to_crate_graph(
crate = display_name.as_ref().map(|name| name.canonical_name().as_str()),
"added root to crate graph"
);
- if *is_proc_macro {
- if let Some(path) = proc_macro_dylib_path.clone() {
- let node = Ok((
- display_name
- .as_ref()
- .map(|it| it.canonical_name().as_str().to_owned())
- .unwrap_or_else(|| format!("crate{}", idx.0)),
- path,
- ));
- proc_macros.insert(crate_graph_crate_id, node);
- }
+ if *is_proc_macro && let Some(path) = proc_macro_dylib_path.clone() {
+ let node = Ok((
+ display_name
+ .as_ref()
+ .map(|it| it.canonical_name().as_str().to_owned())
+ .unwrap_or_else(|| format!("crate{}", idx.0)),
+ path,
+ ));
+ proc_macros.insert(crate_graph_crate_id, node);
}
(idx, crate_graph_crate_id)
},
@@ -1318,16 +1316,17 @@ fn cargo_to_crate_graph(
public_deps.add_to_crate_graph(crate_graph, from);
// Add dep edge of all targets to the package's lib target
- if let Some((to, name)) = lib_tgt.clone() {
- if to != from && kind != TargetKind::BuildScript {
- // (build script can not depend on its library target)
+ if let Some((to, name)) = lib_tgt.clone()
+ && to != from
+ && kind != TargetKind::BuildScript
+ {
+ // (build script can not depend on its library target)
- // For root projects with dashes in their name,
- // cargo metadata does not do any normalization,
- // so we do it ourselves currently
- let name = CrateName::normalize_dashes(&name);
- add_dep(crate_graph, from, name, to);
- }
+ // For root projects with dashes in their name,
+ // cargo metadata does not do any normalization,
+ // so we do it ourselves currently
+ let name = CrateName::normalize_dashes(&name);
+ add_dep(crate_graph, from, name, to);
}
}
}
@@ -1638,9 +1637,19 @@ fn add_target_crate_root(
let proc_macro = match build_data {
Some((BuildScriptOutput { proc_macro_dylib_path, .. }, has_errors)) => {
match proc_macro_dylib_path {
- Some(path) => Ok((cargo_name.to_owned(), path.clone())),
- None if has_errors => Err(ProcMacroLoadingError::FailedToBuild),
- None => Err(ProcMacroLoadingError::MissingDylibPath),
+ ProcMacroDylibPath::Path(path) => Ok((cargo_name.to_owned(), path.clone())),
+ ProcMacroDylibPath::NotBuilt => Err(ProcMacroLoadingError::NotYetBuilt),
+ ProcMacroDylibPath::NotProcMacro | ProcMacroDylibPath::DylibNotFound
+ if has_errors =>
+ {
+ Err(ProcMacroLoadingError::FailedToBuild)
+ }
+ ProcMacroDylibPath::NotProcMacro => {
+ Err(ProcMacroLoadingError::ExpectedProcMacroArtifact)
+ }
+ ProcMacroDylibPath::DylibNotFound => {
+ Err(ProcMacroLoadingError::MissingDylibPath)
+ }
}
}
None => Err(ProcMacroLoadingError::NotYetBuilt),
@@ -1905,7 +1914,8 @@ fn cargo_target_dir(
meta.manifest_path(manifest);
// `--no-deps` doesn't (over)write lockfiles as it doesn't do any package resolve.
// So we can use it to get `target_directory` before copying lockfiles
- let mut other_options = vec!["--no-deps".to_owned()];
+ meta.no_deps();
+ let mut other_options = vec![];
if manifest.is_rust_manifest() {
meta.env("RUSTC_BOOTSTRAP", "1");
other_options.push("-Zscript".to_owned());
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index fc89f48..4f75d14 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -656,22 +656,26 @@ fn run_mir_lowering(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity:
let mut sw = self.stop_watch();
let mut all = 0;
let mut fail = 0;
- for &body in bodies {
- if matches!(body, DefWithBody::Variant(_)) {
+ for &body_id in bodies {
+ if matches!(body_id, DefWithBody::Variant(_)) {
continue;
}
+ let module = body_id.module(db);
+ if !self.should_process(db, body_id, module) {
+ continue;
+ }
+
all += 1;
- let Err(e) = db.mir_body(body.into()) else {
+ let Err(e) = db.mir_body(body_id.into()) else {
continue;
};
if verbosity.is_spammy() {
- let full_name = body
- .module(db)
+ let full_name = module
.path_to_root(db)
.into_iter()
.rev()
.filter_map(|it| it.name(db))
- .chain(Some(body.name(db).unwrap_or_else(Name::missing)))
+ .chain(Some(body_id.name(db).unwrap_or_else(Name::missing)))
.map(|it| it.display(db, Edition::LATEST).to_string())
.join("::");
bar.println(format!("Mir body for {full_name} failed due {e:?}"));
@@ -727,26 +731,9 @@ fn run_inference(
let name = body_id.name(db).unwrap_or_else(Name::missing);
let module = body_id.module(db);
let display_target = module.krate().to_display_target(db);
- let full_name = move || {
- module
- .krate()
- .display_name(db)
- .map(|it| it.canonical_name().as_str().to_owned())
- .into_iter()
- .chain(
- module
- .path_to_root(db)
- .into_iter()
- .filter_map(|it| it.name(db))
- .rev()
- .chain(Some(body_id.name(db).unwrap_or_else(Name::missing)))
- .map(|it| it.display(db, Edition::LATEST).to_string()),
- )
- .join("::")
- };
if let Some(only_name) = self.only.as_deref() {
if name.display(db, Edition::LATEST).to_string() != only_name
- && full_name() != only_name
+ && full_name(db, body_id, module) != only_name
{
continue;
}
@@ -763,12 +750,17 @@ fn run_inference(
let original_file = src.file_id.original_file(db);
let path = vfs.file_path(original_file.file_id(db));
let syntax_range = src.text_range();
- format!("processing: {} ({} {:?})", full_name(), path, syntax_range)
+ format!(
+ "processing: {} ({} {:?})",
+ full_name(db, body_id, module),
+ path,
+ syntax_range
+ )
} else {
- format!("processing: {}", full_name())
+ format!("processing: {}", full_name(db, body_id, module))
}
} else {
- format!("processing: {}", full_name())
+ format!("processing: {}", full_name(db, body_id, module))
}
};
if verbosity.is_spammy() {
@@ -781,9 +773,11 @@ fn run_inference(
Ok(inference_result) => inference_result,
Err(p) => {
if let Some(s) = p.downcast_ref::<&str>() {
- eprintln!("infer panicked for {}: {}", full_name(), s);
+ eprintln!("infer panicked for {}: {}", full_name(db, body_id, module), s);
} else if let Some(s) = p.downcast_ref::<String>() {
- eprintln!("infer panicked for {}: {}", full_name(), s);
+ eprintln!("infer panicked for {}: {}", full_name(db, body_id, module), s);
+ } else {
+ eprintln!("infer panicked for {}", full_name(db, body_id, module));
}
panics += 1;
bar.inc(1);
@@ -890,7 +884,7 @@ fn run_inference(
if verbosity.is_spammy() {
bar.println(format!(
"In {}: {} exprs, {} unknown, {} partial",
- full_name(),
+ full_name(db, body_id, module),
num_exprs - previous_exprs,
num_exprs_unknown - previous_unknown,
num_exprs_partially_unknown - previous_partially_unknown
@@ -993,7 +987,7 @@ fn run_inference(
if verbosity.is_spammy() {
bar.println(format!(
"In {}: {} pats, {} unknown, {} partial",
- full_name(),
+ full_name(db, body_id, module),
num_pats - previous_pats,
num_pats_unknown - previous_unknown,
num_pats_partially_unknown - previous_partially_unknown
@@ -1049,34 +1043,8 @@ fn run_body_lowering(
bar.tick();
for &body_id in bodies {
let module = body_id.module(db);
- let full_name = move || {
- module
- .krate()
- .display_name(db)
- .map(|it| it.canonical_name().as_str().to_owned())
- .into_iter()
- .chain(
- module
- .path_to_root(db)
- .into_iter()
- .filter_map(|it| it.name(db))
- .rev()
- .chain(Some(body_id.name(db).unwrap_or_else(Name::missing)))
- .map(|it| it.display(db, Edition::LATEST).to_string()),
- )
- .join("::")
- };
- if let Some(only_name) = self.only.as_deref() {
- if body_id
- .name(db)
- .unwrap_or_else(Name::missing)
- .display(db, Edition::LATEST)
- .to_string()
- != only_name
- && full_name() != only_name
- {
- continue;
- }
+ if !self.should_process(db, body_id, module) {
+ continue;
}
let msg = move || {
if verbosity.is_verbose() {
@@ -1090,12 +1058,17 @@ fn run_body_lowering(
let original_file = src.file_id.original_file(db);
let path = vfs.file_path(original_file.file_id(db));
let syntax_range = src.text_range();
- format!("processing: {} ({} {:?})", full_name(), path, syntax_range)
+ format!(
+ "processing: {} ({} {:?})",
+ full_name(db, body_id, module),
+ path,
+ syntax_range
+ )
} else {
- format!("processing: {}", full_name())
+ format!("processing: {}", full_name(db, body_id, module))
}
} else {
- format!("processing: {}", full_name())
+ format!("processing: {}", full_name(db, body_id, module))
}
};
if verbosity.is_spammy() {
@@ -1205,11 +1178,42 @@ fn run_ide_things(&self, analysis: Analysis, mut file_ids: Vec<EditionedFileId>)
eprintln!("{:<20} {} ({} files)", "IDE:", ide_time, file_ids.len());
}
+ fn should_process(&self, db: &RootDatabase, body_id: DefWithBody, module: hir::Module) -> bool {
+ if let Some(only_name) = self.only.as_deref() {
+ let name = body_id.name(db).unwrap_or_else(Name::missing);
+
+ if name.display(db, Edition::LATEST).to_string() != only_name
+ && full_name(db, body_id, module) != only_name
+ {
+ return false;
+ }
+ }
+ true
+ }
+
fn stop_watch(&self) -> StopWatch {
StopWatch::start()
}
}
+fn full_name(db: &RootDatabase, body_id: DefWithBody, module: hir::Module) -> String {
+ module
+ .krate()
+ .display_name(db)
+ .map(|it| it.canonical_name().as_str().to_owned())
+ .into_iter()
+ .chain(
+ module
+ .path_to_root(db)
+ .into_iter()
+ .filter_map(|it| it.name(db))
+ .rev()
+ .chain(Some(body_id.name(db).unwrap_or_else(Name::missing)))
+ .map(|it| it.display(db, Edition::LATEST).to_string()),
+ )
+ .join("::")
+}
+
fn location_csv_expr(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, expr_id: ExprId) -> String {
let src = match sm.expr_syntax(expr_id) {
Ok(s) => s,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 51d4c29..9456fd8 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -2162,6 +2162,7 @@ pub(crate) fn cargo_test_options(&self, source_root: Option<SourceRootId>) -> Ca
extra_test_bin_args: self.runnables_extraTestBinaryArgs(source_root).clone(),
extra_env: self.extra_env(source_root).clone(),
target_dir: self.target_dir_from_config(source_root),
+ set_test: true,
}
}
@@ -2219,6 +2220,7 @@ pub(crate) fn flycheck(&self, source_root: Option<SourceRootId>) -> FlycheckConf
extra_test_bin_args: self.runnables_extraTestBinaryArgs(source_root).clone(),
extra_env: self.check_extra_env(source_root),
target_dir: self.target_dir_from_config(source_root),
+ set_test: *self.cfg_setTest(source_root),
},
ansi_color_output: self.color_diagnostic_output(),
},
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
index 91d37bd..512ce0b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -31,6 +31,7 @@ pub(crate) enum InvocationStrategy {
pub(crate) struct CargoOptions {
pub(crate) target_tuples: Vec<String>,
pub(crate) all_targets: bool,
+ pub(crate) set_test: bool,
pub(crate) no_default_features: bool,
pub(crate) all_features: bool,
pub(crate) features: Vec<String>,
@@ -54,7 +55,13 @@ pub(crate) fn apply_on_command(&self, cmd: &mut Command) {
cmd.args(["--target", target.as_str()]);
}
if self.all_targets {
- cmd.arg("--all-targets");
+ if self.set_test {
+ cmd.arg("--all-targets");
+ } else {
+ // No --benches unfortunately, as this implies --tests (see https://github.com/rust-lang/cargo/issues/6454),
+ // and users setting `cfg.seTest = false` probably prefer disabling benches than enabling tests.
+ cmd.args(["--lib", "--bins", "--examples"]);
+ }
}
if self.all_features {
cmd.arg("--all-features");
@@ -104,7 +111,18 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FlycheckConfig::CargoCommand { command, .. } => write!(f, "cargo {command}"),
FlycheckConfig::CustomCommand { command, args, .. } => {
- write!(f, "{command} {}", args.join(" "))
+ // Don't show `my_custom_check --foo $saved_file` literally to the user, as it
+ // looks like we've forgotten to substitute $saved_file.
+ //
+ // Instead, show `my_custom_check --foo ...`. The
+ // actual path is often too long to be worth showing
+ // in the IDE (e.g. in the VS Code status bar).
+ let display_args = args
+ .iter()
+ .map(|arg| if arg == SAVED_FILE_PLACEHOLDER { "..." } else { arg })
+ .collect::<Vec<_>>();
+
+ write!(f, "{command} {}", display_args.join(" "))
}
}
}
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index 4cbc88c..6d8a360 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -101,7 +101,7 @@
'where' predicates:(WherePred (',' WherePred)* ','?)
WherePred =
- ('for' GenericParamList)? (Lifetime | Type) ':' TypeBoundList?
+ ForBinder? (Lifetime | Type) ':' TypeBoundList?
//*************************//
@@ -534,10 +534,10 @@
Attr* Expr '.' NameRef
ClosureExpr =
- Attr* ClosureBinder? 'const'? 'static'? 'async'? 'gen'? 'move'? ParamList RetType?
+ Attr* ForBinder? 'const'? 'static'? 'async'? 'gen'? 'move'? ParamList RetType?
body:Expr
-ClosureBinder =
+ForBinder =
'for' GenericParamList
IfExpr =
@@ -658,7 +658,7 @@
'const'? 'async'? 'unsafe'? Abi? 'fn' ParamList RetType?
ForType =
- 'for' GenericParamList Type
+ ForBinder Type
ImplTraitType =
'impl' TypeBoundList
@@ -671,7 +671,7 @@
TypeBound =
Lifetime
-| ('~' 'const' | '[' 'const' ']' | 'const')? 'async'? '?'? Type
+| ForBinder? ('~' 'const' | '[' 'const' ']' | 'const')? 'async'? '?'? Type
| 'use' UseBoundGenericArgs
UseBoundGenericArgs =
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast.rs b/src/tools/rust-analyzer/crates/syntax/src/ast.rs
index d787fd0..a9aeeed 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast.rs
@@ -393,8 +393,7 @@ fn foo()
let pred = predicates.next().unwrap();
let mut bounds = pred.type_bound_list().unwrap().bounds();
- assert!(pred.for_token().is_none());
- assert!(pred.generic_param_list().is_none());
+ assert!(pred.for_binder().is_none());
assert_eq!("T", pred.ty().unwrap().syntax().text().to_string());
assert_bound("Clone", bounds.next());
assert_bound("Copy", bounds.next());
@@ -432,8 +431,10 @@ fn foo()
let pred = predicates.next().unwrap();
let mut bounds = pred.type_bound_list().unwrap().bounds();
- assert!(pred.for_token().is_some());
- assert_eq!("<'a>", pred.generic_param_list().unwrap().syntax().text().to_string());
+ assert_eq!(
+ "<'a>",
+ pred.for_binder().unwrap().generic_param_list().unwrap().syntax().text().to_string()
+ );
assert_eq!("F", pred.ty().unwrap().syntax().text().to_string());
assert_bound("Fn(&'a str)", bounds.next());
}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs
index 37cb4a4..d97fdec 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs
@@ -6,9 +6,12 @@
use crate::{
AstToken, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken,
ast::{self, AstNode, make},
+ syntax_editor::{SyntaxEditor, SyntaxMappingBuilder},
ted,
};
+use super::syntax_factory::SyntaxFactory;
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IndentLevel(pub u8);
@@ -95,6 +98,24 @@ pub(super) fn increase_indent(self, node: &SyntaxNode) {
}
}
+ pub(super) fn clone_increase_indent(self, node: &SyntaxNode) -> SyntaxNode {
+ let node = node.clone_subtree();
+ let mut editor = SyntaxEditor::new(node.clone());
+ let tokens = node
+ .preorder_with_tokens()
+ .filter_map(|event| match event {
+ rowan::WalkEvent::Leave(NodeOrToken::Token(it)) => Some(it),
+ _ => None,
+ })
+ .filter_map(ast::Whitespace::cast)
+ .filter(|ws| ws.text().contains('\n'));
+ for ws in tokens {
+ let new_ws = make::tokens::whitespace(&format!("{}{self}", ws.syntax()));
+ editor.replace(ws.syntax(), &new_ws);
+ }
+ editor.finish().new_root().clone()
+ }
+
pub(super) fn decrease_indent(self, node: &SyntaxNode) {
let tokens = node.preorder_with_tokens().filter_map(|event| match event {
rowan::WalkEvent::Leave(NodeOrToken::Token(it)) => Some(it),
@@ -111,36 +132,54 @@ pub(super) fn decrease_indent(self, node: &SyntaxNode) {
}
}
}
+
+ pub(super) fn clone_decrease_indent(self, node: &SyntaxNode) -> SyntaxNode {
+ let node = node.clone_subtree();
+ let mut editor = SyntaxEditor::new(node.clone());
+ let tokens = node
+ .preorder_with_tokens()
+ .filter_map(|event| match event {
+ rowan::WalkEvent::Leave(NodeOrToken::Token(it)) => Some(it),
+ _ => None,
+ })
+ .filter_map(ast::Whitespace::cast)
+ .filter(|ws| ws.text().contains('\n'));
+ for ws in tokens {
+ let new_ws =
+ make::tokens::whitespace(&ws.syntax().text().replace(&format!("\n{self}"), "\n"));
+ editor.replace(ws.syntax(), &new_ws);
+ }
+ editor.finish().new_root().clone()
+ }
}
fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> {
iter::successors(Some(token), |token| token.prev_token())
}
-/// Soft-deprecated in favor of mutable tree editing API `edit_in_place::Ident`.
pub trait AstNodeEdit: AstNode + Clone + Sized {
fn indent_level(&self) -> IndentLevel {
IndentLevel::from_node(self.syntax())
}
#[must_use]
fn indent(&self, level: IndentLevel) -> Self {
- fn indent_inner(node: &SyntaxNode, level: IndentLevel) -> SyntaxNode {
- let res = node.clone_subtree().clone_for_update();
- level.increase_indent(&res);
- res.clone_subtree()
+ Self::cast(level.clone_increase_indent(self.syntax())).unwrap()
+ }
+ #[must_use]
+ fn indent_with_mapping(&self, level: IndentLevel, make: &SyntaxFactory) -> Self {
+ let new_node = self.indent(level);
+ if let Some(mut mapping) = make.mappings() {
+ let mut builder = SyntaxMappingBuilder::new(new_node.syntax().clone());
+ for (old, new) in self.syntax().children().zip(new_node.syntax().children()) {
+ builder.map_node(old, new);
+ }
+ builder.finish(&mut mapping);
}
-
- Self::cast(indent_inner(self.syntax(), level)).unwrap()
+ new_node
}
#[must_use]
fn dedent(&self, level: IndentLevel) -> Self {
- fn dedent_inner(node: &SyntaxNode, level: IndentLevel) -> SyntaxNode {
- let res = node.clone_subtree().clone_for_update();
- level.decrease_indent(&res);
- res.clone_subtree()
- }
-
- Self::cast(dedent_inner(self.syntax(), level)).unwrap()
+ Self::cast(level.clone_decrease_indent(self.syntax())).unwrap()
}
#[must_use]
fn reset_indent(&self) -> Self {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
index e902516..28b543e 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
@@ -644,7 +644,7 @@ fn remove(&self) {
impl ast::Impl {
pub fn get_or_create_assoc_item_list(&self) -> ast::AssocItemList {
if self.assoc_item_list().is_none() {
- let assoc_item_list = make::assoc_item_list().clone_for_update();
+ let assoc_item_list = make::assoc_item_list(None).clone_for_update();
ted::append_child(self.syntax(), assoc_item_list.syntax());
}
self.assoc_item_list().unwrap()
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index 2b86246..ceb2866 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -377,22 +377,13 @@ pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
#[inline]
pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
}
-pub struct ClosureBinder {
- pub(crate) syntax: SyntaxNode,
-}
-impl ClosureBinder {
- #[inline]
- pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
- #[inline]
- pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
-}
pub struct ClosureExpr {
pub(crate) syntax: SyntaxNode,
}
impl ast::HasAttrs for ClosureExpr {}
impl ClosureExpr {
#[inline]
- pub fn closure_binder(&self) -> Option<ClosureBinder> { support::child(&self.syntax) }
+ pub fn for_binder(&self) -> Option<ForBinder> { support::child(&self.syntax) }
#[inline]
pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
#[inline]
@@ -615,6 +606,15 @@ pub fn fn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![
#[inline]
pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
}
+pub struct ForBinder {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ForBinder {
+ #[inline]
+ pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
+ #[inline]
+ pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
+}
pub struct ForExpr {
pub(crate) syntax: SyntaxNode,
}
@@ -632,11 +632,9 @@ pub struct ForType {
}
impl ForType {
#[inline]
- pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
+ pub fn for_binder(&self) -> Option<ForBinder> { support::child(&self.syntax) }
#[inline]
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
- #[inline]
- pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
}
pub struct FormatArgsArg {
pub(crate) syntax: SyntaxNode,
@@ -1766,6 +1764,8 @@ pub struct TypeBound {
}
impl TypeBound {
#[inline]
+ pub fn for_binder(&self) -> Option<ForBinder> { support::child(&self.syntax) }
+ #[inline]
pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
#[inline]
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
@@ -1938,13 +1938,11 @@ pub struct WherePred {
impl ast::HasTypeBounds for WherePred {}
impl WherePred {
#[inline]
- pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
+ pub fn for_binder(&self) -> Option<ForBinder> { support::child(&self.syntax) }
#[inline]
pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
#[inline]
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
- #[inline]
- pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
}
pub struct WhileExpr {
pub(crate) syntax: SyntaxNode,
@@ -3239,42 +3237,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CastExpr").field("syntax", &self.syntax).finish()
}
}
-impl AstNode for ClosureBinder {
- #[inline]
- fn kind() -> SyntaxKind
- where
- Self: Sized,
- {
- CLOSURE_BINDER
- }
- #[inline]
- fn can_cast(kind: SyntaxKind) -> bool { kind == CLOSURE_BINDER }
- #[inline]
- fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
- }
- #[inline]
- fn syntax(&self) -> &SyntaxNode { &self.syntax }
-}
-impl hash::Hash for ClosureBinder {
- fn hash<H: hash::Hasher>(&self, state: &mut H) { self.syntax.hash(state); }
-}
-impl Eq for ClosureBinder {}
-impl PartialEq for ClosureBinder {
- fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax }
-}
-impl Clone for ClosureBinder {
- fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } }
-}
-impl fmt::Debug for ClosureBinder {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("ClosureBinder").field("syntax", &self.syntax).finish()
- }
-}
impl AstNode for ClosureExpr {
#[inline]
fn kind() -> SyntaxKind
@@ -3815,6 +3777,42 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FnPtrType").field("syntax", &self.syntax).finish()
}
}
+impl AstNode for ForBinder {
+ #[inline]
+ fn kind() -> SyntaxKind
+ where
+ Self: Sized,
+ {
+ FOR_BINDER
+ }
+ #[inline]
+ fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_BINDER }
+ #[inline]
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ #[inline]
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl hash::Hash for ForBinder {
+ fn hash<H: hash::Hasher>(&self, state: &mut H) { self.syntax.hash(state); }
+}
+impl Eq for ForBinder {}
+impl PartialEq for ForBinder {
+ fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax }
+}
+impl Clone for ForBinder {
+ fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } }
+}
+impl fmt::Debug for ForBinder {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ForBinder").field("syntax", &self.syntax).finish()
+ }
+}
impl AstNode for ForExpr {
#[inline]
fn kind() -> SyntaxKind
@@ -10146,11 +10144,6 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
}
-impl std::fmt::Display for ClosureBinder {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- std::fmt::Display::fmt(self.syntax(), f)
- }
-}
impl std::fmt::Display for ClosureExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
@@ -10226,6 +10219,11 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
}
+impl std::fmt::Display for ForBinder {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
impl std::fmt::Display for ForExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index d67f24f..2a7b51c 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -229,8 +229,18 @@ pub fn ty_fn_ptr<I: Iterator<Item = Param>>(
}
}
-pub fn assoc_item_list() -> ast::AssocItemList {
- ast_from_text("impl C for D {}")
+pub fn assoc_item_list(
+ body: Option<Vec<either::Either<ast::Attr, ast::AssocItem>>>,
+) -> ast::AssocItemList {
+ let is_break_braces = body.is_some();
+ let body_newline = if is_break_braces { "\n".to_owned() } else { String::new() };
+ let body_indent = if is_break_braces { " ".to_owned() } else { String::new() };
+
+ let body = match body {
+ Some(bd) => bd.iter().map(|elem| elem.to_string()).join("\n\n "),
+ None => String::new(),
+ };
+ ast_from_text(&format!("impl C for D {{{body_newline}{body_indent}{body}{body_newline}}}"))
}
fn merge_gen_params(
@@ -273,7 +283,7 @@ pub fn impl_(
generic_args: Option<ast::GenericArgList>,
path_type: ast::Type,
where_clause: Option<ast::WhereClause>,
- body: Option<Vec<either::Either<ast::Attr, ast::AssocItem>>>,
+ body: Option<ast::AssocItemList>,
) -> ast::Impl {
let gen_args = generic_args.map_or_else(String::new, |it| it.to_string());
@@ -281,20 +291,13 @@ pub fn impl_(
let body_newline =
if where_clause.is_some() && body.is_none() { "\n".to_owned() } else { String::new() };
-
let where_clause = match where_clause {
Some(pr) => format!("\n{pr}\n"),
None => " ".to_owned(),
};
- let body = match body {
- Some(bd) => bd.iter().map(|elem| elem.to_string()).join(""),
- None => String::new(),
- };
-
- ast_from_text(&format!(
- "impl{gen_params} {path_type}{gen_args}{where_clause}{{{body_newline}{body}}}"
- ))
+ let body = body.map_or_else(|| format!("{{{body_newline}}}"), |it| it.to_string());
+ ast_from_text(&format!("impl{gen_params} {path_type}{gen_args}{where_clause}{body}"))
}
pub fn impl_trait(
@@ -308,7 +311,7 @@ pub fn impl_trait(
ty: ast::Type,
trait_where_clause: Option<ast::WhereClause>,
ty_where_clause: Option<ast::WhereClause>,
- body: Option<Vec<either::Either<ast::Attr, ast::AssocItem>>>,
+ body: Option<ast::AssocItemList>,
) -> ast::Impl {
let is_unsafe = if is_unsafe { "unsafe " } else { "" };
@@ -330,13 +333,10 @@ pub fn impl_trait(
let where_clause = merge_where_clause(ty_where_clause, trait_where_clause)
.map_or_else(|| " ".to_owned(), |wc| format!("\n{wc}\n"));
- let body = match body {
- Some(bd) => bd.iter().map(|elem| elem.to_string()).join(""),
- None => String::new(),
- };
+ let body = body.map_or_else(|| format!("{{{body_newline}}}"), |it| it.to_string());
ast_from_text(&format!(
- "{is_unsafe}impl{gen_params} {is_negative}{path_type}{trait_gen_args} for {ty}{type_gen_args}{where_clause}{{{body_newline}{body}}}"
+ "{is_unsafe}impl{gen_params} {is_negative}{path_type}{trait_gen_args} for {ty}{type_gen_args}{where_clause}{body}"
))
}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
index f5530c5..62a7d4d 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
@@ -805,9 +805,7 @@ pub fn kind(&self) -> SelfParamKind {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum TypeBoundKind {
/// Trait
- PathType(ast::PathType),
- /// for<'a> ...
- ForType(ast::ForType),
+ PathType(Option<ast::ForBinder>, ast::PathType),
/// use
Use(ast::UseBoundGenericArgs),
/// 'a
@@ -817,9 +815,7 @@ pub enum TypeBoundKind {
impl ast::TypeBound {
pub fn kind(&self) -> TypeBoundKind {
if let Some(path_type) = support::children(self.syntax()).next() {
- TypeBoundKind::PathType(path_type)
- } else if let Some(for_type) = support::children(self.syntax()).next() {
- TypeBoundKind::ForType(for_type)
+ TypeBoundKind::PathType(self.for_binder(), path_type)
} else if let Some(args) = self.use_bound_generic_args() {
TypeBoundKind::Use(args)
} else if let Some(lifetime) = self.lifetime() {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory.rs
index 7142e4f..f3ae754 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory.rs
@@ -38,7 +38,7 @@ pub fn take(&self) -> SyntaxMapping {
self.mappings.as_ref().map(|mappings| mappings.take()).unwrap_or_default()
}
- fn mappings(&self) -> Option<RefMut<'_, SyntaxMapping>> {
+ pub(crate) fn mappings(&self) -> Option<RefMut<'_, SyntaxMapping>> {
self.mappings.as_ref().map(|it| it.borrow_mut())
}
}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
index 3fa5848..5107754 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
@@ -5,7 +5,7 @@
//! [`SyntaxEditor`]: https://github.com/dotnet/roslyn/blob/43b0b05cc4f492fd5de00f6f6717409091df8daa/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs
use std::{
- fmt,
+ fmt, iter,
num::NonZeroU32,
ops::RangeInclusive,
sync::atomic::{AtomicU32, Ordering},
@@ -41,6 +41,15 @@ pub fn add_annotation(&mut self, element: impl Element, annotation: SyntaxAnnota
self.annotations.push((element.syntax_element(), annotation))
}
+ pub fn add_annotation_all(
+ &mut self,
+ elements: Vec<impl Element>,
+ annotation: SyntaxAnnotation,
+ ) {
+ self.annotations
+ .extend(elements.into_iter().map(|e| e.syntax_element()).zip(iter::repeat(annotation)));
+ }
+
pub fn merge(&mut self, mut other: SyntaxEditor) {
debug_assert!(
self.root == other.root || other.root.ancestors().any(|node| node == self.root),
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs
index d66ea8a..840e769 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs
@@ -92,6 +92,42 @@ fn get_or_insert_comma_after(editor: &mut SyntaxEditor, syntax: &SyntaxNode) ->
}
}
+impl ast::AssocItemList {
+ /// Adds a new associated item after all of the existing associated items.
+ ///
+ /// Attention! This function does align the first line of `item` with respect to `self`,
+ /// but it does _not_ change indentation of other lines (if any).
+ pub fn add_items(&self, editor: &mut SyntaxEditor, items: Vec<ast::AssocItem>) {
+ let (indent, position, whitespace) = match self.assoc_items().last() {
+ Some(last_item) => (
+ IndentLevel::from_node(last_item.syntax()),
+ Position::after(last_item.syntax()),
+ "\n\n",
+ ),
+ None => match self.l_curly_token() {
+ Some(l_curly) => {
+ normalize_ws_between_braces(editor, self.syntax());
+ (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly), "\n")
+ }
+ None => (IndentLevel::single(), Position::last_child_of(self.syntax()), "\n"),
+ },
+ };
+
+ let elements: Vec<SyntaxElement> = items
+ .into_iter()
+ .enumerate()
+ .flat_map(|(i, item)| {
+ let whitespace = if i != 0 { "\n\n" } else { whitespace };
+ vec![
+ make::tokens::whitespace(&format!("{whitespace}{indent}")).into(),
+ item.syntax().clone().into(),
+ ]
+ })
+ .collect();
+ editor.insert_all(position, elements);
+ }
+}
+
impl ast::VariantList {
pub fn add_variant(&self, editor: &mut SyntaxEditor, variant: &ast::Variant) {
let make = SyntaxFactory::without_mappings();
diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/README.md b/src/tools/rust-analyzer/docs/book/src/contributing/README.md
index beb94cd..57c7a9c 100644
--- a/src/tools/rust-analyzer/docs/book/src/contributing/README.md
+++ b/src/tools/rust-analyzer/docs/book/src/contributing/README.md
@@ -252,18 +252,8 @@
4. Commit & push the changelog.
5. Run `cargo xtask publish-release-notes <CHANGELOG>` -- this will convert the changelog entry in AsciiDoc to Markdown and update the body of GitHub Releases entry.
6. Tweet.
-7. Make a new branch and run `cargo xtask rustc-pull`, open a PR, and merge it.
- This will pull any changes from `rust-lang/rust` into `rust-analyzer`.
-8. Switch to `master`, pull, then run `cargo xtask rustc-push --rust-path ../rust-rust-analyzer --rust-fork matklad/rust`.
- Replace `matklad/rust` with your own fork of `rust-lang/rust`.
- You can use the token to authenticate when you get prompted for a password, since `josh` will push over HTTPS, not SSH.
- This will push the `rust-analyzer` changes to your fork.
- You can then open a PR against `rust-lang/rust`.
-
-Note: besides the `rust-rust-analyzer` clone, the Josh cache (stored under `~/.cache/rust-analyzer-josh`) will contain a bare clone of `rust-lang/rust`.
-This currently takes about 3.5 GB.
-
-This [HackMD](https://hackmd.io/7pOuxnkdQDaL1Y1FQr65xg) has details about how `josh` syncs work.
+7. Perform a subtree [pull](#performing-a-pull).
+8. Perform a subtree [push](#performing-a-push).
If the GitHub Actions release fails because of a transient problem like a timeout, you can re-run the job from the Actions console.
If it fails because of something that needs to be fixed, remove the release tag (if needed), fix the problem, then start over.
@@ -288,3 +278,43 @@
If you don't feel like reviewing for whatever reason, someone else will pick the review up (but please speak up if you don't feel like it)!
* The [rust-lang](https://github.com/rust-lang) team [t-rust-analyzer-contributors]([https://github.com/orgs/rust-analyzer/teams/triage](https://github.com/rust-lang/team/blob/master/teams/rust-analyzer-contributors.toml)).
This team has general triaging permissions allowing to label, close and re-open issues.
+
+## Synchronizing subtree changes
+`rust-analyzer` is a [josh](https://josh-project.github.io/josh/intro.html) subtree of the [rust-lang/rust](https://github.com/rust-lang/rust)
+repository. We use the [rustc-josh-sync](https://github.com/rust-lang/josh-sync) tool to perform synchronization between these two
+repositories. You can find documentation of the tool [here](https://github.com/rust-lang/josh-sync).
+
+You can install the synchronization tool using the following commands:
+```
+cargo install --locked --git https://github.com/rust-lang/josh-sync
+```
+
+Both pulls (synchronizing changes from rust-lang/rust into rust-analyzer) and pushes (synchronizing
+changes from rust-analyzer into rust-lang/rust) are performed from this repository.
+changes from rust-analyzer to rust-lang/rust) are performed from this repository.
+
+Usually we first perform a pull, wait for it to be merged, and then perform a push.
+
+### Performing a pull
+1) Checkout a new branch that will be used to create a PR against rust-analyzer
+2) Run the pull command
+ ```
+ rustc-josh-sync pull
+ ```
+3) Push the branch to your fork of `rust-analyzer` and create a PR
+ - If you have the `gh` CLI installed, `rustc-josh-sync` can create the PR for you.
+
+### Performing a push
+
+Wait for the previous pull to be merged.
+
+1) Switch to `master` and pull
+2) Run the push command to create a branch named `<branch-name>` in a `rustc` fork under the `<gh-username>` account
+ ```
+ rustc-josh-sync push <branch-name> <gh-username>
+ ```
+ - The push will ask you to download a checkout of the `rust-lang/rust` repository.
+ - If you get prompted for a password, see [this](https://github.com/rust-lang/josh-sync?tab=readme-ov-file#git-peculiarities).
+3) Create a PR from `<branch-name>` into `rust-lang/rust`
+
+> Besides the `rust` checkout, the Josh cache (stored under `~/.cache/rustc-josh`) will contain a bare clone of `rust-lang/rust`. This currently takes several GBs.
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index 57d67a6..534c24b 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -3336,15 +3336,16 @@
}
},
"node_modules/form-data": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
- "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
+ "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"dev": true,
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index d2dc740..3b1b076 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -8,10 +8,9 @@
export type RunnableEnvCfgItem = {
mask?: string;
- env: Record<string, string>;
+ env: { [key: string]: { toString(): string } | null };
platform?: string | string[];
};
-export type RunnableEnvCfg = Record<string, string> | RunnableEnvCfgItem[];
type ShowStatusBar = "always" | "never" | { documentSelector: vscode.DocumentSelector };
@@ -261,18 +260,13 @@
return this.get<boolean | undefined>("testExplorer");
}
- runnablesExtraEnv(label: string): Record<string, string> | undefined {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const item = this.get<any>("runnables.extraEnv") ?? this.get<any>("runnableEnv");
- if (!item) return undefined;
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const fixRecord = (r: Record<string, any>) => {
- for (const key in r) {
- if (typeof r[key] !== "string") {
- r[key] = String(r[key]);
- }
- }
- };
+ runnablesExtraEnv(label: string): Env {
+ const serverEnv = this.serverExtraEnv;
+ let extraEnv =
+ this.get<
+ RunnableEnvCfgItem[] | { [key: string]: { toString(): string } | null } | null
+ >("runnables.extraEnv") ?? {};
+ if (!extraEnv) return serverEnv;
const platform = process.platform;
const checkPlatform = (it: RunnableEnvCfgItem) => {
@@ -283,19 +277,25 @@
return true;
};
- if (item instanceof Array) {
+ if (extraEnv instanceof Array) {
const env = {};
- for (const it of item) {
+ for (const it of extraEnv) {
const masked = !it.mask || new RegExp(it.mask).test(label);
if (masked && checkPlatform(it)) {
Object.assign(env, it.env);
}
}
- fixRecord(env);
- return env;
+ extraEnv = env;
}
- fixRecord(item);
- return item;
+ const runnableExtraEnv = substituteVariablesInEnv(
+ Object.fromEntries(
+ Object.entries(extraEnv).map(([k, v]) => [
+ k,
+ typeof v === "string" ? v : v?.toString(),
+ ]),
+ ),
+ );
+ return { ...runnableExtraEnv, ...serverEnv };
}
get restartServerOnConfigChange() {
diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts
index adb75c2..24f8d90 100644
--- a/src/tools/rust-analyzer/editors/code/src/debug.ts
+++ b/src/tools/rust-analyzer/editors/code/src/debug.ts
@@ -6,7 +6,14 @@
import { Cargo } from "./toolchain";
import type { Ctx } from "./ctx";
import { createTaskFromRunnable, prepareEnv } from "./run";
-import { execute, isCargoRunnableArgs, unwrapUndefinable, log, normalizeDriveLetter } from "./util";
+import {
+ execute,
+ isCargoRunnableArgs,
+ unwrapUndefinable,
+ log,
+ normalizeDriveLetter,
+ Env,
+} from "./util";
import type { Config } from "./config";
// Here we want to keep track on everything that's currently running
@@ -206,10 +213,7 @@
destination: string;
};
-async function discoverSourceFileMap(
- env: Record<string, string>,
- cwd: string,
-): Promise<SourceFileMap | undefined> {
+async function discoverSourceFileMap(env: Env, cwd: string): Promise<SourceFileMap | undefined> {
const sysroot = env["RUSTC_TOOLCHAIN"];
if (sysroot) {
// let's try to use the default toolchain
@@ -232,7 +236,7 @@
type DebugConfigProvider<Type extends string, DebugConfig extends BaseDebugConfig<Type>> = {
executableProperty: keyof DebugConfig;
- environmentProperty: PropertyFetcher<DebugConfig, Record<string, string>, keyof DebugConfig>;
+ environmentProperty: PropertyFetcher<DebugConfig, Env, keyof DebugConfig>;
runnableArgsProperty: PropertyFetcher<DebugConfig, ra.CargoRunnableArgs, keyof DebugConfig>;
sourceFileMapProperty?: keyof DebugConfig;
type: Type;
@@ -276,7 +280,7 @@
"environment",
Object.entries(env).map((entry) => ({
name: entry[0],
- value: entry[1],
+ value: entry[1] ?? "",
})),
],
runnableArgsProperty: (runnableArgs: ra.CargoRunnableArgs) => [
@@ -304,10 +308,7 @@
},
};
-async function getDebugExecutable(
- runnableArgs: ra.CargoRunnableArgs,
- env: Record<string, string>,
-): Promise<string> {
+async function getDebugExecutable(runnableArgs: ra.CargoRunnableArgs, env: Env): Promise<string> {
const cargo = new Cargo(runnableArgs.workspaceRoot || ".", env);
const executable = await cargo.executableFromArgs(runnableArgs);
@@ -328,7 +329,7 @@
runnable: ra.Runnable,
runnableArgs: ra.CargoRunnableArgs,
executable: string,
- env: Record<string, string>,
+ env: Env,
sourceFileMap?: Record<string, string>,
): vscode.DebugConfiguration {
const {
@@ -380,14 +381,14 @@
args: string[];
sourceMap: Record<string, string> | undefined;
sourceLanguages: ["rust"];
- env: Record<string, string>;
+ env: Env;
} & BaseDebugConfig<"lldb">;
type NativeDebugConfig = {
target: string;
// See https://github.com/WebFreak001/code-debug/issues/359
arguments: string;
- env: Record<string, string>;
+ env: Env;
valuesFormatting: "prettyPrinters";
} & BaseDebugConfig<"gdb">;
diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts
index 95166c4..87c1d52 100644
--- a/src/tools/rust-analyzer/editors/code/src/run.ts
+++ b/src/tools/rust-analyzer/editors/code/src/run.ts
@@ -7,7 +7,7 @@
import { makeDebugConfig } from "./debug";
import type { Config } from "./config";
import type { LanguageClient } from "vscode-languageclient/node";
-import { log, unwrapUndefinable, type RustEditor } from "./util";
+import { Env, log, unwrapUndefinable, type RustEditor } from "./util";
const quickPickButtons = [
{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." },
@@ -122,11 +122,8 @@
}
}
-export function prepareBaseEnv(
- inheritEnv: boolean,
- base?: Record<string, string>,
-): Record<string, string> {
- const env: Record<string, string> = { RUST_BACKTRACE: "short" };
+export function prepareBaseEnv(inheritEnv: boolean, base?: Env): Env {
+ const env: Env = { RUST_BACKTRACE: "short" };
if (inheritEnv) {
Object.assign(env, process.env);
}
@@ -136,11 +133,7 @@
return env;
}
-export function prepareEnv(
- inheritEnv: boolean,
- runnableEnv?: Record<string, string>,
- runnableEnvCfg?: Record<string, string>,
-): Record<string, string> {
+export function prepareEnv(inheritEnv: boolean, runnableEnv?: Env, runnableEnvCfg?: Env): Env {
const env = prepareBaseEnv(inheritEnv, runnableEnv);
if (runnableEnvCfg) {
diff --git a/src/tools/rust-analyzer/editors/code/src/tasks.ts b/src/tools/rust-analyzer/editors/code/src/tasks.ts
index 730ec6d..eb0748a 100644
--- a/src/tools/rust-analyzer/editors/code/src/tasks.ts
+++ b/src/tools/rust-analyzer/editors/code/src/tasks.ts
@@ -1,6 +1,7 @@
import * as vscode from "vscode";
import type { Config } from "./config";
import * as toolchain from "./toolchain";
+import { Env } from "./util";
// This ends up as the `type` key in tasks.json. RLS also uses `cargo` and
// our configuration should be compatible with it so use the same key.
@@ -117,8 +118,8 @@
export async function targetToExecution(
definition: TaskDefinition,
options?: {
- env?: { [key: string]: string };
cwd?: string;
+ env?: Env;
},
cargo?: string,
): Promise<vscode.ProcessExecution | vscode.ShellExecution> {
@@ -131,7 +132,12 @@
command = definition.command;
args = definition.args || [];
}
- return new vscode.ProcessExecution(command, args, options);
+ return new vscode.ProcessExecution(command, args, {
+ cwd: options?.cwd,
+ env: Object.fromEntries(
+ Object.entries(options?.env ?? {}).map(([key, value]) => [key, value ?? ""]),
+ ),
+ });
}
export function activateTaskProvider(config: Config): vscode.Disposable {
diff --git a/src/tools/rust-analyzer/editors/code/src/toolchain.ts b/src/tools/rust-analyzer/editors/code/src/toolchain.ts
index a859ce6..06f75a8 100644
--- a/src/tools/rust-analyzer/editors/code/src/toolchain.ts
+++ b/src/tools/rust-analyzer/editors/code/src/toolchain.ts
@@ -3,7 +3,7 @@
import * as path from "path";
import * as readline from "readline";
import * as vscode from "vscode";
-import { log, memoizeAsync, unwrapUndefinable } from "./util";
+import { Env, log, memoizeAsync, unwrapUndefinable } from "./util";
import type { CargoRunnableArgs } from "./lsp_ext";
interface CompilationArtifact {
@@ -37,7 +37,7 @@
export class Cargo {
constructor(
readonly rootFolder: string,
- readonly env: Record<string, string>,
+ readonly env: Env,
) {}
// Made public for testing purposes
@@ -156,7 +156,7 @@
/** Mirrors `toolchain::cargo()` implementation */
// FIXME: The server should provide this
-export function cargoPath(env?: Record<string, string>): Promise<string> {
+export function cargoPath(env?: Env): Promise<string> {
if (env?.["RUSTC_TOOLCHAIN"]) {
return Promise.resolve("cargo");
}
diff --git a/src/tools/rust-analyzer/josh-sync.toml b/src/tools/rust-analyzer/josh-sync.toml
new file mode 100644
index 0000000..51ff0d7
--- /dev/null
+++ b/src/tools/rust-analyzer/josh-sync.toml
@@ -0,0 +1,2 @@
+repo = "rust-analyzer"
+filter = ":rev(55d9a533b309119c8acd13061581b43ae8840823:prefix=src/tools/rust-analyzer):/src/tools/rust-analyzer"
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index c2b1c15..2178caf 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-e05ab47e6c418fb2b9faa2eae9a7e70c65c98eaa
+733dab558992d902d6d17576de1da768094e2cf3
diff --git a/src/tools/rust-analyzer/triagebot.toml b/src/tools/rust-analyzer/triagebot.toml
index 2201b5a..27fdb67 100644
--- a/src/tools/rust-analyzer/triagebot.toml
+++ b/src/tools/rust-analyzer/triagebot.toml
@@ -17,6 +17,7 @@
"sync from downstream",
"Sync from rust",
"sync from rust",
+ "Rustc pull update",
]
labels = ["has-merge-commits", "S-waiting-on-author"]
@@ -27,3 +28,6 @@
# Prevents mentions in commits to avoid users being spammed
[no-mentions]
+
+# Automatically close and reopen PRs made by bots to run CI on them
+[bot-pull-requests]
diff --git a/src/tools/rust-analyzer/xtask/Cargo.toml b/src/tools/rust-analyzer/xtask/Cargo.toml
index 8cd5811..9d8a195 100644
--- a/src/tools/rust-analyzer/xtask/Cargo.toml
+++ b/src/tools/rust-analyzer/xtask/Cargo.toml
@@ -8,7 +8,6 @@
[dependencies]
anyhow.workspace = true
-directories = "6.0"
flate2 = "1.1.2"
write-json = "0.1.4"
xshell.workspace = true
diff --git a/src/tools/rust-analyzer/xtask/src/flags.rs b/src/tools/rust-analyzer/xtask/src/flags.rs
index 2fd471b..72f6215 100644
--- a/src/tools/rust-analyzer/xtask/src/flags.rs
+++ b/src/tools/rust-analyzer/xtask/src/flags.rs
@@ -59,20 +59,6 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
optional --dry-run
}
- cmd rustc-pull {
- /// rustc commit to pull.
- optional --commit refspec: String
- }
-
- cmd rustc-push {
- /// rust local path, e.g. `../rust-rust-analyzer`.
- required --rust-path rust_path: String
- /// rust fork name, e.g. `matklad/rust`.
- required --rust-fork rust_fork: String
- /// branch name.
- optional --branch branch: String
- }
-
cmd dist {
/// Use mimalloc allocator for server
optional --mimalloc
@@ -121,8 +107,6 @@ pub enum XtaskCmd {
Install(Install),
FuzzTests(FuzzTests),
Release(Release),
- RustcPull(RustcPull),
- RustcPush(RustcPush),
Dist(Dist),
PublishReleaseNotes(PublishReleaseNotes),
Metrics(Metrics),
@@ -152,18 +136,6 @@ pub struct Release {
}
#[derive(Debug)]
-pub struct RustcPull {
- pub commit: Option<String>,
-}
-
-#[derive(Debug)]
-pub struct RustcPush {
- pub rust_path: String,
- pub rust_fork: String,
- pub branch: Option<String>,
-}
-
-#[derive(Debug)]
pub struct Dist {
pub mimalloc: bool,
pub jemalloc: bool,
diff --git a/src/tools/rust-analyzer/xtask/src/main.rs b/src/tools/rust-analyzer/xtask/src/main.rs
index aaa8d0e..c5ad49c 100644
--- a/src/tools/rust-analyzer/xtask/src/main.rs
+++ b/src/tools/rust-analyzer/xtask/src/main.rs
@@ -42,8 +42,6 @@ fn main() -> anyhow::Result<()> {
flags::XtaskCmd::Install(cmd) => cmd.run(sh),
flags::XtaskCmd::FuzzTests(_) => run_fuzzer(sh),
flags::XtaskCmd::Release(cmd) => cmd.run(sh),
- flags::XtaskCmd::RustcPull(cmd) => cmd.run(sh),
- flags::XtaskCmd::RustcPush(cmd) => cmd.run(sh),
flags::XtaskCmd::Dist(cmd) => cmd.run(sh),
flags::XtaskCmd::PublishReleaseNotes(cmd) => cmd.run(sh),
flags::XtaskCmd::Metrics(cmd) => cmd.run(sh),
diff --git a/src/tools/rust-analyzer/xtask/src/release.rs b/src/tools/rust-analyzer/xtask/src/release.rs
index e41f4ce..d06a25c 100644
--- a/src/tools/rust-analyzer/xtask/src/release.rs
+++ b/src/tools/rust-analyzer/xtask/src/release.rs
@@ -1,12 +1,5 @@
mod changelog;
-use std::process::{Command, Stdio};
-use std::thread;
-use std::time::Duration;
-
-use anyhow::{Context as _, bail};
-use directories::ProjectDirs;
-use stdx::JodChild;
use xshell::{Shell, cmd};
use crate::{date_iso, flags, is_release_tag, project_root};
@@ -59,171 +52,3 @@ pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
Ok(())
}
}
-
-// git sync implementation adapted from https://github.com/rust-lang/miri/blob/62039ac/miri-script/src/commands.rs
-impl flags::RustcPull {
- pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
- sh.change_dir(project_root());
- let commit = self.commit.map(Result::Ok).unwrap_or_else(|| {
- let rust_repo_head =
- cmd!(sh, "git ls-remote https://github.com/rust-lang/rust/ HEAD").read()?;
- rust_repo_head
- .split_whitespace()
- .next()
- .map(|front| front.trim().to_owned())
- .ok_or_else(|| anyhow::format_err!("Could not obtain Rust repo HEAD from remote."))
- })?;
- // Make sure the repo is clean.
- if !cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty() {
- bail!("working directory must be clean before running `cargo xtask pull`");
- }
- // This should not add any new root commits. So count those before and after merging.
- let num_roots = || -> anyhow::Result<u32> {
- Ok(cmd!(sh, "git rev-list HEAD --max-parents=0 --count")
- .read()
- .context("failed to determine the number of root commits")?
- .parse::<u32>()?)
- };
- let num_roots_before = num_roots()?;
- // Make sure josh is running.
- let josh = start_josh()?;
-
- // Update rust-version file. As a separate commit, since making it part of
- // the merge has confused the heck out of josh in the past.
- // We pass `--no-verify` to avoid running any git hooks that might exist,
- // in case they dirty the repository.
- sh.write_file("rust-version", format!("{commit}\n"))?;
- const PREPARING_COMMIT_MESSAGE: &str = "Preparing for merge from rust-lang/rust";
- cmd!(sh, "git commit rust-version --no-verify -m {PREPARING_COMMIT_MESSAGE}")
- .run()
- .context("FAILED to commit rust-version file, something went wrong")?;
-
- // Fetch given rustc commit.
- cmd!(sh, "git fetch http://localhost:{JOSH_PORT}/rust-lang/rust.git@{commit}{JOSH_FILTER}.git")
- .run()
- .inspect_err(|_| {
- // Try to un-do the previous `git commit`, to leave the repo in the state we found it it.
- cmd!(sh, "git reset --hard HEAD^")
- .run()
- .expect("FAILED to clean up again after failed `git fetch`, sorry for that");
- })
- .context("FAILED to fetch new commits, something went wrong (committing the rust-version file has been undone)")?;
-
- // Merge the fetched commit.
- const MERGE_COMMIT_MESSAGE: &str = "Merge from rust-lang/rust";
- cmd!(sh, "git merge FETCH_HEAD --no-verify --no-ff -m {MERGE_COMMIT_MESSAGE}")
- .run()
- .context("FAILED to merge new commits, something went wrong")?;
-
- // Check that the number of roots did not increase.
- if num_roots()? != num_roots_before {
- bail!("Josh created a new root commit. This is probably not the history you want.");
- }
-
- drop(josh);
- Ok(())
- }
-}
-
-impl flags::RustcPush {
- pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
- let branch = self.branch.as_deref().unwrap_or("sync-from-ra");
- let rust_path = self.rust_path;
- let rust_fork = self.rust_fork;
-
- sh.change_dir(project_root());
- let base = sh.read_file("rust-version")?.trim().to_owned();
- // Make sure the repo is clean.
- if !cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty() {
- bail!("working directory must be clean before running `cargo xtask push`");
- }
- // Make sure josh is running.
- let josh = start_josh()?;
-
- // Find a repo we can do our preparation in.
- sh.change_dir(rust_path);
-
- // Prepare the branch. Pushing works much better if we use as base exactly
- // the commit that we pulled from last time, so we use the `rust-version`
- // file to find out which commit that would be.
- println!("Preparing {rust_fork} (base: {base})...");
- if cmd!(sh, "git fetch https://github.com/{rust_fork} {branch}")
- .ignore_stderr()
- .read()
- .is_ok()
- {
- bail!(
- "The branch `{branch}` seems to already exist in `https://github.com/{rust_fork}`. Please delete it and try again."
- );
- }
- cmd!(sh, "git fetch https://github.com/rust-lang/rust {base}").run()?;
- cmd!(sh, "git push https://github.com/{rust_fork} {base}:refs/heads/{branch}")
- .ignore_stdout()
- .ignore_stderr() // silence the "create GitHub PR" message
- .run()?;
- println!();
-
- // Do the actual push.
- sh.change_dir(project_root());
- println!("Pushing rust-analyzer changes...");
- cmd!(
- sh,
- "git push http://localhost:{JOSH_PORT}/{rust_fork}.git{JOSH_FILTER}.git HEAD:{branch}"
- )
- .run()?;
- println!();
-
- // Do a round-trip check to make sure the push worked as expected.
- cmd!(
- sh,
- "git fetch http://localhost:{JOSH_PORT}/{rust_fork}.git{JOSH_FILTER}.git {branch}"
- )
- .ignore_stderr()
- .read()?;
- let head = cmd!(sh, "git rev-parse HEAD").read()?;
- let fetch_head = cmd!(sh, "git rev-parse FETCH_HEAD").read()?;
- if head != fetch_head {
- bail!(
- "Josh created a non-roundtrip push! Do NOT merge this into rustc!\n\
- Expected {head}, got {fetch_head}."
- );
- }
- println!(
- "Confirmed that the push round-trips back to rust-analyzer properly. Please create a rustc PR:"
- );
- // https://github.com/github-linguist/linguist/compare/master...octocat:linguist:master
- let fork_path = rust_fork.replace('/', ":");
- println!(
- " https://github.com/rust-lang/rust/compare/{fork_path}:{branch}?quick_pull=1&title=Subtree+update+of+rust-analyzer&body=r?+@ghost"
- );
-
- drop(josh);
- Ok(())
- }
-}
-
-/// Used for rustc syncs.
-const JOSH_FILTER: &str = ":rev(55d9a533b309119c8acd13061581b43ae8840823:prefix=src/tools/rust-analyzer):/src/tools/rust-analyzer";
-const JOSH_PORT: &str = "42042";
-
-fn start_josh() -> anyhow::Result<impl Drop> {
- // Determine cache directory.
- let local_dir = {
- let user_dirs = ProjectDirs::from("org", "rust-lang", "rust-analyzer-josh").unwrap();
- user_dirs.cache_dir().to_owned()
- };
-
- // Start josh, silencing its output.
- let mut cmd = Command::new("josh-proxy");
- cmd.arg("--local").arg(local_dir);
- cmd.arg("--remote").arg("https://github.com");
- cmd.arg("--port").arg(JOSH_PORT);
- cmd.arg("--no-background");
- cmd.stdout(Stdio::null());
- cmd.stderr(Stdio::null());
- let josh = cmd.spawn().context("failed to start josh-proxy, make sure it is installed")?;
- // Give it some time so hopefully the port is open. (100ms was not enough.)
- thread::sleep(Duration::from_millis(200));
-
- Ok(JodChild(josh))
-}
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index e363668..5f30c75 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -1343,9 +1343,9 @@
[[package]]
name = "redox_syscall"
-version = "0.5.13"
+version = "0.5.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
+checksum = "7251471db004e509f4e75a62cca9435365b5ec7bcdff530d612ac7c87c44a792"
dependencies = [
"bitflags 2.9.1",
]
diff --git a/src/tools/rustc-perf b/src/tools/rustc-perf
index 6a70166..dde879c 160000
--- a/src/tools/rustc-perf
+++ b/src/tools/rustc-perf
@@ -1 +1 @@
-Subproject commit 6a70166b92a1b1560cb3cf056427b011b2a1f2bf
+Subproject commit dde879cf1087cb34a32287bd8ccc4d545bb9fee5
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index d995106..c1f27de 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -6,7 +6,7 @@
[dependencies]
build_helper = { path = "../../build_helper" }
-cargo_metadata = "0.19"
+cargo_metadata = "0.21"
regex = "1"
miropt-test-tools = { path = "../miropt-test-tools" }
walkdir = "2"
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index f43f5ea..858b058 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -73,7 +73,6 @@
// tidy-alphabetical-start
("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None, &[]),
("src/bootstrap", EXCEPTIONS_BOOTSTRAP, None, &[]),
- ("src/ci/docker/host-x86_64/test-various/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None, &[]),
("src/tools/cargo", EXCEPTIONS_CARGO, None, &["src/tools/cargo"]),
//("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored
//("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored
@@ -81,6 +80,7 @@
("src/tools/rustbook", EXCEPTIONS_RUSTBOOK, None, &["src/doc/book", "src/doc/reference"]),
("src/tools/rustc-perf", EXCEPTIONS_RUSTC_PERF, None, &["src/tools/rustc-perf"]),
("src/tools/test-float-parse", EXCEPTIONS, None, &[]),
+ ("tests/run-make/uefi-qemu/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None, &[]),
// tidy-alphabetical-end
];
@@ -135,6 +135,7 @@
("libz-rs-sys", "Zlib"),
("normalize-line-endings", "Apache-2.0"),
("openssl", "Apache-2.0"),
+ ("ring", "Apache-2.0 AND ISC"),
("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0
("similar", "Apache-2.0"),
("sized-chunks", "MPL-2.0+"),
@@ -166,7 +167,7 @@
("brotli-decompressor", "BSD-3-Clause/MIT"),
("encoding_rs", "(Apache-2.0 OR MIT) AND BSD-3-Clause"),
("inferno", "CDDL-1.0"),
- ("ring", NON_STANDARD_LICENSE), // see EXCEPTIONS_NON_STANDARD_LICENSE_DEPS for more.
+ ("option-ext", "MPL-2.0"),
("ryu", "Apache-2.0 OR BSL-1.0"),
("snap", "BSD-3-Clause"),
("subtle", "BSD-3-Clause"),
@@ -225,20 +226,6 @@
("r-efi", "MIT OR Apache-2.0 OR LGPL-2.1-or-later"), // LGPL is not acceptable, but we use it under MIT OR Apache-2.0
];
-/// Placeholder for non-standard license file.
-const NON_STANDARD_LICENSE: &str = "NON_STANDARD_LICENSE";
-
-/// These dependencies have non-standard licenses but are genenrally permitted.
-const EXCEPTIONS_NON_STANDARD_LICENSE_DEPS: &[&str] = &[
- // `ring` is included because it is an optional dependency of `hyper`,
- // which is a training data in rustc-perf for optimized build.
- // The license of it is generally `ISC AND MIT AND OpenSSL`,
- // though the `package.license` field is not set.
- //
- // See https://github.com/briansmith/ring/issues/902
- "ring",
-];
-
const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!());
/// Crates rustc is allowed to depend on. Avoid adding to the list if possible.
@@ -378,6 +365,7 @@
"serde",
"serde_derive",
"serde_json",
+ "serde_path_to_error",
"sha1",
"sha2",
"sharded-slab",
@@ -597,7 +585,7 @@ pub fn check(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) {
.other_options(vec!["--locked".to_owned()]);
let metadata = t!(cmd.exec());
- check_license_exceptions(&metadata, exceptions, bad);
+ check_license_exceptions(&metadata, workspace, exceptions, bad);
if let Some((crates, permitted_deps)) = permitted_deps {
check_permitted_dependencies(&metadata, workspace, permitted_deps, crates, bad);
}
@@ -631,8 +619,8 @@ fn check_proc_macro_dep_list(root: &Path, cargo: &Path, bless: bool, bad: &mut b
proc_macro_deps.retain(|pkg| !is_proc_macro_pkg(&metadata[pkg]));
let proc_macro_deps: HashSet<_> =
- proc_macro_deps.into_iter().map(|dep| metadata[dep].name.clone()).collect();
- let expected = proc_macro_deps::CRATES.iter().map(|s| s.to_string()).collect::<HashSet<_>>();
+ proc_macro_deps.into_iter().map(|dep| metadata[dep].name.as_ref()).collect();
+ let expected = proc_macro_deps::CRATES.iter().copied().collect::<HashSet<_>>();
let needs_blessing = proc_macro_deps.difference(&expected).next().is_some()
|| expected.difference(&proc_macro_deps).next().is_some();
@@ -716,7 +704,7 @@ fn check_runtime_license_exceptions(metadata: &Metadata, bad: &mut bool) {
// See https://github.com/rust-lang/rust/issues/62620 for more.
// In general, these should never be added and this exception
// should not be taken as precedent for any new target.
- if pkg.name == "fortanix-sgx-abi" && pkg.license.as_deref() == Some("MPL-2.0") {
+ if *pkg.name == "fortanix-sgx-abi" && pkg.license.as_deref() == Some("MPL-2.0") {
continue;
}
@@ -728,36 +716,38 @@ fn check_runtime_license_exceptions(metadata: &Metadata, bad: &mut bool) {
/// Check that all licenses of tool dependencies are in the valid list in `LICENSES`.
///
/// Packages listed in `exceptions` are allowed for tools.
-fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], bad: &mut bool) {
+fn check_license_exceptions(
+ metadata: &Metadata,
+ workspace: &str,
+ exceptions: &[(&str, &str)],
+ bad: &mut bool,
+) {
// Validate the EXCEPTIONS list hasn't changed.
for (name, license) in exceptions {
// Check that the package actually exists.
- if !metadata.packages.iter().any(|p| p.name == *name) {
+ if !metadata.packages.iter().any(|p| *p.name == *name) {
tidy_error!(
bad,
- "could not find exception package `{}`\n\
+ "could not find exception package `{}` in workspace `{workspace}`\n\
Remove from EXCEPTIONS list if it is no longer used.",
name
);
}
// Check that the license hasn't changed.
- for pkg in metadata.packages.iter().filter(|p| p.name == *name) {
+ for pkg in metadata.packages.iter().filter(|p| *p.name == *name) {
match &pkg.license {
None => {
- if *license == NON_STANDARD_LICENSE
- && EXCEPTIONS_NON_STANDARD_LICENSE_DEPS.contains(&pkg.name.as_str())
- {
- continue;
- }
tidy_error!(
bad,
- "dependency exception `{}` does not declare a license expression",
+ "dependency exception `{}` in workspace `{workspace}` does not declare a license expression",
pkg.id
);
}
Some(pkg_license) => {
if pkg_license.as_str() != *license {
- println!("dependency exception `{name}` license has changed");
+ println!(
+ "dependency exception `{name}` license in workspace `{workspace}` has changed"
+ );
println!(" previously `{license}` now `{pkg_license}`");
println!(" update EXCEPTIONS for the new license");
*bad = true;
@@ -781,12 +771,21 @@ fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], ba
let license = match &pkg.license {
Some(license) => license,
None => {
- tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id);
+ tidy_error!(
+ bad,
+ "dependency `{}` in workspace `{workspace}` does not define a license expression",
+ pkg.id
+ );
continue;
}
};
if !LICENSES.contains(&license.as_str()) {
- tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id);
+ tidy_error!(
+ bad,
+ "invalid license `{}` for package `{}` in workspace `{workspace}`",
+ license,
+ pkg.id
+ );
}
}
}
@@ -816,9 +815,9 @@ fn compare(pkg: &Package, permitted: &str) -> bool {
let Ok(version) = Version::parse(version) else {
return false;
};
- pkg.name == name && pkg.version == version
+ *pkg.name == name && pkg.version == version
} else {
- pkg.name == permitted
+ *pkg.name == permitted
}
}
if !deps.iter().any(|dep_id| compare(pkg_from_id(metadata, dep_id), permitted)) {
@@ -866,7 +865,7 @@ fn compare(pkg: &Package, permitted: &str) -> bool {
/// Finds a package with the given name.
fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
- let mut i = metadata.packages.iter().filter(|p| p.name == name);
+ let mut i = metadata.packages.iter().filter(|p| *p.name == name);
let result =
i.next().unwrap_or_else(|| panic!("could not find package `{name}` in package list"));
assert!(i.next().is_none(), "more than one package found for `{name}`");
diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/extra_checks/mod.rs
similarity index 96%
rename from src/tools/tidy/src/ext_tool_checks.rs
rename to src/tools/tidy/src/extra_checks/mod.rs
index 911d4da..f90f716 100644
--- a/src/tools/tidy/src/ext_tool_checks.rs
+++ b/src/tools/tidy/src/extra_checks/mod.rs
@@ -50,6 +50,7 @@ pub fn check(
ci_info: &CiInfo,
librustdoc_path: &Path,
tools_path: &Path,
+ npm: &Path,
bless: bool,
extra_checks: Option<&str>,
pos_args: &[String],
@@ -61,6 +62,7 @@ pub fn check(
ci_info,
librustdoc_path,
tools_path,
+ npm,
bless,
extra_checks,
pos_args,
@@ -75,6 +77,7 @@ fn check_impl(
ci_info: &CiInfo,
librustdoc_path: &Path,
tools_path: &Path,
+ npm: &Path,
bless: bool,
extra_checks: Option<&str>,
pos_args: &[String],
@@ -83,7 +86,7 @@ fn check_impl(
std::env::var("TIDY_PRINT_DIFF").is_ok_and(|v| v.eq_ignore_ascii_case("true") || v == "1");
// Split comma-separated args up
- let lint_args = match extra_checks {
+ let mut lint_args = match extra_checks {
Some(s) => s
.strip_prefix("--extra-checks=")
.unwrap()
@@ -96,11 +99,7 @@ fn check_impl(
})
.filter_map(|(res, src)| match res {
Ok(arg) => {
- if arg.is_inactive_auto(ci_info) {
- None
- } else {
- Some(arg)
- }
+ Some(arg)
}
Err(err) => {
// only warn because before bad extra checks would be silently ignored.
@@ -111,6 +110,11 @@ fn check_impl(
.collect(),
None => vec![],
};
+ if lint_args.iter().any(|ck| ck.auto) {
+ crate::files_modified_batch_filter(ci_info, &mut lint_args, |ck, path| {
+ ck.is_non_auto_or_matches(path)
+ });
+ }
macro_rules! extra_check {
($lang:ident, $kind:ident) => {
@@ -293,7 +297,7 @@ macro_rules! extra_check {
}
if js_lint || js_typecheck {
- rustdoc_js::npm_install(root_path, outdir)?;
+ rustdoc_js::npm_install(root_path, outdir, npm)?;
}
if js_lint {
@@ -718,10 +722,10 @@ fn matches(&self, lang: ExtraCheckLang, kind: ExtraCheckKind) -> bool {
self.lang == lang && self.kind.map(|k| k == kind).unwrap_or(true)
}
- /// Returns `true` if this is an auto arg and the relevant files are not modified.
- fn is_inactive_auto(&self, ci_info: &CiInfo) -> bool {
+ /// Returns `false` if this is an auto arg and the passed filename does not trigger the auto rule
+ fn is_non_auto_or_matches(&self, filepath: &str) -> bool {
if !self.auto {
- return false;
+ return true;
}
let ext = match self.lang {
ExtraCheckLang::Py => ".py",
@@ -729,12 +733,15 @@ fn is_inactive_auto(&self, ci_info: &CiInfo) -> bool {
ExtraCheckLang::Shell => ".sh",
ExtraCheckLang::Js => ".js",
ExtraCheckLang::Spellcheck => {
- return !crate::files_modified(ci_info, |s| {
- SPELLCHECK_DIRS.iter().any(|dir| Path::new(s).starts_with(dir))
- });
+ for dir in SPELLCHECK_DIRS {
+ if Path::new(filepath).starts_with(dir) {
+ return true;
+ }
+ }
+ return false;
}
};
- !crate::files_modified(ci_info, |s| s.ends_with(ext))
+ filepath.ends_with(ext)
}
fn has_supported_kind(&self) -> bool {
diff --git a/src/tools/tidy/src/ext_tool_checks/rustdoc_js.rs b/src/tools/tidy/src/extra_checks/rustdoc_js.rs
similarity index 93%
rename from src/tools/tidy/src/ext_tool_checks/rustdoc_js.rs
rename to src/tools/tidy/src/extra_checks/rustdoc_js.rs
index c1a62ce..7708b12 100644
--- a/src/tools/tidy/src/ext_tool_checks/rustdoc_js.rs
+++ b/src/tools/tidy/src/extra_checks/rustdoc_js.rs
@@ -23,9 +23,8 @@ fn spawn_cmd(cmd: &mut Command) -> Result<Child, io::Error> {
}
/// install all js dependencies from package.json.
-pub(super) fn npm_install(root_path: &Path, outdir: &Path) -> Result<(), super::Error> {
- // FIXME(lolbinarycat): make this obey build.npm bootstrap option
- npm::install(root_path, outdir, Path::new("npm"))?;
+pub(super) fn npm_install(root_path: &Path, outdir: &Path, npm: &Path) -> Result<(), super::Error> {
+ npm::install(root_path, outdir, npm)?;
Ok(())
}
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 5f6796a..4ea9d05 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -125,48 +125,69 @@ pub fn git_diff<S: AsRef<OsStr>>(base_commit: &str, extra_arg: S) -> Option<Stri
Some(String::from_utf8_lossy(&output.stdout).into())
}
-/// Returns true if any modified file matches the predicate, if we are in CI, or if unable to list modified files.
-pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool {
+/// Similar to `files_modified`, but only involves a single call to `git`.
+///
+/// removes all elements from `items` that do not cause any match when `pred` is called with the list of modifed files.
+///
+/// if in CI, no elements will be removed.
+pub fn files_modified_batch_filter<T>(
+ ci_info: &CiInfo,
+ items: &mut Vec<T>,
+ pred: impl Fn(&T, &str) -> bool,
+) {
if CiEnv::is_ci() {
// assume everything is modified on CI because we really don't want false positives there.
- return true;
+ return;
}
let Some(base_commit) = &ci_info.base_commit else {
eprintln!("No base commit, assuming all files are modified");
- return true;
+ return;
};
match crate::git_diff(base_commit, "--name-status") {
Some(output) => {
- let modified_files = output.lines().filter_map(|ln| {
- let (status, name) = ln
- .trim_end()
- .split_once('\t')
- .expect("bad format from `git diff --name-status`");
- if status == "M" { Some(name) } else { None }
- });
- for modified_file in modified_files {
- if pred(modified_file) {
- return true;
+ let modified_files: Vec<_> = output
+ .lines()
+ .filter_map(|ln| {
+ let (status, name) = ln
+ .trim_end()
+ .split_once('\t')
+ .expect("bad format from `git diff --name-status`");
+ if status == "M" { Some(name) } else { None }
+ })
+ .collect();
+ items.retain(|item| {
+ for modified_file in &modified_files {
+ if pred(item, modified_file) {
+ // at least one predicate matches, keep this item.
+ return true;
+ }
}
- }
- false
+ // no predicates matched, remove this item.
+ false
+ });
}
None => {
eprintln!("warning: failed to run `git diff` to check for changes");
eprintln!("warning: assuming all files are modified");
- true
}
}
}
+/// Returns true if any modified file matches the predicate, if we are in CI, or if unable to list modified files.
+pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool {
+ let mut v = vec![()];
+ files_modified_batch_filter(ci_info, &mut v, |_, p| pred(p));
+ !v.is_empty()
+}
+
pub mod alphabetical;
pub mod bins;
pub mod debug_artifacts;
pub mod deps;
pub mod edition;
pub mod error_codes;
-pub mod ext_tool_checks;
pub mod extdeps;
+pub mod extra_checks;
pub mod features;
pub mod filenames;
pub mod fluent_alphabetical;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 13b20f3..cd2567d 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -29,6 +29,7 @@ fn main() {
let concurrency: NonZeroUsize =
FromStr::from_str(&env::args().nth(4).expect("need concurrency"))
.expect("concurrency must be a number");
+ let npm: PathBuf = env::args_os().nth(5).expect("need name/path of npm command").into();
let root_manifest = root_path.join("Cargo.toml");
let src_path = root_path.join("src");
@@ -127,9 +128,9 @@ macro_rules! check {
check!(pal, &library_path);
// Checks that need to be done for both the compiler and std libraries.
- check!(unit_tests, &src_path);
- check!(unit_tests, &compiler_path);
- check!(unit_tests, &library_path);
+ check!(unit_tests, &src_path, false);
+ check!(unit_tests, &compiler_path, false);
+ check!(unit_tests, &library_path, true);
if bins::check_filesystem_support(&[&root_path], &output_directory) {
check!(bins, &root_path);
@@ -176,12 +177,13 @@ macro_rules! check {
check!(unstable_book, &src_path, collected);
check!(
- ext_tool_checks,
+ extra_checks,
&root_path,
&output_directory,
&ci_info,
&librustdoc_path,
&tools_path,
+ &npm,
bless,
extra_checks,
pos_args
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 35ed61e..fca097c 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -519,8 +519,11 @@ fn skip(path: &Path, is_dir: bool) -> bool {
.any(|directive| matches!(directive, Directive::Ignore(_)));
let has_alphabetical_directive = line.contains("tidy-alphabetical-start")
|| line.contains("tidy-alphabetical-end");
- let has_recognized_directive =
- has_recognized_ignore_directive || has_alphabetical_directive;
+ let has_other_tidy_ignore_directive =
+ line.contains("ignore-tidy-target-specific-tests");
+ let has_recognized_directive = has_recognized_ignore_directive
+ || has_alphabetical_directive
+ || has_other_tidy_ignore_directive;
if contains_potential_directive && (!has_recognized_directive) {
err("Unrecognized tidy directive")
}
diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs
index f4a6783..b2d5f25 100644
--- a/src/tools/tidy/src/target_specific_tests.rs
+++ b/src/tools/tidy/src/target_specific_tests.rs
@@ -12,12 +12,16 @@
#[derive(Default, Debug)]
struct RevisionInfo<'a> {
- target_arch: Option<&'a str>,
+ target_arch: Option<Option<&'a str>>,
llvm_components: Option<Vec<&'a str>>,
}
pub fn check(tests_path: &Path, bad: &mut bool) {
crate::walk::walk(tests_path, |path, _is_dir| filter_not_rust(path), &mut |entry, content| {
+ if content.contains("// ignore-tidy-target-specific-tests") {
+ return;
+ }
+
let file = entry.path().display();
let mut header_map = BTreeMap::new();
iter_header(content, &mut |HeaderLine { revision, directive, .. }| {
@@ -34,10 +38,11 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
&& let Some((_, v)) = compile_flags.split_once("--target")
{
let v = v.trim_start_matches([' ', '=']);
- let v = if v == "{{target}}" { Some((v, v)) } else { v.split_once("-") };
- if let Some((arch, _)) = v {
- let info = header_map.entry(revision).or_insert(RevisionInfo::default());
- info.target_arch.replace(arch);
+ let info = header_map.entry(revision).or_insert(RevisionInfo::default());
+ if v.starts_with("{{") {
+ info.target_arch.replace(None);
+ } else if let Some((arch, _)) = v.split_once("-") {
+ info.target_arch.replace(Some(arch));
} else {
eprintln!("{file}: seems to have a malformed --target value");
*bad = true;
@@ -54,9 +59,11 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
let rev = rev.unwrap_or("[unspecified]");
match (target_arch, llvm_components) {
(None, None) => {}
- (Some(_), None) => {
+ (Some(target_arch), None) => {
+ let llvm_component =
+ target_arch.map_or_else(|| "<arch>".to_string(), arch_to_llvm_component);
eprintln!(
- "{file}: revision {rev} should specify `{LLVM_COMPONENTS_HEADER}` as it has `--target` set"
+ "{file}: revision {rev} should specify `{LLVM_COMPONENTS_HEADER} {llvm_component}` as it has `--target` set"
);
*bad = true;
}
@@ -66,11 +73,45 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
);
*bad = true;
}
- (Some(_), Some(_)) => {
- // FIXME: check specified components against the target architectures we
- // gathered.
+ (Some(target_arch), Some(llvm_components)) => {
+ if let Some(target_arch) = target_arch {
+ let llvm_component = arch_to_llvm_component(target_arch);
+ if !llvm_components.contains(&llvm_component.as_str()) {
+ eprintln!(
+ "{file}: revision {rev} should specify `{LLVM_COMPONENTS_HEADER} {llvm_component}` as it has `--target` set"
+ );
+ *bad = true;
+ }
+ }
}
}
}
});
}
+
+fn arch_to_llvm_component(arch: &str) -> String {
+ // NOTE: This is an *approximate* mapping of Rust's `--target` architecture to LLVM component
+ // names. It is not intended to be an authoritative source, but rather a best-effort that's good
+ // enough for the purpose of this tidy check.
+ match arch {
+ "amdgcn" => "amdgpu".into(),
+ "aarch64_be" | "arm64_32" | "arm64e" | "arm64ec" => "aarch64".into(),
+ "i386" | "i586" | "i686" | "x86" | "x86_64" | "x86_64h" => "x86".into(),
+ "loongarch32" | "loongarch64" => "loongarch".into(),
+ "nvptx64" => "nvptx".into(),
+ "s390x" => "systemz".into(),
+ "sparc64" | "sparcv9" => "sparc".into(),
+ "wasm32" | "wasm32v1" | "wasm64" => "webassembly".into(),
+ _ if arch.starts_with("armeb")
+ || arch.starts_with("armv")
+ || arch.starts_with("thumbv") =>
+ {
+ "arm".into()
+ }
+ _ if arch.starts_with("bpfe") => "bpf".into(),
+ _ if arch.starts_with("mips") => "mips".into(),
+ _ if arch.starts_with("powerpc") => "powerpc".into(),
+ _ if arch.starts_with("riscv") => "riscv".into(),
+ _ => arch.to_ascii_lowercase(),
+ }
+}
diff --git a/src/tools/tidy/src/unit_tests.rs b/src/tools/tidy/src/unit_tests.rs
index df9146b..3d14a46 100644
--- a/src/tools/tidy/src/unit_tests.rs
+++ b/src/tools/tidy/src/unit_tests.rs
@@ -1,44 +1,60 @@
//! Tidy check to ensure `#[test]` and `#[bench]` are not used directly inside
-//! `core` or `alloc`.
+//! of the standard library.
//!
//! `core` and `alloc` cannot be tested directly due to duplicating lang items.
//! All tests and benchmarks must be written externally in
//! `{coretests,alloctests}/{tests,benches}`.
//!
-//! Outside of `core` and `alloc`, tests and benchmarks should be outlined into
-//! separate files named `tests.rs` or `benches.rs`, or directories named
+//! Outside of the standard library, tests and benchmarks should be outlined
+//! into separate files named `tests.rs` or `benches.rs`, or directories named
//! `tests` or `benches` unconfigured during normal build.
use std::path::Path;
use crate::walk::{filter_dirs, walk};
-pub fn check(root_path: &Path, bad: &mut bool) {
- let core = root_path.join("core");
- let core_copy = core.clone();
- let is_core = move |path: &Path| path.starts_with(&core);
- let alloc = root_path.join("alloc");
- let alloc_copy = alloc.clone();
- let is_alloc = move |path: &Path| path.starts_with(&alloc);
-
+pub fn check(root_path: &Path, stdlib: bool, bad: &mut bool) {
let skip = move |path: &Path, is_dir| {
let file_name = path.file_name().unwrap_or_default();
+
+ // Skip excluded directories and non-rust files
if is_dir {
- filter_dirs(path)
- || path.ends_with("src/doc")
- || (file_name == "tests" || file_name == "benches")
- && !is_core(path)
- && !is_alloc(path)
+ if filter_dirs(path) || path.ends_with("src/doc") {
+ return true;
+ }
} else {
let extension = path.extension().unwrap_or_default();
- extension != "rs"
- || (file_name == "tests.rs" || file_name == "benches.rs")
- && !is_core(path)
- && !is_alloc(path)
- // Tests which use non-public internals and, as such, need to
- // have the types in the same crate as the tests themselves. See
- // the comment in alloctests/lib.rs.
- || path.ends_with("library/alloc/src/collections/btree/borrow/tests.rs")
+ if extension != "rs" {
+ return true;
+ }
+ }
+
+ // Tests in a separate package are always allowed
+ if is_dir && file_name != "tests" && file_name.as_encoded_bytes().ends_with(b"tests") {
+ return true;
+ }
+
+ if !stdlib {
+ // Outside of the standard library tests may also be in separate files in the same crate
+ if is_dir {
+ if file_name == "tests" || file_name == "benches" {
+ return true;
+ }
+ } else {
+ if file_name == "tests.rs" || file_name == "benches.rs" {
+ return true;
+ }
+ }
+ }
+
+ if is_dir {
+ // FIXME remove those exceptions once no longer necessary
+ file_name == "std_detect" || file_name == "std" || file_name == "test"
+ } else {
+ // Tests which use non-public internals and, as such, need to
+ // have the types in the same crate as the tests themselves. See
+ // the comment in alloctests/lib.rs.
+ path.ends_with("library/alloc/src/collections/btree/borrow/tests.rs")
|| path.ends_with("library/alloc/src/collections/btree/map/tests.rs")
|| path.ends_with("library/alloc/src/collections/btree/node/tests.rs")
|| path.ends_with("library/alloc/src/collections/btree/set/tests.rs")
@@ -50,22 +66,29 @@ pub fn check(root_path: &Path, bad: &mut bool) {
walk(root_path, skip, &mut |entry, contents| {
let path = entry.path();
- let is_core = path.starts_with(&core_copy);
- let is_alloc = path.starts_with(&alloc_copy);
+ let package = path
+ .strip_prefix(root_path)
+ .unwrap()
+ .components()
+ .next()
+ .unwrap()
+ .as_os_str()
+ .to_str()
+ .unwrap();
for (i, line) in contents.lines().enumerate() {
let line = line.trim();
let is_test = || line.contains("#[test]") && !line.contains("`#[test]");
let is_bench = || line.contains("#[bench]") && !line.contains("`#[bench]");
- let manual_skip = line.contains("//tidy:skip");
- if !line.starts_with("//") && (is_test() || is_bench()) && !manual_skip {
- let explanation = if is_core {
- "`core` unit tests and benchmarks must be placed into `coretests`"
- } else if is_alloc {
- "`alloc` unit tests and benchmarks must be placed into `alloctests`"
+ if !line.starts_with("//") && (is_test() || is_bench()) {
+ let explanation = if stdlib {
+ format!(
+ "`{package}` unit tests and benchmarks must be placed into `{package}tests`"
+ )
} else {
"unit tests and benchmarks must be placed into \
separate files or directories named \
`tests.rs`, `benches.rs`, `tests` or `benches`"
+ .to_owned()
};
let name = if is_test() { "test" } else { "bench" };
tidy_error!(
diff --git a/tests/assembly-llvm/asm/aarch64-outline-atomics.rs b/tests/assembly-llvm/asm/aarch64-outline-atomics.rs
index 5990fb8..22599c1 100644
--- a/tests/assembly-llvm/asm/aarch64-outline-atomics.rs
+++ b/tests/assembly-llvm/asm/aarch64-outline-atomics.rs
@@ -1,7 +1,5 @@
//@ assembly-output: emit-asm
//@ compile-flags: -Copt-level=3
-//@ compile-flags: --target aarch64-unknown-linux-gnu
-//@ needs-llvm-components: aarch64
//@ only-aarch64
//@ only-linux
diff --git a/tests/assembly-llvm/dwarf-mixed-versions-lto.rs b/tests/assembly-llvm/dwarf-mixed-versions-lto.rs
index 9910a6e..828328d 100644
--- a/tests/assembly-llvm/dwarf-mixed-versions-lto.rs
+++ b/tests/assembly-llvm/dwarf-mixed-versions-lto.rs
@@ -1,6 +1,7 @@
// This test ensures that if LTO occurs between crates with different DWARF versions, we
// will choose the highest DWARF version for the final binary. This matches Clang's behavior.
// Note: `.2byte` directive is used on MIPS.
+// Note: `.half` directive is used on RISC-V.
//@ only-linux
//@ aux-build:dwarf-mixed-versions-lto-aux.rs
@@ -15,6 +16,6 @@ fn main() {
}
// CHECK: .section .debug_info
-// CHECK-NOT: {{\.(short|hword|2byte)}} 2
-// CHECK-NOT: {{\.(short|hword|2byte)}} 4
-// CHECK: {{\.(short|hword|2byte)}} 5
+// CHECK-NOT: {{\.(short|hword|2byte|half)}} 2
+// CHECK-NOT: {{\.(short|hword|2byte|half)}} 4
+// CHECK: {{\.(short|hword|2byte|half)}} 5
diff --git a/tests/assembly-llvm/nvptx-safe-naming.rs b/tests/assembly-llvm/nvptx-safe-naming.rs
index d7b46aa..6a6659a 100644
--- a/tests/assembly-llvm/nvptx-safe-naming.rs
+++ b/tests/assembly-llvm/nvptx-safe-naming.rs
@@ -1,6 +1,9 @@
//@ assembly-output: ptx-linker
//@ compile-flags: --crate-type cdylib -Z unstable-options -Clinker-flavor=llbc
//@ only-nvptx64
+//@ revisions: LLVM20 LLVM21
+//@ [LLVM21] min-llvm-version: 21
+//@ [LLVM20] max-llvm-major-version: 20
#![feature(abi_ptx)]
#![no_std]
@@ -15,7 +18,8 @@
#[no_mangle]
pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) {
// CHECK: call.uni (retval0),
- // CHECK-NEXT: [[IMPL_FN]]
+ // LLVM20-NEXT: [[IMPL_FN]]
+ // LLVM21-SAME: [[IMPL_FN]]
*b = deep::private::MyStruct::new(*a).square();
}
diff --git a/tests/assembly-llvm/x86-return-float.rs b/tests/assembly-llvm/x86-return-float.rs
index 165c11d..4db93f6 100644
--- a/tests/assembly-llvm/x86-return-float.rs
+++ b/tests/assembly-llvm/x86-return-float.rs
@@ -334,9 +334,9 @@ pub fn return_f128(x: f128) -> f128 {
// linux-NEXT: .cfi_offset
// CHECK-NEXT: movl %esp, %ebp
// linux-NEXT: .cfi_def_cfa_register
- // linux-NEXT: movaps 8(%ebp), %xmm0
- // win-NEXT: movups 8(%ebp), %xmm0
- // CHECK-NEXT: popl %ebp
+ // linux: movaps 8(%ebp), %xmm0
+ // win: movups 8(%ebp), %xmm0
+ // CHECK: popl %ebp
// linux-NEXT: .cfi_def_cfa
// CHECK-NEXT: retl
x
diff --git a/tests/codegen-llvm/abi-efiapi.rs b/tests/codegen-llvm/abi-efiapi.rs
index 1736f0d..4cd6451 100644
--- a/tests/codegen-llvm/abi-efiapi.rs
+++ b/tests/codegen-llvm/abi-efiapi.rs
@@ -3,15 +3,15 @@
//@ add-core-stubs
//@ revisions:x86_64 i686 aarch64 arm riscv
//@[x86_64] compile-flags: --target x86_64-unknown-uefi
-//@[x86_64] needs-llvm-components: aarch64 arm riscv
+//@[x86_64] needs-llvm-components: x86
//@[i686] compile-flags: --target i686-unknown-linux-musl
-//@[i686] needs-llvm-components: aarch64 arm riscv
+//@[i686] needs-llvm-components: x86
//@[aarch64] compile-flags: --target aarch64-unknown-none
-//@[aarch64] needs-llvm-components: aarch64 arm riscv
+//@[aarch64] needs-llvm-components: aarch64
//@[arm] compile-flags: --target armv7r-none-eabi
-//@[arm] needs-llvm-components: aarch64 arm riscv
+//@[arm] needs-llvm-components: arm
//@[riscv] compile-flags: --target riscv64gc-unknown-none-elf
-//@[riscv] needs-llvm-components: aarch64 arm riscv
+//@[riscv] needs-llvm-components: riscv
//@ compile-flags: -C no-prepopulate-passes
#![crate_type = "lib"]
diff --git a/tests/codegen-llvm/cast-target-abi.rs b/tests/codegen-llvm/cast-target-abi.rs
index cbd49e2..28d3ad5 100644
--- a/tests/codegen-llvm/cast-target-abi.rs
+++ b/tests/codegen-llvm/cast-target-abi.rs
@@ -4,7 +4,7 @@
//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes -Zlint-llvm-ir
//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
-//@[aarch64] needs-llvm-components: arm
+//@[aarch64] needs-llvm-components: aarch64
//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
//@[loongarch64] needs-llvm-components: loongarch
//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
diff --git a/tests/codegen-llvm/cf-protection.rs b/tests/codegen-llvm/cf-protection.rs
index f1349a5..9efadb5 100644
--- a/tests/codegen-llvm/cf-protection.rs
+++ b/tests/codegen-llvm/cf-protection.rs
@@ -3,7 +3,7 @@
//@ add-core-stubs
//@ revisions: undefined none branch return full
//@ needs-llvm-components: x86
-//@ [undefined] compile-flags:
+// [undefined] no extra compile-flags
//@ [none] compile-flags: -Z cf-protection=none
//@ [branch] compile-flags: -Z cf-protection=branch
//@ [return] compile-flags: -Z cf-protection=return
diff --git a/tests/codegen-llvm/cffi/c-variadic-ffi.rs b/tests/codegen-llvm/cffi/c-variadic-ffi.rs
new file mode 100644
index 0000000..3e99c9f
--- /dev/null
+++ b/tests/codegen-llvm/cffi/c-variadic-ffi.rs
@@ -0,0 +1,86 @@
+//! Test calling variadic functions with various ABIs.
+//@ add-core-stubs
+//@ compile-flags: -Z merge-functions=disabled
+//@ revisions: x86_32 x86_32_win x86_64 aarch64 arm32
+//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x86_64] needs-llvm-components: x86
+//@[x86_32_win] compile-flags: --target i686-pc-windows-msvc
+//@[x86_32_win] needs-llvm-components: x86
+//@[x86_32] compile-flags: --target i686-unknown-linux-gnu
+//@[x86_32] needs-llvm-components: x86
+//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64] needs-llvm-components: aarch64
+//@[arm32] compile-flags: --target armv7-unknown-linux-gnueabihf
+//@[arm32] needs-llvm-components: arm
+#![crate_type = "lib"]
+#![feature(no_core)]
+#![feature(extended_varargs_abi_support, extern_system_varargs)]
+#![no_core]
+
+extern crate minicore;
+
+// CHECK-LABEL: @c
+#[unsafe(no_mangle)]
+fn c(f: extern "C" fn(i32, ...)) {
+ // CHECK: call void (i32, ...)
+ f(22, 44);
+}
+
+// CHECK-LABEL: @system
+#[unsafe(no_mangle)]
+fn system(f: extern "system" fn(i32, ...)) {
+ // Crucially, this is *always* the C calling convention, even on Windows.
+ // CHECK: call void (i32, ...)
+ f(22, 44);
+}
+
+// x86_32-LABEL: @cdecl
+#[unsafe(no_mangle)]
+#[cfg(target_arch = "x86")]
+fn cdecl(f: extern "cdecl" fn(i32, ...)) {
+ // x86_32: call void (i32, ...)
+ f(22, 44);
+}
+
+// x86_64-LABEL: @sysv
+#[unsafe(no_mangle)]
+#[cfg(target_arch = "x86_64")]
+fn sysv(f: extern "sysv64" fn(i32, ...)) {
+ // x86_64: call x86_64_sysvcc void (i32, ...)
+ f(22, 44);
+}
+
+// x86_64-LABEL: @win
+#[unsafe(no_mangle)]
+#[cfg(target_arch = "x86_64")]
+fn win(f: extern "win64" fn(i32, ...)) {
+ // x86_64: call win64cc void (i32, ...)
+ f(22, 44);
+}
+
+// CHECK-LABEL: @efiapi
+#[unsafe(no_mangle)]
+#[cfg(any(
+ target_arch = "arm",
+ target_arch = "aarch64",
+ target_arch = "riscv32",
+ target_arch = "riscv64",
+ target_arch = "x86",
+ target_arch = "x86_64"
+))]
+fn efiapi(f: extern "efiapi" fn(i32, ...)) {
+ // x86_32: call void (i32, ...)
+ // x86_32_win: call void (i32, ...)
+ // x86_64: call win64cc void (i32, ...)
+ // aarch64: call void (i32, ...)
+ // arm32: call arm_aapcscc void (i32, ...)
+ f(22, 44);
+}
+
+// arm32-LABEL: @aapcs
+#[unsafe(no_mangle)]
+#[cfg(target_arch = "arm")]
+fn aapcs(f: extern "aapcs" fn(i32, ...)) {
+ // arm32: call arm_aapcscc void (i32, ...)
+ f(22, 44);
+}
diff --git a/tests/codegen-llvm/codemodels.rs b/tests/codegen-llvm/codemodels.rs
index 06d2ead..e82e094 100644
--- a/tests/codegen-llvm/codemodels.rs
+++ b/tests/codegen-llvm/codemodels.rs
@@ -1,7 +1,7 @@
//@ only-x86_64
//@ revisions: NOMODEL MODEL-SMALL MODEL-KERNEL MODEL-MEDIUM MODEL-LARGE
-//@[NOMODEL] compile-flags:
+// [NOMODEL] no compile-flags
//@[MODEL-SMALL] compile-flags: -C code-model=small
//@[MODEL-KERNEL] compile-flags: -C code-model=kernel
//@[MODEL-MEDIUM] compile-flags: -C code-model=medium
diff --git a/tests/codegen-llvm/const-vector.rs b/tests/codegen-llvm/const-vector.rs
index a2249f4..f430749 100644
--- a/tests/codegen-llvm/const-vector.rs
+++ b/tests/codegen-llvm/const-vector.rs
@@ -15,6 +15,7 @@
#![feature(arm_target_feature)]
#![feature(mips_target_feature)]
#![allow(non_camel_case_types)]
+#![feature(riscv_target_feature)]
#[path = "../auxiliary/minisimd.rs"]
mod minisimd;
@@ -42,6 +43,7 @@
#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))]
pub fn do_call() {
unsafe {
// CHECK: call void @test_i8x2(<2 x i8> <i8 32, i8 64>
diff --git a/tests/codegen-llvm/debuginfo-cyclic-structure.rs b/tests/codegen-llvm/debuginfo-cyclic-structure.rs
new file mode 100644
index 0000000..b8cc544
--- /dev/null
+++ b/tests/codegen-llvm/debuginfo-cyclic-structure.rs
@@ -0,0 +1,32 @@
+//@ compile-flags:-g -Copt-level=0 -C panic=abort
+
+// Check that debug information exists for structures containing loops (cyclic references).
+// Previously it may incorrectly prune member information during recursive type inference check.
+
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Arc<debuginfo_cyclic_structure::Inner<alloc::sync::Arc<debuginfo_cyclic_structure::Handle{{.*}}elements: ![[FIELDS:[0-9]+]]
+// CHECK: ![[FIELDS]] = !{!{{.*}}}
+// CHECK-NOT: ![[FIELDS]] = !{}
+
+#![crate_type = "lib"]
+
+use std::mem::MaybeUninit;
+use std::sync::Arc;
+
+struct Inner<T> {
+ buffer: Box<MaybeUninit<T>>,
+}
+struct Shared {
+ shared: Arc<Inner<Arc<Handle>>>,
+}
+struct Handle {
+ shared: Shared,
+}
+struct Core {
+ inner: Arc<Inner<Arc<Handle>>>,
+}
+
+#[no_mangle]
+extern "C" fn test() {
+ let с = Core { inner: Arc::new(Inner { buffer: Box::new(MaybeUninit::uninit()) }) };
+ std::hint::black_box(с);
+}
diff --git a/tests/codegen-llvm/diverging-function-call-debuginfo.rs b/tests/codegen-llvm/diverging-function-call-debuginfo.rs
new file mode 100644
index 0000000..1a80fe1
--- /dev/null
+++ b/tests/codegen-llvm/diverging-function-call-debuginfo.rs
@@ -0,0 +1,38 @@
+/// Make sure that line debuginfo is correct for diverging calls under certain
+/// conditions. In particular we want to ensure that the line number is never
+/// 0, but we check the absence of 0 by looking for the expected exact line
+/// numbers. Regression test for <https://github.com/rust-lang/rust/issues/59558>.
+
+//@ compile-flags: -g -Clto -Copt-level=0
+//@ no-prefer-dynamic
+
+// First find the scope of both diverge() calls, namely this main() function.
+// CHECK-DAG: [[MAIN_SCOPE:![0-9]+]] = distinct !DISubprogram(name: "main", linkageName: {{.*}}diverging_function_call_debuginfo{{.*}}main{{.*}}
+fn main() {
+ if True == False {
+ // unreachable
+ // Then find the DILocation with the correct line number for this call ...
+ // CHECK-DAG: [[UNREACHABLE_CALL_DBG:![0-9]+]] = !DILocation(line: [[@LINE+1]], {{.*}}scope: [[MAIN_SCOPE]]
+ diverge();
+ }
+
+ // ... and this call.
+ // CHECK-DAG: [[LAST_CALL_DBG:![0-9]+]] = !DILocation(line: [[@LINE+1]], {{.*}}scope: [[MAIN_SCOPE]]
+ diverge();
+}
+
+#[derive(PartialEq)]
+pub enum MyBool {
+ True,
+ False,
+}
+
+use MyBool::*;
+
+fn diverge() -> ! {
+ panic!();
+}
+
+// Finally make sure both DILocations belong to each the respective diverge() call.
+// CHECK-DAG: call void {{.*}}diverging_function_call_debuginfo{{.*}}diverge{{.*}} !dbg [[LAST_CALL_DBG]]
+// CHECK-DAG: call void {{.*}}diverging_function_call_debuginfo{{.*}}diverge{{.*}} !dbg [[UNREACHABLE_CALL_DBG]]
diff --git a/tests/codegen-llvm/ehcontguard_disabled.rs b/tests/codegen-llvm/ehcontguard_disabled.rs
index 9efb272..962d14e 100644
--- a/tests/codegen-llvm/ehcontguard_disabled.rs
+++ b/tests/codegen-llvm/ehcontguard_disabled.rs
@@ -1,5 +1,3 @@
-//@ compile-flags:
-
#![crate_type = "lib"]
// A basic test function.
diff --git a/tests/codegen-llvm/enum/enum-discriminant-eq.rs b/tests/codegen-llvm/enum/enum-discriminant-eq.rs
index 0494c5f..d599685 100644
--- a/tests/codegen-llvm/enum/enum-discriminant-eq.rs
+++ b/tests/codegen-llvm/enum/enum-discriminant-eq.rs
@@ -1,6 +1,9 @@
//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
//@ min-llvm-version: 20
//@ only-64bit
+//@ revisions: LLVM20 LLVM21
+//@ [LLVM21] min-llvm-version: 21
+//@ [LLVM20] max-llvm-major-version: 20
// The `derive(PartialEq)` on enums with field-less variants compares discriminants,
// so make sure we emit that in some reasonable way.
@@ -137,17 +140,20 @@ pub fn mid_nz32_eq_discr(a: Mid<NonZero<u32>>, b: Mid<NonZero<u32>>) -> bool {
pub fn mid_ac_eq_discr(a: Mid<AC>, b: Mid<AC>) -> bool {
// CHECK-LABEL: @mid_ac_eq_discr(
- // CHECK: %[[A_REL_DISCR:.+]] = xor i8 %a, -128
+ // LLVM20: %[[A_REL_DISCR:.+]] = xor i8 %a, -128
// CHECK: %[[A_IS_NICHE:.+]] = icmp slt i8 %a, 0
// CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %a, -127
// CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
- // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
+ // LLVM20: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
- // CHECK: %[[B_REL_DISCR:.+]] = xor i8 %b, -128
+ // LLVM20: %[[B_REL_DISCR:.+]] = xor i8 %b, -128
// CHECK: %[[B_IS_NICHE:.+]] = icmp slt i8 %b, 0
// CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %b, -127
// CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
- // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
+ // LLVM20: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
+
+ // LLVM21: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %a, i8 -127
+ // LLVM21: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %b, i8 -127
// CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]]
// CHECK: ret i1 %[[R]]
diff --git a/tests/codegen-llvm/enum/enum-transparent-extract.rs b/tests/codegen-llvm/enum/enum-transparent-extract.rs
new file mode 100644
index 0000000..c5efb8d
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-transparent-extract.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: -Copt-level=0
+//@ only-64bit
+
+#![crate_type = "lib"]
+
+use std::ops::ControlFlow;
+
+pub enum Never {}
+
+#[no_mangle]
+pub fn make_unmake_result_never(x: i32) -> i32 {
+ // CHECK-LABEL: define i32 @make_unmake_result_never(i32 %x)
+ // CHECK: start:
+ // CHECK-NEXT: ret i32 %x
+
+ let y: Result<i32, Never> = Ok(x);
+ let Ok(z) = y;
+ z
+}
+
+#[no_mangle]
+pub fn extract_control_flow_never(x: ControlFlow<&str, Never>) -> &str {
+ // CHECK-LABEL: define { ptr, i64 } @extract_control_flow_never(ptr align 1 %x.0, i64 %x.1)
+ // CHECK: start:
+ // CHECK-NEXT: %[[P0:.+]] = insertvalue { ptr, i64 } poison, ptr %x.0, 0
+ // CHECK-NEXT: %[[P1:.+]] = insertvalue { ptr, i64 } %[[P0]], i64 %x.1, 1
+ // CHECK-NEXT: ret { ptr, i64 } %[[P1]]
+
+ let ControlFlow::Break(s) = x;
+ s
+}
diff --git a/tests/codegen-llvm/intrinsics/transmute-niched.rs b/tests/codegen-llvm/intrinsics/transmute-niched.rs
index 8ff5cc8..a886d9e 100644
--- a/tests/codegen-llvm/intrinsics/transmute-niched.rs
+++ b/tests/codegen-llvm/intrinsics/transmute-niched.rs
@@ -163,11 +163,8 @@ pub unsafe fn check_swap_pair(x: (char, NonZero<u32>)) -> (NonZero<u32>, char) {
pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool {
// CHECK-NOT: icmp
// CHECK-NOT: assume
- // OPT: %0 = sub i8 %x, -1
- // OPT: %1 = icmp ule i8 %0, 2
- // OPT: call void @llvm.assume(i1 %1)
- // OPT: %2 = icmp ule i8 %x, 1
- // OPT: call void @llvm.assume(i1 %2)
+ // OPT: %0 = icmp ule i8 %x, 1
+ // OPT: call void @llvm.assume(i1 %0)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: %[[R:.+]] = trunc{{( nuw)?}} i8 %x to i1
@@ -184,9 +181,6 @@ pub unsafe fn check_bool_to_ordering(x: bool) -> std::cmp::Ordering {
// CHECK-NOT: assume
// OPT: %0 = icmp ule i8 %_0, 1
// OPT: call void @llvm.assume(i1 %0)
- // OPT: %1 = sub i8 %_0, -1
- // OPT: %2 = icmp ule i8 %1, 2
- // OPT: call void @llvm.assume(i1 %2)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: ret i8 %_0
@@ -221,3 +215,42 @@ pub unsafe fn check_ptr_to_nonnull(x: *const u8) -> NonNull<u8> {
transmute(x)
}
+
+#[repr(usize)]
+pub enum FourOrEight {
+ Four = 4,
+ Eight = 8,
+}
+
+// CHECK-LABEL: @check_nonnull_to_four_or_eight(
+#[no_mangle]
+pub unsafe fn check_nonnull_to_four_or_eight(x: NonNull<u8>) -> FourOrEight {
+ // CHECK: start
+ // CHECK-NEXT: %[[RET:.+]] = ptrtoint ptr %x to i64
+ // CHECK-NOT: icmp
+ // CHECK-NOT: assume
+ // OPT: %0 = sub i64 %[[RET]], 4
+ // OPT: %1 = icmp ule i64 %0, 4
+ // OPT: call void @llvm.assume(i1 %1)
+ // CHECK-NOT: icmp
+ // CHECK-NOT: assume
+ // CHECK: ret i64 %[[RET]]
+
+ transmute(x)
+}
+
+// CHECK-LABEL: @check_four_or_eight_to_nonnull(
+#[no_mangle]
+pub unsafe fn check_four_or_eight_to_nonnull(x: FourOrEight) -> NonNull<u8> {
+ // CHECK-NOT: icmp
+ // CHECK-NOT: assume
+ // OPT: %0 = sub i64 %x, 4
+ // OPT: %1 = icmp ule i64 %0, 4
+ // OPT: call void @llvm.assume(i1 %1)
+ // CHECK-NOT: icmp
+ // CHECK-NOT: assume
+ // CHECK: %[[RET:.+]] = getelementptr i8, ptr null, i64 %x
+ // CHECK-NEXT: ret ptr %[[RET]]
+
+ transmute(x)
+}
diff --git a/tests/codegen-llvm/intrinsics/transmute-simd.rs b/tests/codegen-llvm/intrinsics/transmute-simd.rs
new file mode 100644
index 0000000..e34b27e
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/transmute-simd.rs
@@ -0,0 +1,176 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+//@ only-64bit (so I don't need to worry about usize)
+//@ revisions: aarch64 x86_64
+//@ [aarch64] only-aarch64
+//@ [aarch64] compile-flags: -C target-feature=+neon
+//@ [x86_64] only-x86_64
+//@ [x86_64] compile-flags: -C target-feature=+sse2
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+#![feature(portable_simd)]
+
+use std::intrinsics::transmute;
+use std::simd::{Simd, f32x4, f64x2, i32x4, i64x2};
+type PtrX2 = Simd<*const (), 2>;
+
+// These tests use the "C" ABI so that the vectors in question aren't passed and
+// returned though memory (as they are in the "Rust" ABI), which greatly
+// simplifies seeing the difference between the in-operand cases vs the ones
+// that fallback to just using the `LocalKind::Memory` path.
+
+// CHECK-LABEL: <2 x i64> @mixed_int(<4 x i32> %v)
+#[no_mangle]
+pub extern "C" fn mixed_int(v: i32x4) -> i64x2 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[RET:.+]] = bitcast <4 x i32> %v to <2 x i64>
+ // CHECK: ret <2 x i64> %[[RET]]
+ unsafe { transmute(v) }
+}
+
+// CHECK-LABEL: <2 x double> @mixed_float(<4 x float> %v)
+#[no_mangle]
+pub extern "C" fn mixed_float(v: f32x4) -> f64x2 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[RET:.+]] = bitcast <4 x float> %v to <2 x double>
+ // CHECK: ret <2 x double> %[[RET]]
+ unsafe { transmute(v) }
+}
+
+// CHECK-LABEL: <4 x i32> @float_int_same_lanes(<4 x float> %v)
+#[no_mangle]
+pub extern "C" fn float_int_same_lanes(v: f32x4) -> i32x4 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[RET:.+]] = bitcast <4 x float> %v to <4 x i32>
+ // CHECK: ret <4 x i32> %[[RET]]
+ unsafe { transmute(v) }
+}
+
+// CHECK-LABEL: <2 x double> @int_float_same_lanes(<2 x i64> %v)
+#[no_mangle]
+pub extern "C" fn int_float_same_lanes(v: i64x2) -> f64x2 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[RET:.+]] = bitcast <2 x i64> %v to <2 x double>
+ // CHECK: ret <2 x double> %[[RET]]
+ unsafe { transmute(v) }
+}
+
+// CHECK-LABEL: <2 x i64> @float_int_widen(<4 x float> %v)
+#[no_mangle]
+pub extern "C" fn float_int_widen(v: f32x4) -> i64x2 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[RET:.+]] = bitcast <4 x float> %v to <2 x i64>
+ // CHECK: ret <2 x i64> %[[RET]]
+ unsafe { transmute(v) }
+}
+
+// CHECK-LABEL: <2 x double> @int_float_widen(<4 x i32> %v)
+#[no_mangle]
+pub extern "C" fn int_float_widen(v: i32x4) -> f64x2 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[RET:.+]] = bitcast <4 x i32> %v to <2 x double>
+ // CHECK: ret <2 x double> %[[RET]]
+ unsafe { transmute(v) }
+}
+
+// CHECK-LABEL: <4 x i32> @float_int_narrow(<2 x double> %v)
+#[no_mangle]
+pub extern "C" fn float_int_narrow(v: f64x2) -> i32x4 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[RET:.+]] = bitcast <2 x double> %v to <4 x i32>
+ // CHECK: ret <4 x i32> %[[RET]]
+ unsafe { transmute(v) }
+}
+
+// CHECK-LABEL: <4 x float> @int_float_narrow(<2 x i64> %v)
+#[no_mangle]
+pub extern "C" fn int_float_narrow(v: i64x2) -> f32x4 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[RET:.+]] = bitcast <2 x i64> %v to <4 x float>
+ // CHECK: ret <4 x float> %[[RET]]
+ unsafe { transmute(v) }
+}
+
+// CHECK-LABEL: <2 x ptr> @float_ptr_same_lanes(<2 x double> %v)
+#[no_mangle]
+pub extern "C" fn float_ptr_same_lanes(v: f64x2) -> PtrX2 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[TEMP:.+]] = alloca [16 x i8]
+ // CHECK-NOT: alloca
+ // CHECK: call void @llvm.lifetime.start.p0(i64 16, ptr %[[TEMP]])
+ // CHECK: store <2 x double> %v, ptr %[[TEMP]]
+ // CHECK: %[[RET:.+]] = load <2 x ptr>, ptr %[[TEMP]]
+ // CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr %[[TEMP]])
+ // CHECK: ret <2 x ptr> %[[RET]]
+ unsafe { transmute(v) }
+}
+
+// CHECK-LABEL: <2 x double> @ptr_float_same_lanes(<2 x ptr> %v)
+#[no_mangle]
+pub extern "C" fn ptr_float_same_lanes(v: PtrX2) -> f64x2 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[TEMP:.+]] = alloca [16 x i8]
+ // CHECK-NOT: alloca
+ // CHECK: call void @llvm.lifetime.start.p0(i64 16, ptr %[[TEMP]])
+ // CHECK: store <2 x ptr> %v, ptr %[[TEMP]]
+ // CHECK: %[[RET:.+]] = load <2 x double>, ptr %[[TEMP]]
+ // CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr %[[TEMP]])
+ // CHECK: ret <2 x double> %[[RET]]
+ unsafe { transmute(v) }
+}
+
+// CHECK-LABEL: <2 x ptr> @int_ptr_same_lanes(<2 x i64> %v)
+#[no_mangle]
+pub extern "C" fn int_ptr_same_lanes(v: i64x2) -> PtrX2 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[TEMP:.+]] = alloca [16 x i8]
+ // CHECK-NOT: alloca
+ // CHECK: call void @llvm.lifetime.start.p0(i64 16, ptr %[[TEMP]])
+ // CHECK: store <2 x i64> %v, ptr %[[TEMP]]
+ // CHECK: %[[RET:.+]] = load <2 x ptr>, ptr %[[TEMP]]
+ // CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr %[[TEMP]])
+ // CHECK: ret <2 x ptr> %[[RET]]
+ unsafe { transmute(v) }
+}
+
+// CHECK-LABEL: <2 x i64> @ptr_int_same_lanes(<2 x ptr> %v)
+#[no_mangle]
+pub extern "C" fn ptr_int_same_lanes(v: PtrX2) -> i64x2 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[TEMP:.+]] = alloca [16 x i8]
+ // CHECK-NOT: alloca
+ // CHECK: call void @llvm.lifetime.start.p0(i64 16, ptr %[[TEMP]])
+ // CHECK: store <2 x ptr> %v, ptr %[[TEMP]]
+ // CHECK: %[[RET:.+]] = load <2 x i64>, ptr %[[TEMP]]
+ // CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr %[[TEMP]])
+ // CHECK: ret <2 x i64> %[[RET]]
+ unsafe { transmute(v) }
+}
+
+// CHECK-LABEL: <2 x ptr> @float_ptr_widen(<4 x float> %v)
+#[no_mangle]
+pub extern "C" fn float_ptr_widen(v: f32x4) -> PtrX2 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[TEMP:.+]] = alloca [16 x i8]
+ // CHECK-NOT: alloca
+ // CHECK: call void @llvm.lifetime.start.p0(i64 16, ptr %[[TEMP]])
+ // CHECK: store <4 x float> %v, ptr %[[TEMP]]
+ // CHECK: %[[RET:.+]] = load <2 x ptr>, ptr %[[TEMP]]
+ // CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr %[[TEMP]])
+ // CHECK: ret <2 x ptr> %[[RET]]
+ unsafe { transmute(v) }
+}
+
+// CHECK-LABEL: <2 x ptr> @int_ptr_widen(<4 x i32> %v)
+#[no_mangle]
+pub extern "C" fn int_ptr_widen(v: i32x4) -> PtrX2 {
+ // CHECK-NOT: alloca
+ // CHECK: %[[TEMP:.+]] = alloca [16 x i8]
+ // CHECK-NOT: alloca
+ // CHECK: call void @llvm.lifetime.start.p0(i64 16, ptr %[[TEMP]])
+ // CHECK: store <4 x i32> %v, ptr %[[TEMP]]
+ // CHECK: %[[RET:.+]] = load <2 x ptr>, ptr %[[TEMP]]
+ // CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr %[[TEMP]])
+ // CHECK: ret <2 x ptr> %[[RET]]
+ unsafe { transmute(v) }
+}
diff --git a/tests/codegen-llvm/intrinsics/transmute.rs b/tests/codegen-llvm/intrinsics/transmute.rs
index c9a1cd5..91cff38 100644
--- a/tests/codegen-llvm/intrinsics/transmute.rs
+++ b/tests/codegen-llvm/intrinsics/transmute.rs
@@ -191,22 +191,28 @@ pub unsafe fn check_byte_from_bool(x: bool) -> u8 {
// CHECK-LABEL: @check_to_pair(
#[no_mangle]
pub unsafe fn check_to_pair(x: u64) -> Option<i32> {
- // CHECK: %_0 = alloca [8 x i8], align 4
- // CHECK: store i64 %x, ptr %_0, align 4
+ // CHECK: %[[TEMP:.+]] = alloca [8 x i8], align 8
+ // CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr %[[TEMP]])
+ // CHECK: store i64 %x, ptr %[[TEMP]], align 8
+ // CHECK: %[[PAIR0:.+]] = load i32, ptr %[[TEMP]], align 8
+ // CHECK: %[[PAIR1P:.+]] = getelementptr inbounds i8, ptr %[[TEMP]], i64 4
+ // CHECK: %[[PAIR1:.+]] = load i32, ptr %[[PAIR1P]], align 4
+ // CHECK: call void @llvm.lifetime.end.p0(i64 8, ptr %[[TEMP]])
+ // CHECK: insertvalue {{.+}}, i32 %[[PAIR0]], 0
+ // CHECK: insertvalue {{.+}}, i32 %[[PAIR1]], 1
transmute(x)
}
// CHECK-LABEL: @check_from_pair(
#[no_mangle]
pub unsafe fn check_from_pair(x: Option<i32>) -> u64 {
- // The two arguments are of types that are only 4-aligned, but they're
- // immediates so we can write using the destination alloca's alignment.
- const { assert!(std::mem::align_of::<Option<i32>>() == 4) };
-
- // CHECK: %_0 = alloca [8 x i8], align 8
- // CHECK: store i32 %x.0, ptr %_0, align 8
- // CHECK: store i32 %x.1, ptr %0, align 4
- // CHECK: %[[R:.+]] = load i64, ptr %_0, align 8
+ // CHECK: %[[TEMP:.+]] = alloca [8 x i8], align 8
+ // CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr %[[TEMP]])
+ // CHECK: store i32 %x.0, ptr %[[TEMP]], align 8
+ // CHECK: %[[PAIR1P:.+]] = getelementptr inbounds i8, ptr %[[TEMP]], i64 4
+ // CHECK: store i32 %x.1, ptr %[[PAIR1P]], align 4
+ // CHECK: %[[R:.+]] = load i64, ptr %[[TEMP]], align 8
+ // CHECK: call void @llvm.lifetime.end.p0(i64 8, ptr %[[TEMP]])
// CHECK: ret i64 %[[R]]
transmute(x)
}
diff --git a/tests/codegen-llvm/naked-fn/naked-functions.rs b/tests/codegen-llvm/naked-fn/naked-functions.rs
index 344af6e..8a7ee4b 100644
--- a/tests/codegen-llvm/naked-fn/naked-functions.rs
+++ b/tests/codegen-llvm/naked-fn/naked-functions.rs
@@ -8,7 +8,7 @@
//@[win_i686] compile-flags: --target i686-pc-windows-gnu
//@[win_i686] needs-llvm-components: x86
//@[macos] compile-flags: --target aarch64-apple-darwin
-//@[macos] needs-llvm-components: arm
+//@[macos] needs-llvm-components: aarch64
//@[thumb] compile-flags: --target thumbv7em-none-eabi
//@[thumb] needs-llvm-components: arm
diff --git a/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs b/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs
index f319306..642bf5e 100644
--- a/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs
+++ b/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs
@@ -19,9 +19,9 @@
//@ only-linux
//
//@ revisions:ASAN ASAN-FAT-LTO
-//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static
-//@[ASAN] compile-flags:
-//@[ASAN-FAT-LTO] compile-flags: -Cprefer-dynamic=false -Clto=fat
+//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static
+// [ASAN] no extra compile-flags
+//@[ASAN-FAT-LTO] compile-flags: -Cprefer-dynamic=false -Clto=fat
#![crate_type = "staticlib"]
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs
index 6b40918..02c31fb 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs
@@ -5,7 +5,7 @@
//@ [aarch64] compile-flags: --target aarch64-unknown-none
//@ [aarch64] needs-llvm-components: aarch64
//@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
#![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs
index 942b50d..9a60d51 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs
@@ -5,7 +5,7 @@
//@ [aarch64] compile-flags: --target aarch64-unknown-none
//@ [aarch64] needs-llvm-components: aarch64
//@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-generalize-pointers
#![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs
index c89d9bd..134f4ff 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs
@@ -5,7 +5,7 @@
//@ [aarch64] compile-flags: --target aarch64-unknown-none
//@ [aarch64] needs-llvm-components: aarch64
//@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers
#![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs
index 220cae1..4328b7f 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs
@@ -5,7 +5,7 @@
//@ [aarch64] compile-flags: --target aarch64-unknown-none
//@ [aarch64] needs-llvm-components: aarch64
//@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers
#![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs
index bb9a000..81a9db1 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs
@@ -5,7 +5,7 @@
//@ [aarch64] compile-flags: --target aarch64-unknown-none
//@ [aarch64] needs-llvm-components: aarch64
//@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
#![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs
index 8b844b9..61056c2 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs
@@ -5,7 +5,7 @@
//@ [aarch64] compile-flags: --target aarch64-unknown-none
//@ [aarch64] needs-llvm-components: aarch64
//@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
#![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
index 15c107b..182af16 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
@@ -5,7 +5,7 @@
//@ [aarch64] compile-flags: --target aarch64-unknown-none
//@ [aarch64] needs-llvm-components: aarch64
//@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
#![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/memory-track-origins.rs b/tests/codegen-llvm/sanitizer/memory-track-origins.rs
index 318c277..5eb5b35 100644
--- a/tests/codegen-llvm/sanitizer/memory-track-origins.rs
+++ b/tests/codegen-llvm/sanitizer/memory-track-origins.rs
@@ -5,7 +5,7 @@
//@ revisions:MSAN-0 MSAN-1 MSAN-2 MSAN-1-LTO MSAN-2-LTO
//
//@ compile-flags: -Zsanitizer=memory -Ctarget-feature=-crt-static
-//@[MSAN-0] compile-flags:
+// [MSAN-0] no extra compile-flags
//@[MSAN-1] compile-flags: -Zsanitizer-memory-track-origins=1
//@[MSAN-2] compile-flags: -Zsanitizer-memory-track-origins
//@[MSAN-1-LTO] compile-flags: -Zsanitizer-memory-track-origins=1 -C lto=fat
diff --git a/tests/codegen-llvm/ub-checks.rs b/tests/codegen-llvm/ub-checks.rs
index 67f5bff..c40bc9a 100644
--- a/tests/codegen-llvm/ub-checks.rs
+++ b/tests/codegen-llvm/ub-checks.rs
@@ -6,7 +6,7 @@
// but ub-checks are explicitly disabled.
//@ revisions: DEBUG NOCHECKS
-//@ [DEBUG] compile-flags:
+// [DEBUG] no extra compile-flags
//@ [NOCHECKS] compile-flags: -Zub-checks=no
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=yes
diff --git a/tests/codegen-llvm/wasm_exceptions.rs b/tests/codegen-llvm/wasm_exceptions.rs
index 07b8ae6..796b69b 100644
--- a/tests/codegen-llvm/wasm_exceptions.rs
+++ b/tests/codegen-llvm/wasm_exceptions.rs
@@ -2,7 +2,7 @@
//@ compile-flags: -C panic=unwind -Z emscripten-wasm-eh
#![crate_type = "lib"]
-#![feature(core_intrinsics)]
+#![feature(core_intrinsics, wasm_exception_handling_intrinsics)]
extern "C-unwind" {
fn may_panic();
@@ -57,3 +57,17 @@ pub fn test_rtry() {
// CHECK: {{.*}} = catchpad within {{.*}} [ptr null]
// CHECK: catchret
}
+
+// Make sure the intrinsic is not inferred as nounwind. This is a regression test for #132416.
+// CHECK-LABEL: @test_intrinsic() {{.*}} @__gxx_wasm_personality_v0
+#[no_mangle]
+pub fn test_intrinsic() {
+ let _log_on_drop = LogOnDrop;
+ unsafe {
+ core::arch::wasm32::throw::<0>(core::ptr::null_mut());
+ }
+
+ // CHECK-NOT: call
+ // CHECK: invoke void @llvm.wasm.throw(i32 noundef 0, ptr noundef null)
+ // CHECK: %cleanuppad = cleanuppad within none []
+}
diff --git a/tests/coverage/async_closure.cov-map b/tests/coverage/async_closure.cov-map
index 53128dd..9f8dc8d 100644
--- a/tests/coverage/async_closure.cov-map
+++ b/tests/coverage/async_closure.cov-map
@@ -37,29 +37,32 @@
Highest counter ID seen: c0
Function name: async_closure::main::{closure#0}
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24]
Number of files: 1
- file 0 => $DIR/async_closure.rs
Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36)
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35)
+- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36)
Highest counter ID seen: c0
Function name: async_closure::main::{closure#0}
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24]
Number of files: 1
- file 0 => $DIR/async_closure.rs
Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36)
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35)
+- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36)
Highest counter ID seen: c0
Function name: async_closure::main::{closure#0}::{closure#0}::<i16>
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24]
Number of files: 1
- file 0 => $DIR/async_closure.rs
Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36)
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35)
+- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36)
Highest counter ID seen: c0
diff --git a/tests/coverage/auto-derived.auto.cov-map b/tests/coverage/auto-derived.auto.cov-map
new file mode 100644
index 0000000..e3d411d
--- /dev/null
+++ b/tests/coverage/auto-derived.auto.cov-map
@@ -0,0 +1,23 @@
+Function name: <auto_derived::MyStruct as auto_derived::MyTrait>::my_assoc_fn::inner_fn_on
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 1f, 09, 00, 19, 01, 01, 0d, 00, 10, 01, 00, 11, 00, 23, 01, 01, 09, 00, 0a]
+Number of files: 1
+- file 0 => $DIR/auto-derived.rs
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 31, 9) to (start + 0, 25)
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 16)
+- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 35)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
+Highest counter ID seen: c0
+
+Function name: auto_derived::main
+Raw bytes (19): 0x[01, 01, 00, 03, 01, 33, 01, 00, 0a, 01, 01, 05, 00, 1a, 01, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => $DIR/auto-derived.rs
+Number of expressions: 0
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 51, 1) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 26)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
+Highest counter ID seen: c0
+
diff --git a/tests/coverage/auto-derived.auto.coverage b/tests/coverage/auto-derived.auto.coverage
new file mode 100644
index 0000000..242abbf
--- /dev/null
+++ b/tests/coverage/auto-derived.auto.coverage
@@ -0,0 +1,54 @@
+ LL| |#![feature(coverage_attribute)]
+ LL| |//@ edition: 2024
+ LL| |//@ revisions: base auto on
+ LL| |
+ LL| |// Tests for how `#[automatically_derived]` affects coverage instrumentation.
+ LL| |//
+ LL| |// The actual behaviour is an implementation detail, so this test mostly exists
+ LL| |// to show when that behaviour has been accidentally or deliberately changed.
+ LL| |//
+ LL| |// Revision guide:
+ LL| |// - base: Test baseline instrumentation behaviour without `#[automatically_derived]`
+ LL| |// - auto: Test how `#[automatically_derived]` affects instrumentation
+ LL| |// - on: Test interaction between auto-derived and `#[coverage(on)]`
+ LL| |
+ LL| |struct MyStruct;
+ LL| |
+ LL| |trait MyTrait {
+ LL| | fn my_assoc_fn();
+ LL| |}
+ LL| |
+ LL| |#[cfg_attr(auto, automatically_derived)]
+ LL| |#[cfg_attr(on, automatically_derived)]
+ LL| |#[cfg_attr(on, coverage(on))]
+ LL| |impl MyTrait for MyStruct {
+ LL| | fn my_assoc_fn() {
+ LL| | fn inner_fn() {
+ LL| | say("in inner fn");
+ LL| | }
+ LL| |
+ LL| | #[coverage(on)]
+ LL| 1| fn inner_fn_on() {
+ LL| 1| say("in inner fn (on)");
+ LL| 1| }
+ LL| |
+ LL| | let closure = || {
+ LL| | say("in closure");
+ LL| | };
+ LL| |
+ LL| | closure();
+ LL| | inner_fn();
+ LL| | inner_fn_on();
+ LL| | }
+ LL| |}
+ LL| |
+ LL| |#[coverage(off)]
+ LL| |#[inline(never)]
+ LL| |fn say(s: &str) {
+ LL| | println!("{s}");
+ LL| |}
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| MyStruct::my_assoc_fn();
+ LL| 1|}
+
diff --git a/tests/coverage/auto-derived.base.cov-map b/tests/coverage/auto-derived.base.cov-map
new file mode 100644
index 0000000..2dcd616
--- /dev/null
+++ b/tests/coverage/auto-derived.base.cov-map
@@ -0,0 +1,61 @@
+Function name: <auto_derived::MyStruct as auto_derived::MyTrait>::my_assoc_fn
+Raw bytes (34): 0x[01, 01, 00, 06, 01, 19, 05, 00, 15, 01, 0a, 0d, 00, 14, 01, 04, 09, 00, 12, 01, 01, 09, 00, 11, 01, 01, 09, 00, 14, 01, 01, 05, 00, 06]
+Number of files: 1
+- file 0 => $DIR/auto-derived.rs
+Number of expressions: 0
+Number of file 0 mappings: 6
+- Code(Counter(0)) at (prev + 25, 5) to (start + 0, 21)
+- Code(Counter(0)) at (prev + 10, 13) to (start + 0, 20)
+- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 18)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 20)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6)
+Highest counter ID seen: c0
+
+Function name: <auto_derived::MyStruct as auto_derived::MyTrait>::my_assoc_fn::inner_fn
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 1a, 09, 00, 16, 01, 01, 0d, 00, 10, 01, 00, 11, 00, 1e, 01, 01, 09, 00, 0a]
+Number of files: 1
+- file 0 => $DIR/auto-derived.rs
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 26, 9) to (start + 0, 22)
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 16)
+- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 30)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
+Highest counter ID seen: c0
+
+Function name: <auto_derived::MyStruct as auto_derived::MyTrait>::my_assoc_fn::inner_fn_on
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 1f, 09, 00, 19, 01, 01, 0d, 00, 10, 01, 00, 11, 00, 23, 01, 01, 09, 00, 0a]
+Number of files: 1
+- file 0 => $DIR/auto-derived.rs
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 31, 9) to (start + 0, 25)
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 16)
+- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 35)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
+Highest counter ID seen: c0
+
+Function name: <auto_derived::MyStruct as auto_derived::MyTrait>::my_assoc_fn::{closure#0}
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 23, 1a, 00, 1b, 01, 01, 0d, 00, 10, 01, 00, 11, 00, 1d, 01, 01, 09, 00, 0a]
+Number of files: 1
+- file 0 => $DIR/auto-derived.rs
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 35, 26) to (start + 0, 27)
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 16)
+- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 29)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
+Highest counter ID seen: c0
+
+Function name: auto_derived::main
+Raw bytes (19): 0x[01, 01, 00, 03, 01, 33, 01, 00, 0a, 01, 01, 05, 00, 1a, 01, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => $DIR/auto-derived.rs
+Number of expressions: 0
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 51, 1) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 26)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
+Highest counter ID seen: c0
+
diff --git a/tests/coverage/auto-derived.base.coverage b/tests/coverage/auto-derived.base.coverage
new file mode 100644
index 0000000..6ab6aa5
--- /dev/null
+++ b/tests/coverage/auto-derived.base.coverage
@@ -0,0 +1,54 @@
+ LL| |#![feature(coverage_attribute)]
+ LL| |//@ edition: 2024
+ LL| |//@ revisions: base auto on
+ LL| |
+ LL| |// Tests for how `#[automatically_derived]` affects coverage instrumentation.
+ LL| |//
+ LL| |// The actual behaviour is an implementation detail, so this test mostly exists
+ LL| |// to show when that behaviour has been accidentally or deliberately changed.
+ LL| |//
+ LL| |// Revision guide:
+ LL| |// - base: Test baseline instrumentation behaviour without `#[automatically_derived]`
+ LL| |// - auto: Test how `#[automatically_derived]` affects instrumentation
+ LL| |// - on: Test interaction between auto-derived and `#[coverage(on)]`
+ LL| |
+ LL| |struct MyStruct;
+ LL| |
+ LL| |trait MyTrait {
+ LL| | fn my_assoc_fn();
+ LL| |}
+ LL| |
+ LL| |#[cfg_attr(auto, automatically_derived)]
+ LL| |#[cfg_attr(on, automatically_derived)]
+ LL| |#[cfg_attr(on, coverage(on))]
+ LL| |impl MyTrait for MyStruct {
+ LL| 1| fn my_assoc_fn() {
+ LL| 1| fn inner_fn() {
+ LL| 1| say("in inner fn");
+ LL| 1| }
+ LL| |
+ LL| | #[coverage(on)]
+ LL| 1| fn inner_fn_on() {
+ LL| 1| say("in inner fn (on)");
+ LL| 1| }
+ LL| |
+ LL| 1| let closure = || {
+ LL| 1| say("in closure");
+ LL| 1| };
+ LL| |
+ LL| 1| closure();
+ LL| 1| inner_fn();
+ LL| 1| inner_fn_on();
+ LL| 1| }
+ LL| |}
+ LL| |
+ LL| |#[coverage(off)]
+ LL| |#[inline(never)]
+ LL| |fn say(s: &str) {
+ LL| | println!("{s}");
+ LL| |}
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| MyStruct::my_assoc_fn();
+ LL| 1|}
+
diff --git a/tests/coverage/auto-derived.on.cov-map b/tests/coverage/auto-derived.on.cov-map
new file mode 100644
index 0000000..2dcd616
--- /dev/null
+++ b/tests/coverage/auto-derived.on.cov-map
@@ -0,0 +1,61 @@
+Function name: <auto_derived::MyStruct as auto_derived::MyTrait>::my_assoc_fn
+Raw bytes (34): 0x[01, 01, 00, 06, 01, 19, 05, 00, 15, 01, 0a, 0d, 00, 14, 01, 04, 09, 00, 12, 01, 01, 09, 00, 11, 01, 01, 09, 00, 14, 01, 01, 05, 00, 06]
+Number of files: 1
+- file 0 => $DIR/auto-derived.rs
+Number of expressions: 0
+Number of file 0 mappings: 6
+- Code(Counter(0)) at (prev + 25, 5) to (start + 0, 21)
+- Code(Counter(0)) at (prev + 10, 13) to (start + 0, 20)
+- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 18)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 20)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6)
+Highest counter ID seen: c0
+
+Function name: <auto_derived::MyStruct as auto_derived::MyTrait>::my_assoc_fn::inner_fn
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 1a, 09, 00, 16, 01, 01, 0d, 00, 10, 01, 00, 11, 00, 1e, 01, 01, 09, 00, 0a]
+Number of files: 1
+- file 0 => $DIR/auto-derived.rs
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 26, 9) to (start + 0, 22)
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 16)
+- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 30)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
+Highest counter ID seen: c0
+
+Function name: <auto_derived::MyStruct as auto_derived::MyTrait>::my_assoc_fn::inner_fn_on
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 1f, 09, 00, 19, 01, 01, 0d, 00, 10, 01, 00, 11, 00, 23, 01, 01, 09, 00, 0a]
+Number of files: 1
+- file 0 => $DIR/auto-derived.rs
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 31, 9) to (start + 0, 25)
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 16)
+- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 35)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
+Highest counter ID seen: c0
+
+Function name: <auto_derived::MyStruct as auto_derived::MyTrait>::my_assoc_fn::{closure#0}
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 23, 1a, 00, 1b, 01, 01, 0d, 00, 10, 01, 00, 11, 00, 1d, 01, 01, 09, 00, 0a]
+Number of files: 1
+- file 0 => $DIR/auto-derived.rs
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 35, 26) to (start + 0, 27)
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 16)
+- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 29)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
+Highest counter ID seen: c0
+
+Function name: auto_derived::main
+Raw bytes (19): 0x[01, 01, 00, 03, 01, 33, 01, 00, 0a, 01, 01, 05, 00, 1a, 01, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => $DIR/auto-derived.rs
+Number of expressions: 0
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 51, 1) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 26)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
+Highest counter ID seen: c0
+
diff --git a/tests/coverage/auto-derived.on.coverage b/tests/coverage/auto-derived.on.coverage
new file mode 100644
index 0000000..6ab6aa5
--- /dev/null
+++ b/tests/coverage/auto-derived.on.coverage
@@ -0,0 +1,54 @@
+ LL| |#![feature(coverage_attribute)]
+ LL| |//@ edition: 2024
+ LL| |//@ revisions: base auto on
+ LL| |
+ LL| |// Tests for how `#[automatically_derived]` affects coverage instrumentation.
+ LL| |//
+ LL| |// The actual behaviour is an implementation detail, so this test mostly exists
+ LL| |// to show when that behaviour has been accidentally or deliberately changed.
+ LL| |//
+ LL| |// Revision guide:
+ LL| |// - base: Test baseline instrumentation behaviour without `#[automatically_derived]`
+ LL| |// - auto: Test how `#[automatically_derived]` affects instrumentation
+ LL| |// - on: Test interaction between auto-derived and `#[coverage(on)]`
+ LL| |
+ LL| |struct MyStruct;
+ LL| |
+ LL| |trait MyTrait {
+ LL| | fn my_assoc_fn();
+ LL| |}
+ LL| |
+ LL| |#[cfg_attr(auto, automatically_derived)]
+ LL| |#[cfg_attr(on, automatically_derived)]
+ LL| |#[cfg_attr(on, coverage(on))]
+ LL| |impl MyTrait for MyStruct {
+ LL| 1| fn my_assoc_fn() {
+ LL| 1| fn inner_fn() {
+ LL| 1| say("in inner fn");
+ LL| 1| }
+ LL| |
+ LL| | #[coverage(on)]
+ LL| 1| fn inner_fn_on() {
+ LL| 1| say("in inner fn (on)");
+ LL| 1| }
+ LL| |
+ LL| 1| let closure = || {
+ LL| 1| say("in closure");
+ LL| 1| };
+ LL| |
+ LL| 1| closure();
+ LL| 1| inner_fn();
+ LL| 1| inner_fn_on();
+ LL| 1| }
+ LL| |}
+ LL| |
+ LL| |#[coverage(off)]
+ LL| |#[inline(never)]
+ LL| |fn say(s: &str) {
+ LL| | println!("{s}");
+ LL| |}
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| MyStruct::my_assoc_fn();
+ LL| 1|}
+
diff --git a/tests/coverage/auto-derived.rs b/tests/coverage/auto-derived.rs
new file mode 100644
index 0000000..cbf8279
--- /dev/null
+++ b/tests/coverage/auto-derived.rs
@@ -0,0 +1,53 @@
+#![feature(coverage_attribute)]
+//@ edition: 2024
+//@ revisions: base auto on
+
+// Tests for how `#[automatically_derived]` affects coverage instrumentation.
+//
+// The actual behaviour is an implementation detail, so this test mostly exists
+// to show when that behaviour has been accidentally or deliberately changed.
+//
+// Revision guide:
+// - base: Test baseline instrumentation behaviour without `#[automatically_derived]`
+// - auto: Test how `#[automatically_derived]` affects instrumentation
+// - on: Test interaction between auto-derived and `#[coverage(on)]`
+
+struct MyStruct;
+
+trait MyTrait {
+ fn my_assoc_fn();
+}
+
+#[cfg_attr(auto, automatically_derived)]
+#[cfg_attr(on, automatically_derived)]
+#[cfg_attr(on, coverage(on))]
+impl MyTrait for MyStruct {
+ fn my_assoc_fn() {
+ fn inner_fn() {
+ say("in inner fn");
+ }
+
+ #[coverage(on)]
+ fn inner_fn_on() {
+ say("in inner fn (on)");
+ }
+
+ let closure = || {
+ say("in closure");
+ };
+
+ closure();
+ inner_fn();
+ inner_fn_on();
+ }
+}
+
+#[coverage(off)]
+#[inline(never)]
+fn say(s: &str) {
+ println!("{s}");
+}
+
+fn main() {
+ MyStruct::my_assoc_fn();
+}
diff --git a/tests/coverage/auxiliary/try_in_macro_helper.rs b/tests/coverage/auxiliary/try_in_macro_helper.rs
new file mode 100644
index 0000000..27d2af1
--- /dev/null
+++ b/tests/coverage/auxiliary/try_in_macro_helper.rs
@@ -0,0 +1,31 @@
+//@ edition: 2024
+// (The proc-macro crate doesn't need to be instrumented.)
+//@ compile-flags: -Cinstrument-coverage=off
+
+use proc_macro::TokenStream;
+
+/// Minimized form of `#[derive(arbitrary::Arbitrary)]` that still triggers
+/// the original bug.
+const CODE: &str = "
+ impl Arbitrary for MyEnum {
+ fn try_size_hint() -> Option<usize> {
+ Some(0)?;
+ None
+ }
+ }
+";
+
+#[proc_macro_attribute]
+pub fn attr(_attr: TokenStream, _item: TokenStream) -> TokenStream {
+ CODE.parse().unwrap()
+}
+
+#[proc_macro]
+pub fn bang(_item: TokenStream) -> TokenStream {
+ CODE.parse().unwrap()
+}
+
+#[proc_macro_derive(Arbitrary)]
+pub fn derive_arbitrary(_item: TokenStream) -> TokenStream {
+ CODE.parse().unwrap()
+}
diff --git a/tests/coverage/try-in-macro.attr.cov-map b/tests/coverage/try-in-macro.attr.cov-map
new file mode 100644
index 0000000..7111e89
--- /dev/null
+++ b/tests/coverage/try-in-macro.attr.cov-map
@@ -0,0 +1,20 @@
+Function name: <try_in_macro::MyEnum as try_in_macro::Arbitrary>::try_size_hint
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 1e, 2a, 00, 2b]
+Number of files: 1
+- file 0 => $DIR/try-in-macro.rs
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 30, 42) to (start + 0, 43)
+Highest counter ID seen: (none)
+
+Function name: try_in_macro::main
+Raw bytes (19): 0x[01, 01, 00, 03, 01, 29, 01, 00, 0a, 01, 01, 05, 00, 1a, 01, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => $DIR/try-in-macro.rs
+Number of expressions: 0
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 26)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
+Highest counter ID seen: c0
+
diff --git a/tests/coverage/try-in-macro.attr.coverage b/tests/coverage/try-in-macro.attr.coverage
new file mode 100644
index 0000000..457a161
--- /dev/null
+++ b/tests/coverage/try-in-macro.attr.coverage
@@ -0,0 +1,44 @@
+ LL| |//! Regression test for <https://github.com/rust-lang/rust/issues/141577>.
+ LL| |//!
+ LL| |//! The changes in <https://github.com/rust-lang/rust/pull/144298> exposed a
+ LL| |//! latent bug that would sometimes cause the compiler to emit a covfun record
+ LL| |//! for a function, but not emit a corresponding PGO symbol name entry, because
+ LL| |//! the function did not have any physical coverage counters. The `llvm-cov`
+ LL| |//! tool would then fail to resolve the covfun record's function name hash,
+ LL| |//! and exit with the cryptic error:
+ LL| |//!
+ LL| |//! ```text
+ LL| |//! malformed instrumentation profile data: function name is empty
+ LL| |//! ```
+ LL| |//!
+ LL| |//! The bug was then triggered in the wild by the macro-expansion of
+ LL| |//! `#[derive(arbitrary::Arbitrary)]`.
+ LL| |//!
+ LL| |//! This test uses a minimized form of the `Arbitrary` derive macro that was
+ LL| |//! found to still trigger the original bug. The bug could also be triggered
+ LL| |//! by a bang proc-macro or an attribute proc-macro.
+ LL| |
+ LL| |//@ edition: 2024
+ LL| |//@ revisions: attr bang derive
+ LL| |//@ proc-macro: try_in_macro_helper.rs
+ LL| |
+ LL| |trait Arbitrary {
+ LL| | fn try_size_hint() -> Option<usize>;
+ LL| |}
+ LL| |
+ LL| |// Expand via an attribute proc-macro.
+ LL| |#[cfg_attr(attr, try_in_macro_helper::attr)]
+ LL| |const _: () = ();
+ LL| |
+ LL| |// Expand via a regular bang-style proc-macro.
+ LL| |#[cfg(bang)]
+ LL| |try_in_macro_helper::bang!();
+ LL| |
+ LL| |// Expand via a derive proc-macro.
+ LL| |#[cfg_attr(derive, derive(try_in_macro_helper::Arbitrary))]
+ LL| |enum MyEnum {}
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| MyEnum::try_size_hint();
+ LL| 1|}
+
diff --git a/tests/coverage/try-in-macro.bang.cov-map b/tests/coverage/try-in-macro.bang.cov-map
new file mode 100644
index 0000000..80bd91a
--- /dev/null
+++ b/tests/coverage/try-in-macro.bang.cov-map
@@ -0,0 +1,20 @@
+Function name: <try_in_macro::MyEnum as try_in_macro::Arbitrary>::try_size_hint
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 23, 1c, 00, 1d]
+Number of files: 1
+- file 0 => $DIR/try-in-macro.rs
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 35, 28) to (start + 0, 29)
+Highest counter ID seen: (none)
+
+Function name: try_in_macro::main
+Raw bytes (19): 0x[01, 01, 00, 03, 01, 29, 01, 00, 0a, 01, 01, 05, 00, 1a, 01, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => $DIR/try-in-macro.rs
+Number of expressions: 0
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 26)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
+Highest counter ID seen: c0
+
diff --git a/tests/coverage/try-in-macro.bang.coverage b/tests/coverage/try-in-macro.bang.coverage
new file mode 100644
index 0000000..457a161
--- /dev/null
+++ b/tests/coverage/try-in-macro.bang.coverage
@@ -0,0 +1,44 @@
+ LL| |//! Regression test for <https://github.com/rust-lang/rust/issues/141577>.
+ LL| |//!
+ LL| |//! The changes in <https://github.com/rust-lang/rust/pull/144298> exposed a
+ LL| |//! latent bug that would sometimes cause the compiler to emit a covfun record
+ LL| |//! for a function, but not emit a corresponding PGO symbol name entry, because
+ LL| |//! the function did not have any physical coverage counters. The `llvm-cov`
+ LL| |//! tool would then fail to resolve the covfun record's function name hash,
+ LL| |//! and exit with the cryptic error:
+ LL| |//!
+ LL| |//! ```text
+ LL| |//! malformed instrumentation profile data: function name is empty
+ LL| |//! ```
+ LL| |//!
+ LL| |//! The bug was then triggered in the wild by the macro-expansion of
+ LL| |//! `#[derive(arbitrary::Arbitrary)]`.
+ LL| |//!
+ LL| |//! This test uses a minimized form of the `Arbitrary` derive macro that was
+ LL| |//! found to still trigger the original bug. The bug could also be triggered
+ LL| |//! by a bang proc-macro or an attribute proc-macro.
+ LL| |
+ LL| |//@ edition: 2024
+ LL| |//@ revisions: attr bang derive
+ LL| |//@ proc-macro: try_in_macro_helper.rs
+ LL| |
+ LL| |trait Arbitrary {
+ LL| | fn try_size_hint() -> Option<usize>;
+ LL| |}
+ LL| |
+ LL| |// Expand via an attribute proc-macro.
+ LL| |#[cfg_attr(attr, try_in_macro_helper::attr)]
+ LL| |const _: () = ();
+ LL| |
+ LL| |// Expand via a regular bang-style proc-macro.
+ LL| |#[cfg(bang)]
+ LL| |try_in_macro_helper::bang!();
+ LL| |
+ LL| |// Expand via a derive proc-macro.
+ LL| |#[cfg_attr(derive, derive(try_in_macro_helper::Arbitrary))]
+ LL| |enum MyEnum {}
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| MyEnum::try_size_hint();
+ LL| 1|}
+
diff --git a/tests/coverage/try-in-macro.derive.cov-map b/tests/coverage/try-in-macro.derive.cov-map
new file mode 100644
index 0000000..6646b66
--- /dev/null
+++ b/tests/coverage/try-in-macro.derive.cov-map
@@ -0,0 +1,20 @@
+Function name: <try_in_macro::MyEnum as try_in_macro::Arbitrary>::try_size_hint
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 26, 38, 00, 39]
+Number of files: 1
+- file 0 => $DIR/try-in-macro.rs
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 38, 56) to (start + 0, 57)
+Highest counter ID seen: (none)
+
+Function name: try_in_macro::main
+Raw bytes (19): 0x[01, 01, 00, 03, 01, 29, 01, 00, 0a, 01, 01, 05, 00, 1a, 01, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => $DIR/try-in-macro.rs
+Number of expressions: 0
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 26)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
+Highest counter ID seen: c0
+
diff --git a/tests/coverage/try-in-macro.derive.coverage b/tests/coverage/try-in-macro.derive.coverage
new file mode 100644
index 0000000..457a161
--- /dev/null
+++ b/tests/coverage/try-in-macro.derive.coverage
@@ -0,0 +1,44 @@
+ LL| |//! Regression test for <https://github.com/rust-lang/rust/issues/141577>.
+ LL| |//!
+ LL| |//! The changes in <https://github.com/rust-lang/rust/pull/144298> exposed a
+ LL| |//! latent bug that would sometimes cause the compiler to emit a covfun record
+ LL| |//! for a function, but not emit a corresponding PGO symbol name entry, because
+ LL| |//! the function did not have any physical coverage counters. The `llvm-cov`
+ LL| |//! tool would then fail to resolve the covfun record's function name hash,
+ LL| |//! and exit with the cryptic error:
+ LL| |//!
+ LL| |//! ```text
+ LL| |//! malformed instrumentation profile data: function name is empty
+ LL| |//! ```
+ LL| |//!
+ LL| |//! The bug was then triggered in the wild by the macro-expansion of
+ LL| |//! `#[derive(arbitrary::Arbitrary)]`.
+ LL| |//!
+ LL| |//! This test uses a minimized form of the `Arbitrary` derive macro that was
+ LL| |//! found to still trigger the original bug. The bug could also be triggered
+ LL| |//! by a bang proc-macro or an attribute proc-macro.
+ LL| |
+ LL| |//@ edition: 2024
+ LL| |//@ revisions: attr bang derive
+ LL| |//@ proc-macro: try_in_macro_helper.rs
+ LL| |
+ LL| |trait Arbitrary {
+ LL| | fn try_size_hint() -> Option<usize>;
+ LL| |}
+ LL| |
+ LL| |// Expand via an attribute proc-macro.
+ LL| |#[cfg_attr(attr, try_in_macro_helper::attr)]
+ LL| |const _: () = ();
+ LL| |
+ LL| |// Expand via a regular bang-style proc-macro.
+ LL| |#[cfg(bang)]
+ LL| |try_in_macro_helper::bang!();
+ LL| |
+ LL| |// Expand via a derive proc-macro.
+ LL| |#[cfg_attr(derive, derive(try_in_macro_helper::Arbitrary))]
+ LL| |enum MyEnum {}
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| MyEnum::try_size_hint();
+ LL| 1|}
+
diff --git a/tests/coverage/try-in-macro.rs b/tests/coverage/try-in-macro.rs
new file mode 100644
index 0000000..ab9d667
--- /dev/null
+++ b/tests/coverage/try-in-macro.rs
@@ -0,0 +1,43 @@
+//! Regression test for <https://github.com/rust-lang/rust/issues/141577>.
+//!
+//! The changes in <https://github.com/rust-lang/rust/pull/144298> exposed a
+//! latent bug that would sometimes cause the compiler to emit a covfun record
+//! for a function, but not emit a corresponding PGO symbol name entry, because
+//! the function did not have any physical coverage counters. The `llvm-cov`
+//! tool would then fail to resolve the covfun record's function name hash,
+//! and exit with the cryptic error:
+//!
+//! ```text
+//! malformed instrumentation profile data: function name is empty
+//! ```
+//!
+//! The bug was then triggered in the wild by the macro-expansion of
+//! `#[derive(arbitrary::Arbitrary)]`.
+//!
+//! This test uses a minimized form of the `Arbitrary` derive macro that was
+//! found to still trigger the original bug. The bug could also be triggered
+//! by a bang proc-macro or an attribute proc-macro.
+
+//@ edition: 2024
+//@ revisions: attr bang derive
+//@ proc-macro: try_in_macro_helper.rs
+
+trait Arbitrary {
+ fn try_size_hint() -> Option<usize>;
+}
+
+// Expand via an attribute proc-macro.
+#[cfg_attr(attr, try_in_macro_helper::attr)]
+const _: () = ();
+
+// Expand via a regular bang-style proc-macro.
+#[cfg(bang)]
+try_in_macro_helper::bang!();
+
+// Expand via a derive proc-macro.
+#[cfg_attr(derive, derive(try_in_macro_helper::Arbitrary))]
+enum MyEnum {}
+
+fn main() {
+ MyEnum::try_size_hint();
+}
diff --git a/tests/crashes/121097.rs b/tests/crashes/121097.rs
deleted file mode 100644
index 65c6028..0000000
--- a/tests/crashes/121097.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ known-bug: #121097
-#[repr(simd)]
-enum Aligned {
- Zero = 0,
- One = 1,
-}
-
-fn tou8(al: Aligned) -> u8 {
- al as u8
-}
diff --git a/tests/crashes/121176.rs b/tests/crashes/121176.rs
deleted file mode 100644
index 4d82e51..0000000
--- a/tests/crashes/121176.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ known-bug: #121176
-//@ needs-rustc-debug-assertions
-use std::fmt::Debug;
-
-static STATIC_1: dyn Debug + Sync = *();
-
-fn main() {
- println!("{:?}", &STATIC_1);
-}
diff --git a/tests/crashes/129109.rs b/tests/crashes/129109.rs
deleted file mode 100644
index 0db53b9..0000000
--- a/tests/crashes/129109.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ known-bug: rust-lang/rust#129109
-//@ compile-flags: -Zmir-enable-passes=+GVN -Zvalidate-mir
-
-extern "C" {
- pub static mut symbol: [i8];
-}
-
-fn main() {
- println!("C", unsafe { &symbol });
-}
diff --git a/tests/crashes/130970.rs b/tests/crashes/130970.rs
deleted file mode 100644
index 698c2b4..0000000
--- a/tests/crashes/130970.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ known-bug: #130970
-//@ compile-flags: -Zmir-enable-passes=+GVN -Zvalidate-mir
-
-fn main() {
- extern "C" {
- static symbol: [usize];
- }
- println!("{}", symbol[0]);
-}
diff --git a/tests/crashes/131347.rs b/tests/crashes/131347.rs
deleted file mode 100644
index 08f7d06..0000000
--- a/tests/crashes/131347.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ known-bug: #131347
-//@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+Inline -Zvalidate-mir
-
-struct S;
-static STUFF: [i8] = [0; S::N];
-
-fn main() {
- assert_eq!(STUFF, [0; 63]);
-}
diff --git a/tests/debuginfo/basic-types-globals-metadata.rs b/tests/debuginfo/basic-types-globals-metadata.rs
index 53fc550..aec8ff1 100644
--- a/tests/debuginfo/basic-types-globals-metadata.rs
+++ b/tests/debuginfo/basic-types-globals-metadata.rs
@@ -59,7 +59,12 @@
fn main() {
_zzz(); // #break
- let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F16, F32, F64) };
+ let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F32, F64) };
+ // FIXME: Including f16 and f32 in the same tuple emits `__gnu_h2f_ieee`, which
+ // does not exist on some targets like PowerPC.
+ // See https://github.com/llvm/llvm-project/issues/97981 and
+ // https://github.com/rust-lang/compiler-builtins/issues/655
+ let b = unsafe { F16 };
}
fn _zzz() {()}
diff --git a/tests/debuginfo/basic-types-globals.rs b/tests/debuginfo/basic-types-globals.rs
index 41b6993..15a0deb 100644
--- a/tests/debuginfo/basic-types-globals.rs
+++ b/tests/debuginfo/basic-types-globals.rs
@@ -63,7 +63,12 @@
fn main() {
_zzz(); // #break
- let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F16, F32, F64) };
+ let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F32, F64) };
+ // FIXME: Including f16 and f32 in the same tuple emits `__gnu_h2f_ieee`, which
+ // does not exist on some targets like PowerPC.
+ // See https://github.com/llvm/llvm-project/issues/97981 and
+ // https://github.com/rust-lang/compiler-builtins/issues/655
+ let b = unsafe { F16 };
}
fn _zzz() {()}
diff --git a/tests/debuginfo/by-value-non-immediate-argument.rs b/tests/debuginfo/by-value-non-immediate-argument.rs
index 5233b95..deacea5 100644
--- a/tests/debuginfo/by-value-non-immediate-argument.rs
+++ b/tests/debuginfo/by-value-non-immediate-argument.rs
@@ -3,6 +3,7 @@
//@ compile-flags:-g
//@ ignore-windows-gnu: #128973
//@ ignore-aarch64-unknown-linux-gnu (gdb tries to read from 0x0; FIXME: #128973)
+//@ ignore-powerpc64: #128973 on both -gnu and -musl
// === GDB TESTS ===================================================================================
diff --git a/tests/debuginfo/unsized.rs b/tests/debuginfo/unsized.rs
index 17c5e46..edd9f5a 100644
--- a/tests/debuginfo/unsized.rs
+++ b/tests/debuginfo/unsized.rs
@@ -37,7 +37,6 @@
// cdb-check: [...] vtable : 0x[...] [Type: unsigned [...]int[...] (*)[4]]
// cdb-command:dx _box
-// cdb-check:
// cdb-check:_box [Type: alloc::boxed::Box<unsized::Foo<dyn$<core::fmt::Debug> >,alloc::alloc::Global>]
// cdb-check:[+0x000] pointer : 0x[...] [Type: unsized::Foo<dyn$<core::fmt::Debug> > *]
// cdb-check:[...] vtable : 0x[...] [Type: unsigned [...]int[...] (*)[4]]
diff --git a/tests/mir-opt/building/enum_cast.bar.built.after.mir b/tests/mir-opt/building/enum_cast.bar.built.after.mir
index 72d0cf5..0dc6448 100644
--- a/tests/mir-opt/building/enum_cast.bar.built.after.mir
+++ b/tests/mir-opt/building/enum_cast.bar.built.after.mir
@@ -5,16 +5,11 @@
let mut _0: usize;
let _2: Bar;
let mut _3: isize;
- let mut _4: u8;
- let mut _5: bool;
bb0: {
StorageLive(_2);
_2 = move _1;
_3 = discriminant(_2);
- _4 = copy _3 as u8 (IntToInt);
- _5 = Le(copy _4, const 1_u8);
- assume(move _5);
_0 = move _3 as usize (IntToInt);
StorageDead(_2);
return;
diff --git a/tests/mir-opt/building/enum_cast.boo.built.after.mir b/tests/mir-opt/building/enum_cast.boo.built.after.mir
index 91e06dc..3540a2b 100644
--- a/tests/mir-opt/building/enum_cast.boo.built.after.mir
+++ b/tests/mir-opt/building/enum_cast.boo.built.after.mir
@@ -5,16 +5,11 @@
let mut _0: usize;
let _2: Boo;
let mut _3: u8;
- let mut _4: u8;
- let mut _5: bool;
bb0: {
StorageLive(_2);
_2 = move _1;
_3 = discriminant(_2);
- _4 = copy _3 as u8 (IntToInt);
- _5 = Le(copy _4, const 1_u8);
- assume(move _5);
_0 = move _3 as usize (IntToInt);
StorageDead(_2);
return;
diff --git a/tests/mir-opt/building/enum_cast.far.built.after.mir b/tests/mir-opt/building/enum_cast.far.built.after.mir
index 14eaf344..da34b7b 100644
--- a/tests/mir-opt/building/enum_cast.far.built.after.mir
+++ b/tests/mir-opt/building/enum_cast.far.built.after.mir
@@ -5,16 +5,11 @@
let mut _0: isize;
let _2: Far;
let mut _3: i16;
- let mut _4: u16;
- let mut _5: bool;
bb0: {
StorageLive(_2);
_2 = move _1;
_3 = discriminant(_2);
- _4 = copy _3 as u16 (IntToInt);
- _5 = Le(copy _4, const 1_u16);
- assume(move _5);
_0 = move _3 as isize (IntToInt);
StorageDead(_2);
return;
diff --git a/tests/mir-opt/building/enum_cast.offsetty.built.after.mir b/tests/mir-opt/building/enum_cast.offsetty.built.after.mir
index 1c2acbe..b84ce0d 100644
--- a/tests/mir-opt/building/enum_cast.offsetty.built.after.mir
+++ b/tests/mir-opt/building/enum_cast.offsetty.built.after.mir
@@ -5,20 +5,11 @@
let mut _0: u32;
let _2: NotStartingAtZero;
let mut _3: isize;
- let mut _4: u8;
- let mut _5: bool;
- let mut _6: bool;
- let mut _7: bool;
bb0: {
StorageLive(_2);
_2 = move _1;
_3 = discriminant(_2);
- _4 = copy _3 as u8 (IntToInt);
- _5 = Ge(copy _4, const 4_u8);
- _6 = Le(copy _4, const 8_u8);
- _7 = BitAnd(move _5, move _6);
- assume(move _7);
_0 = move _3 as u32 (IntToInt);
StorageDead(_2);
return;
diff --git a/tests/mir-opt/building/enum_cast.rs b/tests/mir-opt/building/enum_cast.rs
index 4fb9a27..eaf5537 100644
--- a/tests/mir-opt/building/enum_cast.rs
+++ b/tests/mir-opt/building/enum_cast.rs
@@ -4,6 +4,13 @@
// EMIT_MIR enum_cast.boo.built.after.mir
// EMIT_MIR enum_cast.far.built.after.mir
+// Previously MIR building included range `Assume`s in the MIR statements,
+// which these tests demonstrated, but now that we have range metadata on
+// parameters in LLVM (in addition to !range metadata on loads) the impact
+// of the extra volume of MIR is worse than its value.
+// Thus these are now about the discriminant type and the cast type,
+// both of which might be different from the backend type of the tag.
+
enum Foo {
A,
}
diff --git a/tests/mir-opt/building/enum_cast.signy.built.after.mir b/tests/mir-opt/building/enum_cast.signy.built.after.mir
index 39b6dfa..503c506 100644
--- a/tests/mir-opt/building/enum_cast.signy.built.after.mir
+++ b/tests/mir-opt/building/enum_cast.signy.built.after.mir
@@ -5,20 +5,11 @@
let mut _0: i16;
let _2: SignedAroundZero;
let mut _3: i16;
- let mut _4: u16;
- let mut _5: bool;
- let mut _6: bool;
- let mut _7: bool;
bb0: {
StorageLive(_2);
_2 = move _1;
_3 = discriminant(_2);
- _4 = copy _3 as u16 (IntToInt);
- _5 = Ge(copy _4, const 65534_u16);
- _6 = Le(copy _4, const 2_u16);
- _7 = BitOr(move _5, move _6);
- assume(move _7);
_0 = move _3 as i16 (IntToInt);
StorageDead(_2);
return;
diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
index fa88211..d465b8b 100644
--- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
@@ -40,7 +40,7 @@
+ coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:17: 19:18 (#0);
+ coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:23: 19:30 (#0);
+ coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:31: 19:32 (#0);
-+ coverage Code { bcb: bcb2 } => $DIR/branch_match_arms.rs:21:1: 21:2 (#0);
++ coverage Code { bcb: bcb2 } => $DIR/branch_match_arms.rs:21:2: 21:2 (#0);
+
bb0: {
+ Coverage::VirtualCounter(bcb0);
diff --git a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
index 9b6d2b2..cf6d85a 100644
--- a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
@@ -6,7 +6,7 @@
+ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:27:1: 27:17 (#0);
+ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:28:5: 28:9 (#0);
-+ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:29:1: 29:2 (#0);
++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:29:2: 29:2 (#0);
+
bb0: {
+ Coverage::VirtualCounter(bcb0);
diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
index b2bb237..980c5e2 100644
--- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
@@ -10,8 +10,8 @@
+ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:13:1: 13:10 (#0);
+ coverage Code { bcb: bcb1 } => $DIR/instrument_coverage.rs:15:12: 15:15 (#0);
+ coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:16:13: 16:18 (#0);
-+ coverage Code { bcb: bcb3 } => $DIR/instrument_coverage.rs:17:9: 17:10 (#0);
-+ coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:19:1: 19:2 (#0);
++ coverage Code { bcb: bcb3 } => $DIR/instrument_coverage.rs:17:10: 17:10 (#0);
++ coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:19:2: 19:2 (#0);
+
bb0: {
+ Coverage::VirtualCounter(bcb0);
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
index 2eb78c0..b707cd4 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
@@ -10,8 +10,8 @@
coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 13:10 (#0);
coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
coverage Code { bcb: bcb3 } => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0);
- coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:38: 14:39 (#0);
- coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:1: 15:2 (#0);
+ coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0);
+ coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0);
coverage Branch { true_bcb: bcb3, false_bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
bb0: {
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
index 0c1bc24..239b845 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
@@ -10,8 +10,8 @@
+ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 13:10 (#0);
+ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
+ coverage Code { bcb: bcb3 } => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0);
-+ coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:38: 14:39 (#0);
-+ coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:1: 15:2 (#0);
++ coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0);
++ coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0);
+ coverage Branch { true_bcb: bcb3, false_bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
+
bb0: {
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 169a676..22e6ea7 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"
@@ -64,9 +64,8 @@
+ let mut _45: &mut std::future::Ready<()>;
+ let mut _46: &mut std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
-+ let mut _47: std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) {
-+ let mut _48: &mut &mut std::future::Ready<()>;
++ let mut _47: &mut &mut std::future::Ready<()>;
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
+ }
+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
@@ -76,15 +75,15 @@
+ }
+ }
+ scope 19 (inlined Option::<()>::take) {
-+ let mut _49: std::option::Option<()>;
++ let mut _48: std::option::Option<()>;
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
+ scope 21 {
+ }
+ }
+ }
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
-+ let mut _50: isize;
-+ let mut _51: !;
++ let mut _49: isize;
++ let mut _50: !;
+ scope 23 {
+ }
+ }
@@ -229,28 +228,25 @@
+ StorageDead(_24);
+ StorageLive(_45);
+ StorageLive(_46);
-+ StorageLive(_51);
++ StorageLive(_50);
+ StorageLive(_42);
+ StorageLive(_43);
+ StorageLive(_44);
+ _46 = &mut _19;
+ StorageLive(_47);
-+ StorageLive(_48);
-+ _48 = &mut (_19.0: &mut std::future::Ready<()>);
++ _47 = &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 };
+ StorageDead(_47);
+ _44 = &mut ((*_45).0: std::option::Option<()>);
-+ StorageLive(_49);
-+ _49 = Option::<()>::None;
++ StorageLive(_48);
++ _48 = Option::<()>::None;
+ _43 = copy ((*_45).0: std::option::Option<()>);
-+ ((*_45).0: std::option::Option<()>) = copy _49;
-+ StorageDead(_49);
++ ((*_45).0: std::option::Option<()>) = copy _48;
++ StorageDead(_48);
+ StorageDead(_44);
-+ StorageLive(_50);
-+ _50 = discriminant(_43);
-+ switchInt(move _50) -> [0: bb11, 1: bb12, otherwise: bb5];
++ StorageLive(_49);
++ _49 = discriminant(_43);
++ switchInt(move _49) -> [0: bb11, 1: bb12, otherwise: bb5];
}
+
+ bb5: {
@@ -313,16 +309,16 @@
+ }
+
+ bb11: {
-+ _51 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
++ _50 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
+ }
+
+ bb12: {
+ _42 = move ((_43 as Some).0: ());
-+ StorageDead(_50);
++ StorageDead(_49);
+ StorageDead(_43);
+ _18 = Poll::<()>::Ready(move _42);
+ StorageDead(_42);
-+ StorageDead(_51);
++ StorageDead(_50);
+ StorageDead(_46);
+ StorageDead(_45);
+ StorageDead(_22);
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 14ba331..8b027e9 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"
@@ -66,9 +66,8 @@
+ let mut _47: &mut std::future::Ready<()>;
+ let mut _48: &mut std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
-+ let mut _49: std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) {
-+ let mut _50: &mut &mut std::future::Ready<()>;
++ let mut _49: &mut &mut std::future::Ready<()>;
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
+ }
+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
@@ -78,15 +77,15 @@
+ }
+ }
+ scope 19 (inlined Option::<()>::take) {
-+ let mut _51: std::option::Option<()>;
++ let mut _50: std::option::Option<()>;
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
+ scope 21 {
+ }
+ }
+ }
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
-+ let mut _52: isize;
-+ let mut _53: !;
++ let mut _51: isize;
++ let mut _52: !;
+ scope 23 {
+ }
+ }
@@ -246,28 +245,25 @@
+ StorageDead(_24);
+ StorageLive(_47);
+ StorageLive(_48);
-+ StorageLive(_53);
++ StorageLive(_52);
+ StorageLive(_44);
+ StorageLive(_45);
+ StorageLive(_46);
+ _48 = &mut _19;
+ StorageLive(_49);
-+ StorageLive(_50);
-+ _50 = &mut (_19.0: &mut std::future::Ready<()>);
++ _49 = &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 };
+ StorageDead(_49);
+ _46 = &mut ((*_47).0: std::option::Option<()>);
-+ StorageLive(_51);
-+ _51 = Option::<()>::None;
++ StorageLive(_50);
++ _50 = Option::<()>::None;
+ _45 = copy ((*_47).0: std::option::Option<()>);
-+ ((*_47).0: std::option::Option<()>) = copy _51;
-+ StorageDead(_51);
++ ((*_47).0: std::option::Option<()>) = copy _50;
++ StorageDead(_50);
+ StorageDead(_46);
-+ StorageLive(_52);
-+ _52 = discriminant(_45);
-+ switchInt(move _52) -> [0: bb16, 1: bb17, otherwise: bb7];
++ StorageLive(_51);
++ _51 = discriminant(_45);
++ switchInt(move _51) -> [0: bb16, 1: bb17, otherwise: bb7];
}
- bb6 (cleanup): {
@@ -354,16 +350,16 @@
+ }
+
+ bb16: {
-+ _53 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
++ _52 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
+ }
+
+ bb17: {
+ _44 = move ((_45 as Some).0: ());
-+ StorageDead(_52);
++ StorageDead(_51);
+ StorageDead(_45);
+ _18 = Poll::<()>::Ready(move _44);
+ StorageDead(_44);
-+ StorageDead(_53);
++ StorageDead(_52);
+ StorageDead(_48);
+ StorageDead(_47);
+ StorageDead(_22);
diff --git a/tests/mir-opt/instsimplify/align_of_slice.of_val_slice.InstSimplify-after-simplifycfg.diff b/tests/mir-opt/instsimplify/align_of_slice.of_val_slice.InstSimplify-after-simplifycfg.diff
new file mode 100644
index 0000000..042e19b
--- /dev/null
+++ b/tests/mir-opt/instsimplify/align_of_slice.of_val_slice.InstSimplify-after-simplifycfg.diff
@@ -0,0 +1,22 @@
+- // MIR for `of_val_slice` before InstSimplify-after-simplifycfg
++ // MIR for `of_val_slice` after InstSimplify-after-simplifycfg
+
+ fn of_val_slice(_1: &[T]) -> usize {
+ debug slice => _1;
+ let mut _0: usize;
+ let mut _2: *const [T];
+
+ bb0: {
+ StorageLive(_2);
+ _2 = &raw const (*_1);
+- _0 = std::intrinsics::align_of_val::<[T]>(move _2) -> [return: bb1, unwind unreachable];
++ _0 = AlignOf(T);
++ goto -> bb1;
+ }
+
+ bb1: {
+ StorageDead(_2);
+ return;
+ }
+ }
+
diff --git a/tests/mir-opt/instsimplify/align_of_slice.rs b/tests/mir-opt/instsimplify/align_of_slice.rs
new file mode 100644
index 0000000..0af05cb
--- /dev/null
+++ b/tests/mir-opt/instsimplify/align_of_slice.rs
@@ -0,0 +1,12 @@
+//@ test-mir-pass: InstSimplify-after-simplifycfg
+//@ needs-unwind
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+// EMIT_MIR align_of_slice.of_val_slice.InstSimplify-after-simplifycfg.diff
+pub fn of_val_slice<T>(slice: &[T]) -> usize {
+ // CHECK-LABEL: fn of_val_slice(_1: &[T])
+ // CHECK: _0 = AlignOf(T);
+ unsafe { core::intrinsics::align_of_val(slice) }
+}
diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir
index 5876c55..b5c2382 100644
--- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir
+++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir
@@ -8,12 +8,14 @@
let _2: std::option::Option<u32>;
scope 2 (inlined Option::<u32>::is_some) {
let mut _3: isize;
+ scope 3 {
+ }
}
}
- scope 3 (inlined #[track_caller] Option::<u32>::unwrap) {
+ scope 4 (inlined #[track_caller] Option::<u32>::unwrap) {
let mut _5: isize;
let mut _6: !;
- scope 4 {
+ scope 5 {
}
}
diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir
index f118535..f22b883 100644
--- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir
+++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir
@@ -8,12 +8,14 @@
let _2: std::option::Option<u32>;
scope 2 (inlined Option::<u32>::is_some) {
let mut _3: isize;
+ scope 3 {
+ }
}
}
- scope 3 (inlined #[track_caller] Option::<u32>::unwrap) {
+ scope 4 (inlined #[track_caller] Option::<u32>::unwrap) {
let mut _5: isize;
let mut _6: !;
- scope 4 {
+ scope 5 {
}
}
diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir
index 5876c55..b5c2382 100644
--- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir
+++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir
@@ -8,12 +8,14 @@
let _2: std::option::Option<u32>;
scope 2 (inlined Option::<u32>::is_some) {
let mut _3: isize;
+ scope 3 {
+ }
}
}
- scope 3 (inlined #[track_caller] Option::<u32>::unwrap) {
+ scope 4 (inlined #[track_caller] Option::<u32>::unwrap) {
let mut _5: isize;
let mut _6: !;
- scope 4 {
+ scope 5 {
}
}
diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir
index f118535..f22b883 100644
--- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir
+++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir
@@ -8,12 +8,14 @@
let _2: std::option::Option<u32>;
scope 2 (inlined Option::<u32>::is_some) {
let mut _3: isize;
+ scope 3 {
+ }
}
}
- scope 3 (inlined #[track_caller] Option::<u32>::unwrap) {
+ scope 4 (inlined #[track_caller] Option::<u32>::unwrap) {
let mut _5: isize;
let mut _6: !;
- scope 4 {
+ scope 5 {
}
}
diff --git a/tests/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff
index 281f43b..3ce82fd 100644
--- a/tests/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff
+++ b/tests/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff
@@ -7,6 +7,8 @@
let mut _2: bool;
let mut _3: isize;
+ let mut _4: isize;
+ scope 1 {
+ }
bb0: {
StorageLive(_2);
diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir
index 1a1c8b4..83478e6 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir
@@ -25,9 +25,11 @@
}
scope 8 (inlined Option::<u16>::is_none) {
scope 9 (inlined Option::<u16>::is_some) {
+ scope 10 {
+ }
}
}
- scope 10 (inlined core::num::<impl u16>::wrapping_add) {
+ scope 11 (inlined core::num::<impl u16>::wrapping_add) {
}
}
diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir
index e7e19af..ac7a6e0 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir
@@ -25,9 +25,11 @@
}
scope 8 (inlined Option::<u16>::is_none) {
scope 9 (inlined Option::<u16>::is_some) {
+ scope 10 {
+ }
}
}
- scope 10 (inlined core::num::<impl u16>::wrapping_add) {
+ scope 11 (inlined core::num::<impl u16>::wrapping_add) {
}
}
diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir
new file mode 100644
index 0000000..2777bba
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir
@@ -0,0 +1,108 @@
+// MIR for `generic_in_place` after PreCodegen
+
+fn generic_in_place(_1: *mut Box<[T]>) -> () {
+ debug ptr => _1;
+ let mut _0: ();
+ scope 1 (inlined drop_in_place::<Box<[T]>> - shim(Some(Box<[T]>))) {
+ scope 2 (inlined <Box<[T]> as Drop>::drop) {
+ let _2: std::ptr::NonNull<[T]>;
+ let mut _3: *mut [T];
+ let mut _4: *const [T];
+ let _12: ();
+ scope 3 {
+ let _8: std::ptr::alignment::AlignmentEnum;
+ scope 4 {
+ scope 12 (inlined Layout::size) {
+ }
+ scope 13 (inlined Unique::<[T]>::cast::<u8>) {
+ scope 14 (inlined NonNull::<[T]>::cast::<u8>) {
+ scope 15 (inlined NonNull::<[T]>::as_ptr) {
+ }
+ }
+ }
+ scope 16 (inlined <NonNull<u8> as From<Unique<u8>>>::from) {
+ scope 17 (inlined Unique::<u8>::as_non_null_ptr) {
+ }
+ }
+ scope 18 (inlined <std::alloc::Global as Allocator>::deallocate) {
+ let mut _9: *mut u8;
+ scope 19 (inlined Layout::size) {
+ }
+ scope 20 (inlined NonNull::<u8>::as_ptr) {
+ }
+ scope 21 (inlined std::alloc::dealloc) {
+ let mut _11: usize;
+ scope 22 (inlined Layout::size) {
+ }
+ scope 23 (inlined Layout::align) {
+ scope 24 (inlined std::ptr::Alignment::as_usize) {
+ let mut _10: u32;
+ }
+ }
+ }
+ }
+ }
+ scope 5 (inlined Unique::<[T]>::as_ptr) {
+ scope 6 (inlined NonNull::<[T]>::as_ptr) {
+ }
+ }
+ scope 7 (inlined Layout::for_value_raw::<[T]>) {
+ let mut _5: usize;
+ let mut _6: usize;
+ scope 8 {
+ scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) {
+ let mut _7: std::ptr::Alignment;
+ }
+ }
+ scope 9 (inlined size_of_val_raw::<[T]>) {
+ }
+ scope 10 (inlined align_of_val_raw::<[T]>) {
+ }
+ }
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_2);
+ _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>);
+ StorageLive(_4);
+ _3 = copy _2 as *mut [T] (Transmute);
+ _4 = copy _2 as *const [T] (Transmute);
+ StorageLive(_6);
+ _5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable];
+ }
+
+ bb1: {
+ _6 = AlignOf(T);
+ StorageLive(_7);
+ _7 = copy _6 as std::ptr::Alignment (Transmute);
+ _8 = move (_7.0: std::ptr::alignment::AlignmentEnum);
+ StorageDead(_7);
+ StorageDead(_6);
+ StorageDead(_4);
+ switchInt(copy _5) -> [0: bb4, otherwise: bb2];
+ }
+
+ bb2: {
+ StorageLive(_9);
+ _9 = copy _3 as *mut u8 (PtrToPtr);
+ StorageLive(_11);
+ StorageLive(_10);
+ _10 = discriminant(_8);
+ _11 = move _10 as usize (IntToInt);
+ StorageDead(_10);
+ _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable];
+ }
+
+ bb3: {
+ StorageDead(_11);
+ StorageDead(_9);
+ goto -> bb4;
+ }
+
+ bb4: {
+ StorageDead(_2);
+ return;
+ }
+}
diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir
new file mode 100644
index 0000000..2777bba
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir
@@ -0,0 +1,108 @@
+// MIR for `generic_in_place` after PreCodegen
+
+fn generic_in_place(_1: *mut Box<[T]>) -> () {
+ debug ptr => _1;
+ let mut _0: ();
+ scope 1 (inlined drop_in_place::<Box<[T]>> - shim(Some(Box<[T]>))) {
+ scope 2 (inlined <Box<[T]> as Drop>::drop) {
+ let _2: std::ptr::NonNull<[T]>;
+ let mut _3: *mut [T];
+ let mut _4: *const [T];
+ let _12: ();
+ scope 3 {
+ let _8: std::ptr::alignment::AlignmentEnum;
+ scope 4 {
+ scope 12 (inlined Layout::size) {
+ }
+ scope 13 (inlined Unique::<[T]>::cast::<u8>) {
+ scope 14 (inlined NonNull::<[T]>::cast::<u8>) {
+ scope 15 (inlined NonNull::<[T]>::as_ptr) {
+ }
+ }
+ }
+ scope 16 (inlined <NonNull<u8> as From<Unique<u8>>>::from) {
+ scope 17 (inlined Unique::<u8>::as_non_null_ptr) {
+ }
+ }
+ scope 18 (inlined <std::alloc::Global as Allocator>::deallocate) {
+ let mut _9: *mut u8;
+ scope 19 (inlined Layout::size) {
+ }
+ scope 20 (inlined NonNull::<u8>::as_ptr) {
+ }
+ scope 21 (inlined std::alloc::dealloc) {
+ let mut _11: usize;
+ scope 22 (inlined Layout::size) {
+ }
+ scope 23 (inlined Layout::align) {
+ scope 24 (inlined std::ptr::Alignment::as_usize) {
+ let mut _10: u32;
+ }
+ }
+ }
+ }
+ }
+ scope 5 (inlined Unique::<[T]>::as_ptr) {
+ scope 6 (inlined NonNull::<[T]>::as_ptr) {
+ }
+ }
+ scope 7 (inlined Layout::for_value_raw::<[T]>) {
+ let mut _5: usize;
+ let mut _6: usize;
+ scope 8 {
+ scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) {
+ let mut _7: std::ptr::Alignment;
+ }
+ }
+ scope 9 (inlined size_of_val_raw::<[T]>) {
+ }
+ scope 10 (inlined align_of_val_raw::<[T]>) {
+ }
+ }
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_2);
+ _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>);
+ StorageLive(_4);
+ _3 = copy _2 as *mut [T] (Transmute);
+ _4 = copy _2 as *const [T] (Transmute);
+ StorageLive(_6);
+ _5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable];
+ }
+
+ bb1: {
+ _6 = AlignOf(T);
+ StorageLive(_7);
+ _7 = copy _6 as std::ptr::Alignment (Transmute);
+ _8 = move (_7.0: std::ptr::alignment::AlignmentEnum);
+ StorageDead(_7);
+ StorageDead(_6);
+ StorageDead(_4);
+ switchInt(copy _5) -> [0: bb4, otherwise: bb2];
+ }
+
+ bb2: {
+ StorageLive(_9);
+ _9 = copy _3 as *mut u8 (PtrToPtr);
+ StorageLive(_11);
+ StorageLive(_10);
+ _10 = discriminant(_8);
+ _11 = move _10 as usize (IntToInt);
+ StorageDead(_10);
+ _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable];
+ }
+
+ bb3: {
+ StorageDead(_11);
+ StorageDead(_9);
+ goto -> bb4;
+ }
+
+ bb4: {
+ StorageDead(_2);
+ return;
+ }
+}
diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir
new file mode 100644
index 0000000..2be0a47
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir
@@ -0,0 +1,108 @@
+// MIR for `generic_in_place` after PreCodegen
+
+fn generic_in_place(_1: *mut Box<[T]>) -> () {
+ debug ptr => _1;
+ let mut _0: ();
+ scope 1 (inlined drop_in_place::<Box<[T]>> - shim(Some(Box<[T]>))) {
+ scope 2 (inlined <Box<[T]> as Drop>::drop) {
+ let _2: std::ptr::NonNull<[T]>;
+ let mut _3: *mut [T];
+ let mut _4: *const [T];
+ let _12: ();
+ scope 3 {
+ let _8: std::ptr::alignment::AlignmentEnum;
+ scope 4 {
+ scope 12 (inlined Layout::size) {
+ }
+ scope 13 (inlined Unique::<[T]>::cast::<u8>) {
+ scope 14 (inlined NonNull::<[T]>::cast::<u8>) {
+ scope 15 (inlined NonNull::<[T]>::as_ptr) {
+ }
+ }
+ }
+ scope 16 (inlined <NonNull<u8> as From<Unique<u8>>>::from) {
+ scope 17 (inlined Unique::<u8>::as_non_null_ptr) {
+ }
+ }
+ scope 18 (inlined <std::alloc::Global as Allocator>::deallocate) {
+ let mut _9: *mut u8;
+ scope 19 (inlined Layout::size) {
+ }
+ scope 20 (inlined NonNull::<u8>::as_ptr) {
+ }
+ scope 21 (inlined std::alloc::dealloc) {
+ let mut _11: usize;
+ scope 22 (inlined Layout::size) {
+ }
+ scope 23 (inlined Layout::align) {
+ scope 24 (inlined std::ptr::Alignment::as_usize) {
+ let mut _10: u64;
+ }
+ }
+ }
+ }
+ }
+ scope 5 (inlined Unique::<[T]>::as_ptr) {
+ scope 6 (inlined NonNull::<[T]>::as_ptr) {
+ }
+ }
+ scope 7 (inlined Layout::for_value_raw::<[T]>) {
+ let mut _5: usize;
+ let mut _6: usize;
+ scope 8 {
+ scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) {
+ let mut _7: std::ptr::Alignment;
+ }
+ }
+ scope 9 (inlined size_of_val_raw::<[T]>) {
+ }
+ scope 10 (inlined align_of_val_raw::<[T]>) {
+ }
+ }
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_2);
+ _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>);
+ StorageLive(_4);
+ _3 = copy _2 as *mut [T] (Transmute);
+ _4 = copy _2 as *const [T] (Transmute);
+ StorageLive(_6);
+ _5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable];
+ }
+
+ bb1: {
+ _6 = AlignOf(T);
+ StorageLive(_7);
+ _7 = copy _6 as std::ptr::Alignment (Transmute);
+ _8 = move (_7.0: std::ptr::alignment::AlignmentEnum);
+ StorageDead(_7);
+ StorageDead(_6);
+ StorageDead(_4);
+ switchInt(copy _5) -> [0: bb4, otherwise: bb2];
+ }
+
+ bb2: {
+ StorageLive(_9);
+ _9 = copy _3 as *mut u8 (PtrToPtr);
+ StorageLive(_11);
+ StorageLive(_10);
+ _10 = discriminant(_8);
+ _11 = move _10 as usize (IntToInt);
+ StorageDead(_10);
+ _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable];
+ }
+
+ bb3: {
+ StorageDead(_11);
+ StorageDead(_9);
+ goto -> bb4;
+ }
+
+ bb4: {
+ StorageDead(_2);
+ return;
+ }
+}
diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir
new file mode 100644
index 0000000..2be0a47
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir
@@ -0,0 +1,108 @@
+// MIR for `generic_in_place` after PreCodegen
+
+fn generic_in_place(_1: *mut Box<[T]>) -> () {
+ debug ptr => _1;
+ let mut _0: ();
+ scope 1 (inlined drop_in_place::<Box<[T]>> - shim(Some(Box<[T]>))) {
+ scope 2 (inlined <Box<[T]> as Drop>::drop) {
+ let _2: std::ptr::NonNull<[T]>;
+ let mut _3: *mut [T];
+ let mut _4: *const [T];
+ let _12: ();
+ scope 3 {
+ let _8: std::ptr::alignment::AlignmentEnum;
+ scope 4 {
+ scope 12 (inlined Layout::size) {
+ }
+ scope 13 (inlined Unique::<[T]>::cast::<u8>) {
+ scope 14 (inlined NonNull::<[T]>::cast::<u8>) {
+ scope 15 (inlined NonNull::<[T]>::as_ptr) {
+ }
+ }
+ }
+ scope 16 (inlined <NonNull<u8> as From<Unique<u8>>>::from) {
+ scope 17 (inlined Unique::<u8>::as_non_null_ptr) {
+ }
+ }
+ scope 18 (inlined <std::alloc::Global as Allocator>::deallocate) {
+ let mut _9: *mut u8;
+ scope 19 (inlined Layout::size) {
+ }
+ scope 20 (inlined NonNull::<u8>::as_ptr) {
+ }
+ scope 21 (inlined std::alloc::dealloc) {
+ let mut _11: usize;
+ scope 22 (inlined Layout::size) {
+ }
+ scope 23 (inlined Layout::align) {
+ scope 24 (inlined std::ptr::Alignment::as_usize) {
+ let mut _10: u64;
+ }
+ }
+ }
+ }
+ }
+ scope 5 (inlined Unique::<[T]>::as_ptr) {
+ scope 6 (inlined NonNull::<[T]>::as_ptr) {
+ }
+ }
+ scope 7 (inlined Layout::for_value_raw::<[T]>) {
+ let mut _5: usize;
+ let mut _6: usize;
+ scope 8 {
+ scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) {
+ let mut _7: std::ptr::Alignment;
+ }
+ }
+ scope 9 (inlined size_of_val_raw::<[T]>) {
+ }
+ scope 10 (inlined align_of_val_raw::<[T]>) {
+ }
+ }
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_2);
+ _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>);
+ StorageLive(_4);
+ _3 = copy _2 as *mut [T] (Transmute);
+ _4 = copy _2 as *const [T] (Transmute);
+ StorageLive(_6);
+ _5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable];
+ }
+
+ bb1: {
+ _6 = AlignOf(T);
+ StorageLive(_7);
+ _7 = copy _6 as std::ptr::Alignment (Transmute);
+ _8 = move (_7.0: std::ptr::alignment::AlignmentEnum);
+ StorageDead(_7);
+ StorageDead(_6);
+ StorageDead(_4);
+ switchInt(copy _5) -> [0: bb4, otherwise: bb2];
+ }
+
+ bb2: {
+ StorageLive(_9);
+ _9 = copy _3 as *mut u8 (PtrToPtr);
+ StorageLive(_11);
+ StorageLive(_10);
+ _10 = discriminant(_8);
+ _11 = move _10 as usize (IntToInt);
+ StorageDead(_10);
+ _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable];
+ }
+
+ bb3: {
+ StorageDead(_11);
+ StorageDead(_9);
+ goto -> bb4;
+ }
+
+ bb4: {
+ StorageDead(_2);
+ return;
+ }
+}
diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs
new file mode 100644
index 0000000..11fb7af
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -O -Zmir-opt-level=2
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
+#![crate_type = "lib"]
+
+// EMIT_MIR drop_boxed_slice.generic_in_place.PreCodegen.after.mir
+pub unsafe fn generic_in_place<T: Copy>(ptr: *mut Box<[T]>) {
+ // CHECK-LABEL: fn generic_in_place(_1: *mut Box<[T]>)
+ // CHECK: (inlined <Box<[T]> as Drop>::drop)
+ // CHECK: [[SIZE:_.+]] = std::intrinsics::size_of_val::<[T]>
+ // CHECK: [[ALIGN:_.+]] = AlignOf(T);
+ // CHECK: [[B:_.+]] = copy [[ALIGN]] as std::ptr::Alignment (Transmute);
+ // CHECK: [[C:_.+]] = move ([[B]].0: std::ptr::alignment::AlignmentEnum);
+ // CHECK: [[D:_.+]] = discriminant([[C]]);
+ // CHECK: [[E:_.+]] = move [[D]] as usize (IntToInt);
+ // CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[E]]) ->
+ std::ptr::drop_in_place(ptr)
+}
diff --git a/tests/mir-opt/pre-codegen/matches_macro.issue_77355_opt.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/matches_macro.issue_77355_opt.PreCodegen.after.mir
index d41135c..2d6f82f 100644
--- a/tests/mir-opt/pre-codegen/matches_macro.issue_77355_opt.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/matches_macro.issue_77355_opt.PreCodegen.after.mir
@@ -4,6 +4,8 @@
debug num => _1;
let mut _0: u64;
let mut _2: isize;
+ scope 1 {
+ }
bb0: {
_2 = discriminant(_1);
diff --git a/tests/pretty/asm.pp b/tests/pretty/asm.pp
index e6c9545..dca28f9 100644
--- a/tests/pretty/asm.pp
+++ b/tests/pretty/asm.pp
@@ -1,9 +1,9 @@
#![feature(prelude_import)]
#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ pretty-mode:expanded
//@ pp-exact:asm.pp
//@ only-x86_64
diff --git a/tests/pretty/cast-lt.pp b/tests/pretty/cast-lt.pp
index f6155c9..e82636e 100644
--- a/tests/pretty/cast-lt.pp
+++ b/tests/pretty/cast-lt.pp
@@ -1,9 +1,9 @@
#![feature(prelude_import)]
#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ pretty-compare-only
//@ pretty-mode:expanded
//@ pp-exact:cast-lt.pp
diff --git a/tests/pretty/dollar-crate.pp b/tests/pretty/dollar-crate.pp
index 561a950..31a55ec 100644
--- a/tests/pretty/dollar-crate.pp
+++ b/tests/pretty/dollar-crate.pp
@@ -1,9 +1,9 @@
#![feature(prelude_import)]
#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ pretty-compare-only
//@ pretty-mode:expanded
//@ pp-exact:dollar-crate.pp
diff --git a/tests/pretty/expanded-and-path-remap-80832.pp b/tests/pretty/expanded-and-path-remap-80832.pp
index 5b3922b..6206498 100644
--- a/tests/pretty/expanded-and-path-remap-80832.pp
+++ b/tests/pretty/expanded-and-path-remap-80832.pp
@@ -1,9 +1,9 @@
#![feature(prelude_import)]
#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
// Test for issue 80832
//
//@ pretty-mode:expanded
diff --git a/tests/pretty/format-args-str-escape.pp b/tests/pretty/format-args-str-escape.pp
index 277b608..d0bd7cf 100644
--- a/tests/pretty/format-args-str-escape.pp
+++ b/tests/pretty/format-args-str-escape.pp
@@ -1,9 +1,9 @@
#![feature(prelude_import)]
#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ pretty-compare-only
//@ pretty-mode:expanded
//@ pp-exact:format-args-str-escape.pp
diff --git a/tests/pretty/hir-delegation.pp b/tests/pretty/hir-delegation.pp
index c0d724c..f8ad02f 100644
--- a/tests/pretty/hir-delegation.pp
+++ b/tests/pretty/hir-delegation.pp
@@ -4,10 +4,10 @@
#![allow(incomplete_features)]
#![feature(fn_delegation)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
fn b<C>(e: C) { }
diff --git a/tests/pretty/hir-fn-params.pp b/tests/pretty/hir-fn-params.pp
index cfb33cc..fb4ea03 100644
--- a/tests/pretty/hir-fn-params.pp
+++ b/tests/pretty/hir-fn-params.pp
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ pretty-compare-only
//@ pretty-mode:hir
//@ pp-exact:hir-fn-params.pp
diff --git a/tests/pretty/hir-fn-variadic.pp b/tests/pretty/hir-fn-variadic.pp
index 99919e7..c0f5b70 100644
--- a/tests/pretty/hir-fn-variadic.pp
+++ b/tests/pretty/hir-fn-variadic.pp
@@ -3,10 +3,10 @@
//@ pp-exact:hir-fn-variadic.pp
#![feature(c_variadic)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
extern "C" {
unsafe fn foo(x: i32, va1: ...);
diff --git a/tests/pretty/hir-if-else.pp b/tests/pretty/hir-if-else.pp
index 4bccde6..af5d31b0 100644
--- a/tests/pretty/hir-if-else.pp
+++ b/tests/pretty/hir-if-else.pp
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ pretty-compare-only
//@ pretty-mode:hir
//@ pp-exact:hir-if-else.pp
diff --git a/tests/pretty/hir-lifetimes.pp b/tests/pretty/hir-lifetimes.pp
index 1bb2f17..00c052d 100644
--- a/tests/pretty/hir-lifetimes.pp
+++ b/tests/pretty/hir-lifetimes.pp
@@ -5,10 +5,10 @@
// This tests the pretty-printing of lifetimes in lots of ways.
#![allow(unused)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
struct Foo<'a> {
x: &'a u32,
diff --git a/tests/pretty/hir-pretty-attr.pp b/tests/pretty/hir-pretty-attr.pp
index c780f8e..01bfe2c 100644
--- a/tests/pretty/hir-pretty-attr.pp
+++ b/tests/pretty/hir-pretty-attr.pp
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ pretty-compare-only
//@ pretty-mode:hir
//@ pp-exact:hir-pretty-attr.pp
diff --git a/tests/pretty/hir-pretty-loop.pp b/tests/pretty/hir-pretty-loop.pp
index c071202..a0830c5 100644
--- a/tests/pretty/hir-pretty-loop.pp
+++ b/tests/pretty/hir-pretty-loop.pp
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ pretty-compare-only
//@ pretty-mode:hir
//@ pp-exact:hir-pretty-loop.pp
diff --git a/tests/pretty/hir-struct-expr.pp b/tests/pretty/hir-struct-expr.pp
index 177eb5e..bb222dc 100644
--- a/tests/pretty/hir-struct-expr.pp
+++ b/tests/pretty/hir-struct-expr.pp
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ pretty-compare-only
//@ pretty-mode:hir
//@ pp-exact:hir-struct-expr.pp
diff --git a/tests/pretty/if-else.pp b/tests/pretty/if-else.pp
index d4ff02c..f29b693 100644
--- a/tests/pretty/if-else.pp
+++ b/tests/pretty/if-else.pp
@@ -1,9 +1,9 @@
#![feature(prelude_import)]
#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ pretty-compare-only
//@ pretty-mode:expanded
//@ pp-exact:if-else.pp
diff --git a/tests/pretty/issue-12590-c.pp b/tests/pretty/issue-12590-c.pp
index 691738a..0df095b 100644
--- a/tests/pretty/issue-12590-c.pp
+++ b/tests/pretty/issue-12590-c.pp
@@ -1,9 +1,9 @@
#![feature(prelude_import)]
#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ pretty-compare-only
//@ pretty-mode:expanded
//@ pp-exact:issue-12590-c.pp
diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp
index f4b6413..1344923 100644
--- a/tests/pretty/issue-4264.pp
+++ b/tests/pretty/issue-4264.pp
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ pretty-compare-only
//@ pretty-mode:hir,typed
//@ pp-exact:issue-4264.pp
diff --git a/tests/pretty/issue-85089.pp b/tests/pretty/issue-85089.pp
index 31c0f90..28a85bd 100644
--- a/tests/pretty/issue-85089.pp
+++ b/tests/pretty/issue-85089.pp
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
// Test to print lifetimes on HIR pretty-printing.
//@ pretty-compare-only
diff --git a/tests/pretty/never-pattern.pp b/tests/pretty/never-pattern.pp
index 923ad9b..1ce332e 100644
--- a/tests/pretty/never-pattern.pp
+++ b/tests/pretty/never-pattern.pp
@@ -7,10 +7,10 @@
#![allow(incomplete_features)]
#![feature(never_patterns)]
#![feature(never_type)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
fn f(x: Result<u32, !>) { _ = match x { Ok(x) => x, Err(!) , }; }
diff --git a/tests/pretty/pin-ergonomics-hir.pp b/tests/pretty/pin-ergonomics-hir.pp
index 58a1c62..beca598 100644
--- a/tests/pretty/pin-ergonomics-hir.pp
+++ b/tests/pretty/pin-ergonomics-hir.pp
@@ -4,10 +4,10 @@
#![feature(pin_ergonomics)]
#![allow(dead_code, incomplete_features)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
use std::pin::Pin;
diff --git a/tests/pretty/postfix-match/precedence.pp b/tests/pretty/postfix-match/precedence.pp
index 2052b44..b6ff45d 100644
--- a/tests/pretty/postfix-match/precedence.pp
+++ b/tests/pretty/postfix-match/precedence.pp
@@ -1,10 +1,10 @@
#![feature(prelude_import)]
#![no_std]
#![feature(postfix_match)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
use std::ops::Add;
diff --git a/tests/pretty/shebang-at-top.pp b/tests/pretty/shebang-at-top.pp
index a279725..197def4 100644
--- a/tests/pretty/shebang-at-top.pp
+++ b/tests/pretty/shebang-at-top.pp
@@ -1,10 +1,10 @@
#!/usr/bin/env rust
#![feature(prelude_import)]
#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ pretty-mode:expanded
//@ pp-exact:shebang-at-top.pp
//@ pretty-compare-only
diff --git a/tests/pretty/tests-are-sorted.pp b/tests/pretty/tests-are-sorted.pp
index d6a2c0f..9e1566b 100644
--- a/tests/pretty/tests-are-sorted.pp
+++ b/tests/pretty/tests-are-sorted.pp
@@ -1,9 +1,9 @@
#![feature(prelude_import)]
#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ compile-flags: --crate-type=lib --test --remap-path-prefix={{src-base}}/=/the/src/ --remap-path-prefix={{src-base}}\=/the/src/
//@ pretty-compare-only
//@ pretty-mode:expanded
diff --git a/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr b/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr
index 7f13115..9433a0b 100644
--- a/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr
+++ b/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr
@@ -7,19 +7,19 @@
note: there are multiple different versions of crate `foo` in the dependency graph
--> foo-current.rs:7:1
|
-4 | extern crate foo;
+ 4 | extern crate foo;
| ----------------- one version of crate `foo` used here, as a direct dependency of the current crate
-5 |
-6 | pub struct Struct;
+ 5 |
+ 6 | pub struct Struct;
| ----------------- this type implements the required trait
-7 | pub trait Trait {}
+ 7 | pub trait Trait {}
| ^^^^^^^^^^^^^^^ this is the required trait
|
::: foo-prev.rs:X:Y
|
-4 | pub struct Struct;
+ 4 | pub struct Struct;
| ----------------- this type doesn't implement the required trait
-5 | pub trait Trait {}
+ 5 | pub trait Trait {}
| --------------- this is the found trait
= note: two types coming from two different versions of the same crate are different types even if they look the same
= help: you can use `cargo tree` to explore your dependency tree
diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs
index 57b68c6..9ea706a 100644
--- a/tests/run-make/linker-warning/rmake.rs
+++ b/tests/run-make/linker-warning/rmake.rs
@@ -64,7 +64,9 @@ fn main() {
.normalize(r#"/rustc[^/_-]*/"#, "/rustc/")
.normalize("libpanic_abort", "libpanic_unwind")
.normalize(
- regex::escape(run_make_support::build_root().to_str().unwrap()),
+ regex::escape(
+ run_make_support::build_root().canonicalize().unwrap().to_str().unwrap(),
+ ),
"/build-root",
)
.normalize(r#""[^"]*\/symbols.o""#, "\"/symbols.o\"")
diff --git a/tests/run-make/rustdoc-dep-info/after.md b/tests/run-make/rustdoc-dep-info/after.md
new file mode 100644
index 0000000..10d4b4c
--- /dev/null
+++ b/tests/run-make/rustdoc-dep-info/after.md
@@ -0,0 +1 @@
+meow! :3
diff --git a/tests/run-make/rustdoc-dep-info/before.html b/tests/run-make/rustdoc-dep-info/before.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/run-make/rustdoc-dep-info/before.html
diff --git a/tests/run-make/rustdoc-dep-info/extend.css b/tests/run-make/rustdoc-dep-info/extend.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/run-make/rustdoc-dep-info/extend.css
diff --git a/tests/run-make/rustdoc-dep-info/rmake.rs b/tests/run-make/rustdoc-dep-info/rmake.rs
index db7a00a..625f81f 100644
--- a/tests/run-make/rustdoc-dep-info/rmake.rs
+++ b/tests/run-make/rustdoc-dep-info/rmake.rs
@@ -9,13 +9,26 @@
fn main() {
// We're only emitting dep info, so we shouldn't be running static analysis to
// figure out that this program is erroneous.
- rustdoc().input("lib.rs").arg("-Zunstable-options").emit("dep-info").run();
+ // Ensure that all kinds of input reading flags end up in dep-info.
+ rustdoc()
+ .input("lib.rs")
+ .arg("-Zunstable-options")
+ .arg("--html-before-content=before.html")
+ .arg("--markdown-after-content=after.md")
+ .arg("--extend-css=extend.css")
+ .arg("--theme=theme.css")
+ .emit("dep-info")
+ .run();
let content = rfs::read_to_string("foo.d");
assert_contains(&content, "lib.rs:");
assert_contains(&content, "foo.rs:");
assert_contains(&content, "bar.rs:");
assert_contains(&content, "doc.md:");
+ assert_contains(&content, "after.md:");
+ assert_contains(&content, "before.html:");
+ assert_contains(&content, "extend.css:");
+ assert_contains(&content, "theme.css:");
// Now we check that we can provide a file name to the `dep-info` argument.
rustdoc().input("lib.rs").arg("-Zunstable-options").emit("dep-info=bla.d").run();
diff --git a/tests/run-make/rustdoc-dep-info/theme.css b/tests/run-make/rustdoc-dep-info/theme.css
new file mode 100644
index 0000000..459daff
--- /dev/null
+++ b/tests/run-make/rustdoc-dep-info/theme.css
@@ -0,0 +1 @@
+/* This is not a valid theme but that doesn't really matter */
diff --git a/tests/run-make/rustdoc-target-modifiers/c.rs b/tests/run-make/rustdoc-target-modifiers/c.rs
new file mode 100644
index 0000000..287d0bb
--- /dev/null
+++ b/tests/run-make/rustdoc-target-modifiers/c.rs
@@ -0,0 +1,7 @@
+#![allow(internal_features)]
+#![feature(lang_items, no_core)]
+#![no_core]
+
+fn f() {
+ d::f();
+}
diff --git a/tests/run-make/rustdoc-target-modifiers/d.rs b/tests/run-make/rustdoc-target-modifiers/d.rs
new file mode 100644
index 0000000..6cbff06
--- /dev/null
+++ b/tests/run-make/rustdoc-target-modifiers/d.rs
@@ -0,0 +1,12 @@
+#![allow(internal_features)]
+#![feature(lang_items, no_core)]
+#![no_core]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+
+pub fn f() {}
diff --git a/tests/run-make/rustdoc-target-modifiers/rmake.rs b/tests/run-make/rustdoc-target-modifiers/rmake.rs
new file mode 100644
index 0000000..ee52250
--- /dev/null
+++ b/tests/run-make/rustdoc-target-modifiers/rmake.rs
@@ -0,0 +1,28 @@
+//! Test that target modifiers are taken into account by `rustdoc`.
+//!
+//! Otherwise, `rustdoc` errors when trying to generate documentation
+//! using dependencies (e.g. `core`) that set a target modifier.
+//!
+//! Please see https://github.com/rust-lang/rust/issues/144521.
+
+use run_make_support::{rustc, rustdoc};
+
+fn main() {
+ rustc()
+ .input("d.rs")
+ .edition("2024")
+ .crate_type("rlib")
+ .emit("metadata")
+ .sysroot("/dev/null")
+ .target("aarch64-unknown-none-softfloat")
+ .arg("-Zfixed-x18")
+ .run();
+
+ rustdoc()
+ .input("c.rs")
+ .crate_type("rlib")
+ .extern_("d", "libd.rmeta")
+ .target("aarch64-unknown-none-softfloat")
+ .arg("-Zfixed-x18")
+ .run();
+}
diff --git a/tests/run-make/rustdoc-target-spec-json-path/target.json b/tests/run-make/rustdoc-target-spec-json-path/target.json
index c478f11..d7e4cac 100644
--- a/tests/run-make/rustdoc-target-spec-json-path/target.json
+++ b/tests/run-make/rustdoc-target-spec-json-path/target.json
@@ -6,7 +6,6 @@
"dynamic-linking": true,
"env": "gnu",
"executables": true,
- "has-elf-tls": true,
"has-rpath": true,
"linker-is-gnu": true,
"llvm-target": "x86_64-unknown-linux-gnu",
diff --git a/tests/run-make/target-specs/endianness-mismatch.json b/tests/run-make/target-specs/endianness-mismatch.json
index 431053e..cc03bec 100644
--- a/tests/run-make/target-specs/endianness-mismatch.json
+++ b/tests/run-make/target-specs/endianness-mismatch.json
@@ -5,7 +5,6 @@
"llvm-target": "x86_64-unknown-linux-gnu",
"target-endian": "big",
"target-pointer-width": "64",
- "target-c-int-width": "32",
"arch": "x86_64",
"os": "linux"
}
diff --git a/tests/run-make/target-specs/my-awesome-platform.json b/tests/run-make/target-specs/my-awesome-platform.json
index 1673ef7..d41038b 100644
--- a/tests/run-make/target-specs/my-awesome-platform.json
+++ b/tests/run-make/target-specs/my-awesome-platform.json
@@ -4,8 +4,6 @@
"llvm-target": "i686-unknown-linux-gnu",
"target-endian": "little",
"target-pointer-width": "32",
- "target-c-int-width": "32",
"arch": "x86",
- "os": "linux",
- "morestack": false
+ "os": "linux"
}
diff --git a/tests/run-make/target-specs/my-incomplete-platform.json b/tests/run-make/target-specs/my-incomplete-platform.json
index ceaa25c..8bdc410 100644
--- a/tests/run-make/target-specs/my-incomplete-platform.json
+++ b/tests/run-make/target-specs/my-incomplete-platform.json
@@ -3,8 +3,6 @@
"linker-flavor": "gcc",
"target-endian": "little",
"target-pointer-width": "32",
- "target-c-int-width": "32",
"arch": "x86",
- "os": "foo",
- "morestack": false
+ "os": "foo"
}
diff --git a/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json b/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json
index 0cafce1..27833f1 100644
--- a/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json
+++ b/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json
@@ -5,8 +5,6 @@
"llvm-target": "x86_64-unknown-linux-gnu",
"target-endian": "little",
"target-pointer-width": "64",
- "target-c-int-width": "32",
"arch": "x86_64",
- "os": "linux",
- "morestack": false
+ "os": "linux"
}
diff --git a/tests/run-make/target-specs/require-explicit-cpu.json b/tests/run-make/target-specs/require-explicit-cpu.json
index 5cbb957..9744bca 100644
--- a/tests/run-make/target-specs/require-explicit-cpu.json
+++ b/tests/run-make/target-specs/require-explicit-cpu.json
@@ -4,7 +4,6 @@
"llvm-target": "i686-unknown-linux-gnu",
"target-endian": "little",
"target-pointer-width": "32",
- "target-c-int-width": "32",
"arch": "x86",
"os": "linux",
"need-explicit-cpu": true
diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs
index 398f6bd..7c30a5b 100644
--- a/tests/run-make/target-specs/rmake.rs
+++ b/tests/run-make/target-specs/rmake.rs
@@ -9,8 +9,6 @@
use run_make_support::{diff, rfs, rustc};
fn main() {
- rustc().input("foo.rs").target("my-awesome-platform.json").crate_type("lib").emit("asm").run();
- assert!(!rfs::read_to_string("foo.s").contains("morestack"));
rustc()
.input("foo.rs")
.target("my-invalid-platform.json")
@@ -20,7 +18,7 @@ fn main() {
.input("foo.rs")
.target("my-incomplete-platform.json")
.run_fail()
- .assert_stderr_contains("Field llvm-target");
+ .assert_stderr_contains("missing field `llvm-target`");
rustc()
.env("RUST_TARGET_PATH", ".")
.input("foo.rs")
diff --git a/tests/run-make/uefi-qemu/rmake.rs b/tests/run-make/uefi-qemu/rmake.rs
new file mode 100644
index 0000000..55d42fb
--- /dev/null
+++ b/tests/run-make/uefi-qemu/rmake.rs
@@ -0,0 +1,84 @@
+//! This test builds and runs a basic UEFI application on QEMU for various targets.
+//!
+//! You must have the relevant OVMF or AAVMF firmware installed for this to work.
+//!
+//! Requires: qemu-system-x86_64, qemu-system-aarch64
+//! OVMF/AAVMF firmware
+//!
+//! Note: test assumes `/uefi_qemu_test` exists and is a self-contained crate.
+
+//@ only-uefi
+
+use std::path::Path;
+
+use run_make_support::{cargo, cmd, path, rfs};
+
+fn main() {
+ let target = run_make_support::target();
+
+ let (boot_filename, ovmf_dir, ovmf_code_name, ovmf_vars_name, qemu, machine, cpu) =
+ match target.as_str() {
+ "aarch64-unknown-uefi" => (
+ "bootaa64.efi",
+ Path::new("/usr/share/AAVMF"),
+ "AAVMF_CODE.fd",
+ "AAVMF_VARS.fd",
+ "qemu-system-aarch64",
+ "virt",
+ "cortex-a72",
+ ),
+ "i686-unknown-uefi" => (
+ "bootia32.efi",
+ Path::new("/usr/share/OVMF"),
+ "OVMF32_CODE_4M.secboot.fd",
+ "OVMF32_VARS_4M.fd",
+ "qemu-system-x86_64",
+ "q35",
+ "qemu64",
+ ),
+ "x86_64-unknown-uefi" => (
+ "bootx64.efi",
+ Path::new("/usr/share/OVMF"),
+ "OVMF_CODE_4M.fd",
+ "OVMF_VARS_4M.fd",
+ "qemu-system-x86_64",
+ "q35",
+ "qemu64",
+ ),
+ _ => panic!("unsupported target {target}"),
+ };
+
+ let tmp = std::env::temp_dir();
+ let test_crate = tmp.join("uefi_qemu_test");
+ rfs::copy_dir_all(path("uefi_qemu_test"), &test_crate);
+
+ cargo().args(&["build", "--target", &target]).current_dir(&test_crate).run();
+
+ // Prepare ESP
+ let esp = test_crate.join("esp");
+ let boot = esp.join("efi/boot");
+ rfs::create_dir_all(&boot);
+
+ let src_efi = test_crate.join("target").join(&target).join("debug/uefi_qemu_test.efi");
+ let dst_efi = boot.join(boot_filename);
+ rfs::copy(&src_efi, &dst_efi);
+
+ // Copy OVMF files
+ let code = ovmf_dir.join(ovmf_code_name);
+ let vars_src = ovmf_dir.join(ovmf_vars_name);
+ let vars_dst = tmp.join("vars.fd");
+ rfs::copy(&vars_src, &vars_dst);
+
+ let output = cmd(qemu)
+ .args(["-machine", machine])
+ .args(["-cpu", cpu])
+ .args(["-display", "none"])
+ .args(["-serial", "stdio"])
+ .args(["-drive", &format!("if=pflash,format=raw,readonly=on,file={}", code.display())])
+ .args(["-drive", &format!("if=pflash,format=raw,readonly=off,file={}", vars_dst.display())])
+ .args(["-drive", &format!("format=raw,file=fat:rw:{}", esp.display())])
+ .run()
+ .stdout_utf8();
+
+ assert!(output.contains("Hello World!"), "invalid output for {target}:\n{output}");
+}
diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock b/tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.lock
similarity index 100%
rename from src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock
rename to tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.lock
diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml b/tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.toml
similarity index 100%
rename from src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml
rename to tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.toml
diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs b/tests/run-make/uefi-qemu/uefi_qemu_test/src/main.rs
similarity index 67%
rename from src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs
rename to tests/run-make/uefi-qemu/uefi_qemu_test/src/main.rs
index 89e4393..f8e1212 100644
--- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs
+++ b/tests/run-make/uefi-qemu/uefi_qemu_test/src/main.rs
@@ -15,14 +15,7 @@ fn panic_handler(_info: &panic::PanicInfo) -> ! {
#[export_name = "efi_main"]
pub extern "C" fn main(_h: Handle, st: *mut SystemTable) -> Status {
- let s = [
- 0x0048u16, 0x0065u16, 0x006cu16, 0x006cu16, 0x006fu16, // "Hello"
- 0x0020u16, // " "
- 0x0057u16, 0x006fu16, 0x0072u16, 0x006cu16, 0x0064u16, // "World"
- 0x0021u16, // "!"
- 0x000au16, // "\n"
- 0x0000u16, // NUL
- ];
+ let s = b"Hello World!\n\0".map(|c| u16::from(c));
// Print "Hello World!".
let r = unsafe { ((*(*st).con_out).output_string)((*st).con_out, s.as_ptr() as *mut Char16) };
diff --git a/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr
index bfc1e91..ce65557 100644
--- a/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr
+++ b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr
@@ -15,7 +15,7 @@
note: the lint level is defined here
--> $DIR/standalone-warning-2024.rs:9:9
|
-9 | #![deny(warnings)]
+ 9 | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(warnings)]`
diff --git a/tests/ui/SUMMARY.md b/tests/ui/README.md
similarity index 99%
rename from tests/ui/SUMMARY.md
rename to tests/ui/README.md
index b635b63..66c1bb9 100644
--- a/tests/ui/SUMMARY.md
+++ b/tests/ui/README.md
@@ -412,6 +412,10 @@
Exercises `#[diagnostic::*]` namespaced attributes. See [RFC 3368 Diagnostic attribute namespace](https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md).
+## `tests/ui/diagnostics-infra`
+
+This directory contains tests and infrastructure related to the diagnostics system, including support for translatable diagnostics
+
## `tests/ui/diagnostic-width/`: `--diagnostic-width`
Everything to do with `--diagnostic-width`.
@@ -650,10 +654,6 @@
Tests for the standard library collection [`std::collections::HashMap`](https://doc.rust-lang.org/std/collections/struct.HashMap.html).
-## `tests/ui/hello_world/`
-
-Tests that the basic hello-world program is not somehow broken.
-
## `tests/ui/higher-ranked/`
Tests for higher-ranked trait bounds.
@@ -1233,6 +1233,10 @@
Tests with erroneous ways of using `self`, such as using `this.x` syntax as seen in other languages, having it not be the first argument, or using it in a non-associated function (no `impl` or `trait`). It also contains correct uses of `self` which have previously been observed to cause ICEs.
+## `tests/ui/self-profile/`: self-profiling
+
+Tests related to the self-profiler (`-Zself-profile`) functionality of rustc.
+
## `tests/ui/sepcomp/`: Separate Compilation
In this directory, multiple crates are compiled, but some of them have `inline` functions, meaning they must be inlined into a different crate despite having been compiled separately.
diff --git a/tests/ui/allocator/no_std-alloc-error-handler-custom.rs b/tests/ui/allocator/no_std-alloc-error-handler-custom.rs
index 1b0f060..7b7ca2f 100644
--- a/tests/ui/allocator/no_std-alloc-error-handler-custom.rs
+++ b/tests/ui/allocator/no_std-alloc-error-handler-custom.rs
@@ -2,6 +2,7 @@
//@ ignore-android no libc
//@ ignore-emscripten no libc
//@ ignore-sgx no libc
+//@ ignore-backends: gcc
//@ only-linux
//@ compile-flags:-C panic=abort
//@ aux-build:helper.rs
diff --git a/tests/ui/allocator/no_std-alloc-error-handler-default.rs b/tests/ui/allocator/no_std-alloc-error-handler-default.rs
index 51ecf1a..5a6c0b3 100644
--- a/tests/ui/allocator/no_std-alloc-error-handler-default.rs
+++ b/tests/ui/allocator/no_std-alloc-error-handler-default.rs
@@ -2,6 +2,7 @@
//@ ignore-android no libc
//@ ignore-emscripten no libc
//@ ignore-sgx no libc
+//@ ignore-backends: gcc
//@ only-linux
//@ compile-flags:-C panic=abort
//@ aux-build:helper.rs
diff --git a/tests/ui/asm/may_unwind.rs b/tests/ui/asm/may_unwind.rs
index 1d4f50d..0fef317 100644
--- a/tests/ui/asm/may_unwind.rs
+++ b/tests/ui/asm/may_unwind.rs
@@ -1,6 +1,7 @@
//@ run-pass
//@ needs-asm-support
//@ needs-unwind
+//@ ignore-backends: gcc
#![feature(asm_unwind)]
diff --git a/tests/ui/asm/named-asm-labels.rs b/tests/ui/asm/named-asm-labels.rs
index 996fb82..e78553f 100644
--- a/tests/ui/asm/named-asm-labels.rs
+++ b/tests/ui/asm/named-asm-labels.rs
@@ -171,12 +171,10 @@ fn main() {
}
}
-// Trigger on naked fns too, even though they can't be inlined, reusing a
-// label or LTO can cause labels to break
+// Don't trigger on naked functions.
#[unsafe(naked)]
pub extern "C" fn foo() -> i32 {
naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1)
- //~^ ERROR avoid using named labels
}
// Make sure that non-naked attributes *do* still let the lint happen
@@ -190,7 +188,18 @@ pub extern "C" fn bar() {
pub extern "C" fn aaa() {
fn _local() {}
- naked_asm!(".Laaa: nop; ret;") //~ ERROR avoid using named labels
+ naked_asm!(".Laaa: nop; ret;")
+}
+
+#[unsafe(naked)]
+pub extern "C" fn bbb<'a>(a: &'a u32) {
+ naked_asm!(".Lbbb: nop; ret;")
+}
+
+#[unsafe(naked)]
+pub extern "C" fn ccc<T>(a: &T) {
+ naked_asm!(".Lccc: nop; ret;")
+ //~^ ERROR avoid using named labels
}
pub fn normal() {
@@ -200,7 +209,7 @@ fn _local1() {}
pub extern "C" fn bbb() {
fn _very_local() {}
- naked_asm!(".Lbbb: nop; ret;") //~ ERROR avoid using named labels
+ naked_asm!(".Lbbb: nop; ret;")
}
fn _local2() {}
@@ -230,3 +239,10 @@ extern "C" fn _nested() {
// Don't trigger on global asm
global_asm!("aaaaaaaa: nop");
+
+trait Foo {
+ #[unsafe(naked)]
+ extern "C" fn bbb<'a>(a: &'a u32) {
+ naked_asm!(".Lbbb: nop; ret;") //~ ERROR avoid using named labels
+ }
+}
diff --git a/tests/ui/asm/named-asm-labels.stderr b/tests/ui/asm/named-asm-labels.stderr
index cd7e7a0..9ba9e14 100644
--- a/tests/ui/asm/named-asm-labels.stderr
+++ b/tests/ui/asm/named-asm-labels.stderr
@@ -475,16 +475,7 @@
| ^^^^^^^^^^^^^^^^
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:178:17
- |
-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:185:20
+ --> $DIR/named-asm-labels.rs:183:20
|
LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noreturn)) }
| ^^^^^
@@ -493,25 +484,16 @@
= 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:193:17
+ --> $DIR/named-asm-labels.rs:201:17
|
-LL | naked_asm!(".Laaa: nop; ret;")
+LL | naked_asm!(".Lccc: 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:203:21
- |
-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:212:15
+ --> $DIR/named-asm-labels.rs:221:15
|
LL | asm!("closure1: nop");
| ^^^^^^^^
@@ -520,7 +502,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:216:15
+ --> $DIR/named-asm-labels.rs:225:15
|
LL | asm!("closure2: nop");
| ^^^^^^^^
@@ -529,7 +511,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:226:19
+ --> $DIR/named-asm-labels.rs:235:19
|
LL | asm!("closure3: nop");
| ^^^^^^^^
@@ -537,5 +519,14 @@
= 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: aborting due to 56 previous errors; 1 warning emitted
+error: avoid using named labels in inline assembly
+ --> $DIR/named-asm-labels.rs:246:21
+ |
+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: aborting due to 55 previous errors; 1 warning emitted
diff --git a/tests/ui/asm/unpretty-expanded.stdout b/tests/ui/asm/unpretty-expanded.stdout
index 7ba1702..7678f6b 100644
--- a/tests/ui/asm/unpretty-expanded.stdout
+++ b/tests/ui/asm/unpretty-expanded.stdout
@@ -1,9 +1,9 @@
#![feature(prelude_import)]
#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ needs-asm-support
//@ check-pass
//@ compile-flags: -Zunpretty=expanded
diff --git a/tests/ui/asm/x86_64/may_unwind.rs b/tests/ui/asm/x86_64/may_unwind.rs
index d3a2916..9657f49 100644
--- a/tests/ui/asm/x86_64/may_unwind.rs
+++ b/tests/ui/asm/x86_64/may_unwind.rs
@@ -2,6 +2,7 @@
//@ run-pass
//@ needs-asm-support
//@ needs-unwind
+//@ ignore-backends: gcc
#![feature(asm_unwind)]
diff --git a/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stdout b/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stdout
index 8766755..7499df5 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stdout
+++ b/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stdout
@@ -1,8 +1,8 @@
#![feature(prelude_import)]
-#[prelude_import]
-use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use std::prelude::rust_2021::*;
//@ edition: 2021
//@ compile-flags: -Zunpretty=expanded
//@ check-pass
diff --git a/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.rs b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.rs
index c8bb0eb..49e46f4 100644
--- a/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.rs
+++ b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.rs
@@ -1,4 +1,4 @@
-// Regression test for issue #105056.
+// issue: <https://github.com/rust-lang/rust/issues/105056>
//@ edition: 2021
fn f(_: impl Trait<T = Copy>) {}
@@ -23,4 +23,11 @@ fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {}
trait Trait { type T; }
+// Don't suggest assoc ty bounds when we have parenthesized args (the underlying assoc type
+// binding `Output` isn't introduced by `=` but by `->`, suggesting `:` wouldn't be valid).
+// issue: <https://github.com/rust-lang/rust/issues/140543>
+fn i(_: impl Fn() -> std::fmt::Debug) {}
+//~^ ERROR expected a type, found a trait
+//~| HELP you can add the `dyn` keyword if you want a trait object
+
fn main() {}
diff --git a/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr
index 6eb8fab..ea9f25f 100644
--- a/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr
+++ b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr
@@ -57,6 +57,17 @@
LL | type Obj = dyn Trait<T = dyn Clone>;
| +++
-error: aborting due to 4 previous errors
+error[E0782]: expected a type, found a trait
+ --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:29:22
+ |
+LL | fn i(_: impl Fn() -> std::fmt::Debug) {}
+ | ^^^^^^^^^^^^^^^
+ |
+help: you can add the `dyn` keyword if you want a trait object
+ |
+LL | fn i(_: impl Fn() -> dyn std::fmt::Debug) {}
+ | +++
+
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0782`.
diff --git a/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr
index 03fa220..3fe1431 100644
--- a/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr
+++ b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr
@@ -1,14 +1,13 @@
error[E0507]: cannot move out of `x` which is behind a mutable reference
--> $DIR/closure-shim-borrowck-error.rs:11:18
|
+LL | fn hello(x: Ty) {
+ | -- move occurs because `x` has type `Ty`, which does not implement the `Copy` trait
LL | needs_fn_mut(async || {
| ^^^^^^^^ `x` is moved here
LL |
LL | x.hello();
- | -
- | |
- | variable moved due to use in coroutine
- | move occurs because `x` has type `Ty`, which does not implement the `Copy` trait
+ | - variable moved due to use in coroutine
|
note: if `Ty` implemented `Clone`, you could clone the value
--> $DIR/closure-shim-borrowck-error.rs:17:1
diff --git a/tests/ui/async-await/async-closures/move-out-of-ref.stderr b/tests/ui/async-await/async-closures/move-out-of-ref.stderr
index 8a63515..d443dc9 100644
--- a/tests/ui/async-await/async-closures/move-out-of-ref.stderr
+++ b/tests/ui/async-await/async-closures/move-out-of-ref.stderr
@@ -1,8 +1,11 @@
error[E0507]: cannot move out of `*x` which is behind a shared reference
--> $DIR/move-out-of-ref.rs:9:9
|
+LL | fn hello(x: &Ty) {
+ | --- move occurs because `*x` has type `Ty`, which does not implement the `Copy` trait
+LL | let c = async || {
LL | *x;
- | ^^ move occurs because `*x` has type `Ty`, which does not implement the `Copy` trait
+ | ^^ `*x` is moved here
|
note: if `Ty` implemented `Clone`, you could clone the value
--> $DIR/move-out-of-ref.rs:5:1
diff --git a/tests/ui/async-await/deep-futures-are-freeze.rs b/tests/ui/async-await/deep-futures-are-freeze.rs
index c430016..79dbc03 100644
--- a/tests/ui/async-await/deep-futures-are-freeze.rs
+++ b/tests/ui/async-await/deep-futures-are-freeze.rs
@@ -1,3 +1,4 @@
+//@ ignore-backends: gcc
//@ build-pass
//@ compile-flags: -Copt-level=s -Clto=fat
//@ no-prefer-dynamic
diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs
index 4bafb39..d6180bb 100644
--- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs
+++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs
@@ -1,3 +1,4 @@
+//@ ignore-backends: gcc
//@ edition: 2021
//@ known-bug: #108309
diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr
index 62cca41..3d82f57 100644
--- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr
+++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr
@@ -1,11 +1,11 @@
error[E0053]: method `foo` has an incompatible type for trait
- --> $DIR/dont-project-to-specializable-projection.rs:13:5
+ --> $DIR/dont-project-to-specializable-projection.rs:14:5
|
LL | default async fn foo(_: T) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found future
|
note: type in trait
- --> $DIR/dont-project-to-specializable-projection.rs:9:5
+ --> $DIR/dont-project-to-specializable-projection.rs:10:5
|
LL | async fn foo(_: T) -> &'static str;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@
found signature `fn(_) -> impl Future<Output = &'static str>`
error: async associated function in trait cannot be specialized
- --> $DIR/dont-project-to-specializable-projection.rs:13:5
+ --> $DIR/dont-project-to-specializable-projection.rs:14:5
|
LL | default async fn foo(_: T) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -21,7 +21,7 @@
= note: specialization behaves in inconsistent and surprising ways with async functions in traits, and for now is disallowed
error[E0599]: no method named `poll` found for struct `Pin<&mut impl Future<Output = ()>>` in the current scope
- --> $DIR/dont-project-to-specializable-projection.rs:48:28
+ --> $DIR/dont-project-to-specializable-projection.rs:49:28
|
LL | match fut.as_mut().poll(ctx) {
| ^^^^ method not found in `Pin<&mut impl Future<Output = ()>>`
diff --git a/tests/ui/async-await/issue-64130-non-send-future-diags.stderr b/tests/ui/async-await/issue-64130-non-send-future-diags.stderr
index d28807e..beaf8e9 100644
--- a/tests/ui/async-await/issue-64130-non-send-future-diags.stderr
+++ b/tests/ui/async-await/issue-64130-non-send-future-diags.stderr
@@ -4,12 +4,12 @@
LL | is_send(foo());
| ^^^^^ future returned by `foo` is not `Send`
|
- = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`
+ = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, u32>`
note: future is not `Send` as this value is used across an await
--> $DIR/issue-64130-non-send-future-diags.rs:17:11
|
LL | let g = x.lock().unwrap();
- | - has type `MutexGuard<'_, u32>` which is not `Send`
+ | - has type `std::sync::MutexGuard<'_, u32>` which is not `Send`
LL | baz().await;
| ^^^^^ await occurs here, with `g` maybe used later
note: required by a bound in `is_send`
diff --git a/tests/ui/async-await/issue-71137.stderr b/tests/ui/async-await/issue-71137.stderr
index 8739c22..d567e3f 100644
--- a/tests/ui/async-await/issue-71137.stderr
+++ b/tests/ui/async-await/issue-71137.stderr
@@ -4,12 +4,12 @@
LL | fake_spawn(wrong_mutex());
| ^^^^^^^^^^^^^ future returned by `wrong_mutex` is not `Send`
|
- = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`
+ = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, i32>`
note: future is not `Send` as this value is used across an await
--> $DIR/issue-71137.rs:14:26
|
LL | let mut guard = m.lock().unwrap();
- | --------- has type `MutexGuard<'_, i32>` which is not `Send`
+ | --------- has type `std::sync::MutexGuard<'_, i32>` which is not `Send`
LL | (async { "right"; }).await;
| ^^^^^ await occurs here, with `mut guard` maybe used later
note: required by a bound in `fake_spawn`
diff --git a/tests/ui/async-await/issues/issue-67893.rs b/tests/ui/async-await/issues/issue-67893.rs
index 73cce38..2020abe 100644
--- a/tests/ui/async-await/issues/issue-67893.rs
+++ b/tests/ui/async-await/issues/issue-67893.rs
@@ -7,5 +7,5 @@ fn g(_: impl Send) {}
fn main() {
g(issue_67893::run())
- //~^ ERROR `MutexGuard<'_, ()>` cannot be sent between threads safely
+ //~^ ERROR `std::sync::MutexGuard<'_, ()>` cannot be sent between threads safely
}
diff --git a/tests/ui/async-await/issues/issue-67893.stderr b/tests/ui/async-await/issues/issue-67893.stderr
index c012372..34f28dd 100644
--- a/tests/ui/async-await/issues/issue-67893.stderr
+++ b/tests/ui/async-await/issues/issue-67893.stderr
@@ -1,8 +1,8 @@
-error[E0277]: `MutexGuard<'_, ()>` cannot be sent between threads safely
+error[E0277]: `std::sync::MutexGuard<'_, ()>` cannot be sent between threads safely
--> $DIR/issue-67893.rs:9:7
|
LL | g(issue_67893::run())
- | - ^^^^^^^^^^^^^^^^^^ `MutexGuard<'_, ()>` cannot be sent between threads safely
+ | - ^^^^^^^^^^^^^^^^^^ `std::sync::MutexGuard<'_, ()>` cannot be sent between threads safely
| |
| required by a bound introduced by this call
|
@@ -11,7 +11,7 @@
LL | pub async fn run() {
| ------------------ within this `impl Future<Output = ()>`
|
- = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
+ = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, ()>`
note: required because it's used within this `async` fn body
--> $DIR/auxiliary/issue_67893.rs:9:20
|
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index 7ae24db..814a1e5 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -43,12 +43,6 @@
LL | #[no_sanitize]
| ^^^^^^^^^^^^^^ help: must be of the form: `#[no_sanitize(address, kcfi, memory, thread)]`
-error: malformed `proc_macro` attribute input
- --> $DIR/malformed-attrs.rs:100:1
- |
-LL | #[proc_macro = 18]
- | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]`
-
error: malformed `instruction_set` attribute input
--> $DIR/malformed-attrs.rs:107:1
|
@@ -67,18 +61,6 @@
LL | #[coroutine = 63] || {}
| ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[coroutine]`
-error: malformed `proc_macro_attribute` attribute input
- --> $DIR/malformed-attrs.rs:117:1
- |
-LL | #[proc_macro_attribute = 19]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]`
-
-error: malformed `proc_macro_derive` attribute input
- --> $DIR/malformed-attrs.rs:124:1
- |
-LL | #[proc_macro_derive]
- | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-
error: malformed `must_not_suspend` attribute input
--> $DIR/malformed-attrs.rs:133:1
|
@@ -454,6 +436,24 @@
| | didn't expect any arguments here
| help: must be of the form: `#[no_implicit_prelude]`
+error[E0565]: malformed `proc_macro` attribute input
+ --> $DIR/malformed-attrs.rs:100:1
+ |
+LL | #[proc_macro = 18]
+ | ^^^^^^^^^^^^^----^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro]`
+
+error[E0565]: malformed `proc_macro_attribute` attribute input
+ --> $DIR/malformed-attrs.rs:117:1
+ |
+LL | #[proc_macro_attribute = 19]
+ | ^^^^^^^^^^^^^^^^^^^^^^^----^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro_attribute]`
+
error[E0539]: malformed `must_use` attribute input
--> $DIR/malformed-attrs.rs:120:1
|
@@ -471,6 +471,15 @@
LL + #[must_use]
|
+error[E0539]: malformed `proc_macro_derive` attribute input
+ --> $DIR/malformed-attrs.rs:124:1
+ |
+LL | #[proc_macro_derive]
+ | ^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected this to be a list
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+
error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input
--> $DIR/malformed-attrs.rs:129:1
|
diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
index 2f17d96..bd136e6 100644
--- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
@@ -12,6 +12,7 @@ pub fn b() {}
#[proc_macro_derive(unsafe(Foo))]
//~^ ERROR attribute is only usable with crates of the `proc-macro` crate type
//~| ERROR: expected identifier, found keyword `unsafe`
+//~| ERROR malformed `proc_macro_derive` attribute input
pub fn c() {}
#[unsafe(proc_macro_attribute)]
diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
index 25b83a2..884e766 100644
--- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
+++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
@@ -1,11 +1,11 @@
error[E0452]: malformed lint attribute input
- --> $DIR/proc-unsafe-attributes.rs:26:16
+ --> $DIR/proc-unsafe-attributes.rs:27:16
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/proc-unsafe-attributes.rs:26:16
+ --> $DIR/proc-unsafe-attributes.rs:27:16
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^^^^^^^^^^^^ bad attribute argument
@@ -40,7 +40,7 @@
| ++
error: `proc_macro_attribute` is not an unsafe attribute
- --> $DIR/proc-unsafe-attributes.rs:17:3
+ --> $DIR/proc-unsafe-attributes.rs:18:3
|
LL | #[unsafe(proc_macro_attribute)]
| ^^^^^^ this is not an unsafe attribute
@@ -48,7 +48,7 @@
= note: extraneous unsafe is not allowed in attributes
error: `allow` is not an unsafe attribute
- --> $DIR/proc-unsafe-attributes.rs:22:3
+ --> $DIR/proc-unsafe-attributes.rs:23:3
|
LL | #[unsafe(allow(dead_code))]
| ^^^^^^ this is not an unsafe attribute
@@ -56,7 +56,7 @@
= note: extraneous unsafe is not allowed in attributes
error: `allow` is not an unsafe attribute
- --> $DIR/proc-unsafe-attributes.rs:26:3
+ --> $DIR/proc-unsafe-attributes.rs:27:3
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^ this is not an unsafe attribute
@@ -64,7 +64,7 @@
= note: extraneous unsafe is not allowed in attributes
error: expected identifier, found keyword `unsafe`
- --> $DIR/proc-unsafe-attributes.rs:26:16
+ --> $DIR/proc-unsafe-attributes.rs:27:16
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^ expected identifier, found keyword
@@ -93,13 +93,13 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type
- --> $DIR/proc-unsafe-attributes.rs:17:1
+ --> $DIR/proc-unsafe-attributes.rs:18:1
|
LL | #[unsafe(proc_macro_attribute)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0452]: malformed lint attribute input
- --> $DIR/proc-unsafe-attributes.rs:26:16
+ --> $DIR/proc-unsafe-attributes.rs:27:16
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^^^^^^^^^^^^ bad attribute argument
@@ -107,7 +107,24 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0452]: malformed lint attribute input
- --> $DIR/proc-unsafe-attributes.rs:26:16
+ --> $DIR/proc-unsafe-attributes.rs:27:16
+ |
+LL | #[unsafe(allow(unsafe(dead_code)))]
+ | ^^^^^^^^^^^^^^^^^ bad attribute argument
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0565]: malformed `proc_macro_derive` attribute input
+ --> $DIR/proc-unsafe-attributes.rs:12:1
+ |
+LL | #[proc_macro_derive(unsafe(Foo))]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^-----^^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+
+error[E0452]: malformed lint attribute input
+ --> $DIR/proc-unsafe-attributes.rs:27:16
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^^^^^^^^^^^^ bad attribute argument
@@ -115,21 +132,14 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0452]: malformed lint attribute input
- --> $DIR/proc-unsafe-attributes.rs:26:16
+ --> $DIR/proc-unsafe-attributes.rs:27:16
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^^^^^^^^^^^^ bad attribute argument
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error[E0452]: malformed lint attribute input
- --> $DIR/proc-unsafe-attributes.rs:26:16
- |
-LL | #[unsafe(allow(unsafe(dead_code)))]
- | ^^^^^^^^^^^^^^^^^ bad attribute argument
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+error: aborting due to 18 previous errors
-error: aborting due to 17 previous errors
-
-For more information about this error, try `rustc --explain E0452`.
+Some errors have detailed explanations: E0452, E0565.
+For more information about an error, try `rustc --explain E0452`.
diff --git a/tests/ui/backtrace/dylib-dep.rs b/tests/ui/backtrace/dylib-dep.rs
index a41931a..05fdb9a 100644
--- a/tests/ui/backtrace/dylib-dep.rs
+++ b/tests/ui/backtrace/dylib-dep.rs
@@ -8,6 +8,7 @@
//@ ignore-fuchsia Backtraces not symbolized
//@ ignore-musl musl doesn't support dynamic libraries (at least when the original test was written).
//@ needs-unwind
+//@ ignore-backends: gcc
//@ compile-flags: -g -Copt-level=0 -Cstrip=none -Cforce-frame-pointers=yes
//@ ignore-emscripten Requires custom symbolization code
//@ aux-crate: dylib_dep_helper=dylib-dep-helper.rs
diff --git a/tests/ui/backtrace/std-backtrace.rs b/tests/ui/backtrace/std-backtrace.rs
index 7ccbd46..b81bdee 100644
--- a/tests/ui/backtrace/std-backtrace.rs
+++ b/tests/ui/backtrace/std-backtrace.rs
@@ -13,9 +13,9 @@
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() >= 2 && args[1] == "force" {
- println!("stack backtrace:\n{}", std::backtrace::Backtrace::force_capture());
+ println!("{}", std::backtrace::Backtrace::force_capture());
} else if args.len() >= 2 {
- println!("stack backtrace:\n{}", std::backtrace::Backtrace::capture());
+ println!("{}", std::backtrace::Backtrace::capture());
} else {
runtest(&args[0]);
println!("test ok");
@@ -28,7 +28,6 @@ fn runtest(me: &str) {
let p = Command::new(me).arg("a").env("RUST_BACKTRACE", "1").output().unwrap();
assert!(p.status.success());
- assert!(String::from_utf8_lossy(&p.stdout).contains("stack backtrace:\n"));
assert!(String::from_utf8_lossy(&p.stdout).contains("backtrace::main"));
let p = Command::new(me).arg("a").env("RUST_BACKTRACE", "0").output().unwrap();
@@ -46,7 +45,6 @@ fn runtest(me: &str) {
.output()
.unwrap();
assert!(p.status.success());
- assert!(String::from_utf8_lossy(&p.stdout).contains("stack backtrace:\n"));
let p = Command::new(me)
.arg("a")
@@ -64,9 +62,7 @@ fn runtest(me: &str) {
.output()
.unwrap();
assert!(p.status.success());
- assert!(String::from_utf8_lossy(&p.stdout).contains("stack backtrace:\n"));
let p = Command::new(me).arg("force").output().unwrap();
assert!(p.status.success());
- assert!(String::from_utf8_lossy(&p.stdout).contains("stack backtrace:\n"));
}
diff --git a/tests/ui/borrowck/borrowck-in-static.stderr b/tests/ui/borrowck/borrowck-in-static.stderr
index 745b02a..9bcf64d 100644
--- a/tests/ui/borrowck/borrowck-in-static.stderr
+++ b/tests/ui/borrowck/borrowck-in-static.stderr
@@ -2,9 +2,11 @@
--> $DIR/borrowck-in-static.rs:5:17
|
LL | let x = Box::new(0);
- | - captured outer variable
+ | - ----------- move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+ | |
+ | captured outer variable
LL | Box::new(|| x)
- | -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+ | -- ^ `x` is moved here
| |
| captured by this `Fn` closure
|
diff --git a/tests/ui/borrowck/borrowck-move-by-capture.stderr b/tests/ui/borrowck/borrowck-move-by-capture.stderr
index 58d5e90..732af15 100644
--- a/tests/ui/borrowck/borrowck-move-by-capture.stderr
+++ b/tests/ui/borrowck/borrowck-move-by-capture.stderr
@@ -2,14 +2,14 @@
--> $DIR/borrowck-move-by-capture.rs:9:29
|
LL | let bar: Box<_> = Box::new(3);
- | --- captured outer variable
+ | --- ------ move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
+ | |
+ | captured outer variable
LL | let _g = to_fn_mut(|| {
| -- captured by this `FnMut` closure
LL | let _h = to_fn_once(move || -> isize { *bar });
- | ^^^^^^^^^^^^^^^^ ----
- | | |
- | | variable moved due to use in closure
- | | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
+ | ^^^^^^^^^^^^^^^^ ---- variable moved due to use in closure
+ | |
| `bar` is moved here
|
help: consider cloning the value before moving it into the closure
diff --git a/tests/ui/borrowck/borrowck-partial-reinit-1.stderr b/tests/ui/borrowck/borrowck-partial-reinit-1.stderr
index 65f2bd6..d261f3a 100644
--- a/tests/ui/borrowck/borrowck-partial-reinit-1.stderr
+++ b/tests/ui/borrowck/borrowck-partial-reinit-1.stderr
@@ -8,6 +8,15 @@
| - value moved here
LL | t.b = Some(u);
| ^^^ value assigned here after move
+ |
+note: if `Test2` implemented `Clone`, you could clone the value
+ --> $DIR/borrowck-partial-reinit-1.rs:3:1
+ |
+LL | struct Test2 {
+ | ^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | drop(t);
+ | - you could clone this value
error[E0382]: assign of moved value: `t`
--> $DIR/borrowck-partial-reinit-1.rs:33:5
@@ -19,6 +28,15 @@
| - value moved here
LL | t.0 = Some(u);
| ^^^ value assigned here after move
+ |
+note: if `Test3` implemented `Clone`, you could clone the value
+ --> $DIR/borrowck-partial-reinit-1.rs:7:1
+ |
+LL | struct Test3(Option<Test>);
+ | ^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | drop(t);
+ | - you could clone this value
error: aborting due to 2 previous errors
diff --git a/tests/ui/borrowck/borrowck-partial-reinit-2.stderr b/tests/ui/borrowck/borrowck-partial-reinit-2.stderr
index e25ca08..dde70eb 100644
--- a/tests/ui/borrowck/borrowck-partial-reinit-2.stderr
+++ b/tests/ui/borrowck/borrowck-partial-reinit-2.stderr
@@ -7,6 +7,15 @@
| - value moved here
LL | t.b = Some(Box::new(u));
| ^^^ value assigned here after move
+ |
+note: if `Test` implemented `Clone`, you could clone the value
+ --> $DIR/borrowck-partial-reinit-2.rs:1:1
+ |
+LL | struct Test {
+ | ^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let mut u = Test { a: 2, b: Some(Box::new(t))};
+ | - you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/borrowck/borrowck-union-move-assign.stderr b/tests/ui/borrowck/borrowck-union-move-assign.stderr
index 8c0239a..8721481 100644
--- a/tests/ui/borrowck/borrowck-union-move-assign.stderr
+++ b/tests/ui/borrowck/borrowck-union-move-assign.stderr
@@ -7,6 +7,15 @@
| --- value moved here
LL | let a = u.a;
| ^^^ value used here after move
+ |
+note: if `U` implemented `Clone`, you could clone the value
+ --> $DIR/borrowck-union-move-assign.rs:7:1
+ |
+LL | union U {
+ | ^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let a = u.a;
+ | --- you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/borrowck/borrowck-union-move.stderr b/tests/ui/borrowck/borrowck-union-move.stderr
index 731607f..0bae7ac 100644
--- a/tests/ui/borrowck/borrowck-union-move.stderr
+++ b/tests/ui/borrowck/borrowck-union-move.stderr
@@ -7,6 +7,15 @@
| ---- value moved here
LL | let a = u.n1;
| ^^^^ value used here after move
+ |
+note: if `Unn` implemented `Clone`, you could clone the value
+ --> $DIR/borrowck-union-move.rs:7:1
+ |
+LL | union Unn {
+ | ^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let a = u.n1;
+ | ---- you could clone this value
error[E0382]: use of moved value: `u`
--> $DIR/borrowck-union-move.rs:31:21
@@ -17,6 +26,15 @@
| ---- value moved here
LL | let a = u;
| ^ value used here after move
+ |
+note: if `Unn` implemented `Clone`, you could clone the value
+ --> $DIR/borrowck-union-move.rs:7:1
+ |
+LL | union Unn {
+ | ^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let a = u.n1;
+ | ---- you could clone this value
error[E0382]: use of moved value: `u`
--> $DIR/borrowck-union-move.rs:36:21
@@ -27,6 +45,15 @@
| ---- value moved here
LL | let a = u.n2;
| ^^^^ value used here after move
+ |
+note: if `Unn` implemented `Clone`, you could clone the value
+ --> $DIR/borrowck-union-move.rs:7:1
+ |
+LL | union Unn {
+ | ^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let a = u.n1;
+ | ---- you could clone this value
error[E0382]: use of moved value: `u`
--> $DIR/borrowck-union-move.rs:63:21
@@ -37,6 +64,15 @@
| --- value moved here
LL | let a = u.n;
| ^^^ value used here after move
+ |
+note: if `Ucn` implemented `Clone`, you could clone the value
+ --> $DIR/borrowck-union-move.rs:15:1
+ |
+LL | union Ucn {
+ | ^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let a = u.n;
+ | --- you could clone this value
error[E0382]: use of moved value: `u`
--> $DIR/borrowck-union-move.rs:68:21
@@ -47,6 +83,15 @@
| --- value moved here
LL | let a = u.c;
| ^^^ value used here after move
+ |
+note: if `Ucn` implemented `Clone`, you could clone the value
+ --> $DIR/borrowck-union-move.rs:15:1
+ |
+LL | union Ucn {
+ | ^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let a = u.n;
+ | --- you could clone this value
error[E0382]: use of moved value: `u`
--> $DIR/borrowck-union-move.rs:83:21
@@ -57,6 +102,15 @@
| --- value moved here
LL | let a = u;
| ^ value used here after move
+ |
+note: if `Ucn` implemented `Clone`, you could clone the value
+ --> $DIR/borrowck-union-move.rs:15:1
+ |
+LL | union Ucn {
+ | ^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let a = u.n;
+ | --- you could clone this value
error: aborting due to 6 previous errors
diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr
index 4e19fd8..c559230 100644
--- a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr
+++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr
@@ -4,7 +4,7 @@
LL | let sfoo: *mut Foo = &mut SFOO;
| ^^^^^^^^^ mutable reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
= note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
= note: `#[warn(static_mut_refs)]` on by default
help: use `&raw mut` instead to create a raw pointer
diff --git a/tests/ui/issues/issue-11192.rs b/tests/ui/borrowck/closure-borrow-conflict-11192.rs
similarity index 84%
rename from tests/ui/issues/issue-11192.rs
rename to tests/ui/borrowck/closure-borrow-conflict-11192.rs
index 1a3d8c9..dff70d6 100644
--- a/tests/ui/issues/issue-11192.rs
+++ b/tests/ui/borrowck/closure-borrow-conflict-11192.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/11192
+
struct Foo {
x: isize
}
diff --git a/tests/ui/issues/issue-11192.stderr b/tests/ui/borrowck/closure-borrow-conflict-11192.stderr
similarity index 91%
rename from tests/ui/issues/issue-11192.stderr
rename to tests/ui/borrowck/closure-borrow-conflict-11192.stderr
index a8a18c4..f1df635 100644
--- a/tests/ui/issues/issue-11192.stderr
+++ b/tests/ui/borrowck/closure-borrow-conflict-11192.stderr
@@ -1,5 +1,5 @@
error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as mutable
- --> $DIR/issue-11192.rs:20:10
+ --> $DIR/closure-borrow-conflict-11192.rs:22:10
|
LL | let mut test = |foo: &Foo| {
| ----------- mutable borrow occurs here
diff --git a/tests/ui/borrowck/issue-103624.stderr b/tests/ui/borrowck/issue-103624.stderr
index 603055b..af65deb 100644
--- a/tests/ui/borrowck/issue-103624.stderr
+++ b/tests/ui/borrowck/issue-103624.stderr
@@ -2,13 +2,16 @@
--> $DIR/issue-103624.rs:16:13
|
LL | async fn foo(&self) {
- | ----- captured outer variable
+ | -----
+ | |
+ | captured outer variable
+ | move occurs because `self.b` has type `StructB`, which does not implement the `Copy` trait
LL | let bar = self.b.bar().await;
LL | spawn_blocking(move || {
| ------- captured by this `Fn` closure
LL |
LL | self.b;
- | ^^^^^^ move occurs because `self.b` has type `StructB`, which does not implement the `Copy` trait
+ | ^^^^^^ `self.b` is moved here
|
note: if `StructB` implemented `Clone`, you could clone the value
--> $DIR/issue-103624.rs:23:1
diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr
index b188766..167fd6b 100644
--- a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr
+++ b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr
@@ -17,6 +17,15 @@
| - value moved here
LL | u.0 = S(1);
| ^^^^^^^^^^ value partially assigned here after move
+ |
+note: if `Tpair` implemented `Clone`, you could clone the value
+ --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:6:1
+ |
+LL | struct Tpair(S, i32);
+ | ^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | drop(u);
+ | - you could clone this value
error[E0382]: assign to part of moved value: `v`
--> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:31:9
@@ -27,6 +36,15 @@
| - value moved here
LL | v.x = S(1);
| ^^^^^^^^^^ value partially assigned here after move
+ |
+note: if `Spair` implemented `Clone`, you could clone the value
+ --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:7:1
+ |
+LL | struct Spair { x: S, y: i32 }
+ | ^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | drop(v);
+ | - you could clone this value
error: aborting due to 3 previous errors
diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr
index 774b6cf..78c5040 100644
--- a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr
+++ b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr
@@ -50,6 +50,15 @@
| - value moved here
LL | u.0 = S(1);
| ^^^^^^^^^^ value partially assigned here after move
+ |
+note: if `Tpair` implemented `Clone`, you could clone the value
+ --> $DIR/issue-54499-field-mutation-of-moved-out.rs:6:1
+ |
+LL | struct Tpair(S, i32);
+ | ^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | drop(u);
+ | - you could clone this value
error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9
@@ -82,6 +91,15 @@
| - value moved here
LL | v.x = S(1);
| ^^^^^^^^^^ value partially assigned here after move
+ |
+note: if `Spair` implemented `Clone`, you could clone the value
+ --> $DIR/issue-54499-field-mutation-of-moved-out.rs:7:1
+ |
+LL | struct Spair { x: S, y: i32 }
+ | ^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | drop(v);
+ | - you could clone this value
error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9
diff --git a/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr b/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr
index 121c2e8..5a0d353a 100644
--- a/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr
+++ b/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr
@@ -4,6 +4,14 @@
LL | *array
| ^^^^^^ move occurs because `*array` has type `Vec<Value>`, which does not implement the `Copy` trait
|
+note: if `Value` implemented `Clone`, you could clone the value
+ --> $DIR/issue-54597-reject-move-out-of-borrow-via-pat.rs:4:1
+ |
+LL | struct Value;
+ | ^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | *array
+ | ------ you could clone this value
help: consider removing the dereference here
|
LL - *array
diff --git a/tests/ui/borrowck/liberated-region-from-outer-closure.rs b/tests/ui/borrowck/liberated-region-from-outer-closure.rs
new file mode 100644
index 0000000..dcc6370
--- /dev/null
+++ b/tests/ui/borrowck/liberated-region-from-outer-closure.rs
@@ -0,0 +1,12 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/144608>.
+
+fn example<T: Copy>(x: T) -> impl FnMut(&mut ()) {
+ move |_: &mut ()| {
+ move || needs_static_lifetime(x);
+ //~^ ERROR the parameter type `T` may not live long enough
+ }
+}
+
+fn needs_static_lifetime<T: 'static>(obj: T) {}
+
+fn main() {}
diff --git a/tests/ui/borrowck/liberated-region-from-outer-closure.stderr b/tests/ui/borrowck/liberated-region-from-outer-closure.stderr
new file mode 100644
index 0000000..98b45ac
--- /dev/null
+++ b/tests/ui/borrowck/liberated-region-from-outer-closure.stderr
@@ -0,0 +1,17 @@
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/liberated-region-from-outer-closure.rs:5:17
+ |
+LL | move || needs_static_lifetime(x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | the parameter type `T` must be valid for the static lifetime...
+ | ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound
+ |
+LL | fn example<T: Copy + 'static>(x: T) -> impl FnMut(&mut ()) {
+ | +++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/tests/ui/c-variadic/same-program-multiple-abis.rs b/tests/ui/c-variadic/same-program-multiple-abis.rs
new file mode 100644
index 0000000..b21accb
--- /dev/null
+++ b/tests/ui/c-variadic/same-program-multiple-abis.rs
@@ -0,0 +1,112 @@
+#![feature(extended_varargs_abi_support)]
+//@ run-pass
+//@ only-x86_64
+
+// Check that multiple c-variadic calling conventions can be used in the same program.
+//
+// Clang and gcc reject defining functions with a non-default calling convention and a variable
+// argument list, so C programs that use multiple c-variadic calling conventions are unlikely
+// to come up. Here we validate that our codegen backends do in fact generate correct code.
+
+extern "sysv64" {
+ fn variadic_sysv64(_: u32, _: ...) -> u32;
+}
+
+extern "win64" {
+ fn variadic_win64(_: u32, _: ...) -> u32;
+}
+
+fn main() {
+ unsafe {
+ assert_eq!(variadic_win64(1, 2, 3), 1 + 2 + 3);
+ assert_eq!(variadic_sysv64(1, 2, 3), 1 + 2 + 3);
+ }
+}
+
+// This assembly was generated using https://godbolt.org/z/dbTGanoh6, and corresponds to the
+// following code compiled for the `x86_64-unknown-linux-gnu` and `x86_64-pc-windows-gnu`
+// targets, respectively:
+//
+// ```rust
+// #![feature(c_variadic)]
+//
+// #[unsafe(no_mangle)]
+// unsafe extern "C" fn variadic(a: u32, mut args: ...) -> u32 {
+// let b = args.arg::<u32>();
+// let c = args.arg::<u32>();
+//
+// a + b + c
+// }
+// ```
+core::arch::global_asm!(
+ r#"
+{variadic_sysv64}:
+ sub rsp, 88
+ test al, al
+ je .LBB0_7
+ movaps xmmword ptr [rsp - 48], xmm0
+ movaps xmmword ptr [rsp - 32], xmm1
+ movaps xmmword ptr [rsp - 16], xmm2
+ movaps xmmword ptr [rsp], xmm3
+ movaps xmmword ptr [rsp + 16], xmm4
+ movaps xmmword ptr [rsp + 32], xmm5
+ movaps xmmword ptr [rsp + 48], xmm6
+ movaps xmmword ptr [rsp + 64], xmm7
+.LBB0_7:
+ mov qword ptr [rsp - 88], rsi
+ mov qword ptr [rsp - 80], rdx
+ mov qword ptr [rsp - 72], rcx
+ mov qword ptr [rsp - 64], r8
+ mov qword ptr [rsp - 56], r9
+ movabs rax, 206158430216
+ mov qword ptr [rsp - 120], rax
+ lea rax, [rsp + 96]
+ mov qword ptr [rsp - 112], rax
+ lea rax, [rsp - 96]
+ mov qword ptr [rsp - 104], rax
+ mov edx, 8
+ cmp rdx, 41
+ jae .LBB0_1
+ mov rax, qword ptr [rsp - 104]
+ mov ecx, 8
+ add rcx, 8
+ mov dword ptr [rsp - 120], ecx
+ mov eax, dword ptr [rax + rdx]
+ cmp edx, 32
+ ja .LBB0_2
+ add rcx, qword ptr [rsp - 104]
+ add edx, 16
+ mov dword ptr [rsp - 120], edx
+ add eax, edi
+ add eax, dword ptr [rcx]
+ add rsp, 88
+ ret
+.LBB0_1:
+ mov rax, qword ptr [rsp - 112]
+ lea rcx, [rax + 8]
+ mov qword ptr [rsp - 112], rcx
+ mov eax, dword ptr [rax]
+.LBB0_2:
+ mov rcx, qword ptr [rsp - 112]
+ lea rdx, [rcx + 8]
+ mov qword ptr [rsp - 112], rdx
+ add eax, edi
+ add eax, dword ptr [rcx]
+ add rsp, 88
+ ret
+
+{variadic_win64}:
+ push rax
+ mov qword ptr [rsp + 40], r9
+ mov qword ptr [rsp + 24], rdx
+ mov qword ptr [rsp + 32], r8
+ lea rax, [rsp + 40]
+ mov qword ptr [rsp], rax
+ lea eax, [rdx + rcx]
+ add eax, r8d
+ pop rcx
+ ret
+ "#,
+ variadic_win64 = sym variadic_win64,
+ variadic_sysv64 = sym variadic_sysv64,
+);
diff --git a/tests/ui/c-variadic/variadic-ffi-1.rs b/tests/ui/c-variadic/variadic-ffi-1.rs
index cd8f2a9..2baa00a 100644
--- a/tests/ui/c-variadic/variadic-ffi-1.rs
+++ b/tests/ui/c-variadic/variadic-ffi-1.rs
@@ -12,6 +12,11 @@
//~^ ERROR: C-variadic functions with the "stdcall" calling convention are not supported
}
+fn baz(f: extern "Rust" fn(usize, ...)) {
+ //~^ ERROR: C-variadic functions with the "Rust" calling convention are not supported
+ f(22, 44);
+}
+
extern "C" {
fn foo(f: isize, x: u8, ...);
}
diff --git a/tests/ui/c-variadic/variadic-ffi-1.stderr b/tests/ui/c-variadic/variadic-ffi-1.stderr
index a49fc0c..981b021 100644
--- a/tests/ui/c-variadic/variadic-ffi-1.stderr
+++ b/tests/ui/c-variadic/variadic-ffi-1.stderr
@@ -4,14 +4,20 @@
LL | fn printf(_: *const u8, ...);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
+error[E0045]: C-variadic functions with the "Rust" calling convention are not supported
+ --> $DIR/variadic-ffi-1.rs:15:11
+ |
+LL | fn baz(f: extern "Rust" fn(usize, ...)) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
+
error[E0060]: this function takes at least 2 arguments but 0 arguments were supplied
- --> $DIR/variadic-ffi-1.rs:23:9
+ --> $DIR/variadic-ffi-1.rs:28:9
|
LL | foo();
| ^^^-- two arguments of type `isize` and `u8` are missing
|
note: function defined here
- --> $DIR/variadic-ffi-1.rs:16:8
+ --> $DIR/variadic-ffi-1.rs:21:8
|
LL | fn foo(f: isize, x: u8, ...);
| ^^^ - -
@@ -21,13 +27,13 @@
| +++++++++++++++++++++
error[E0060]: this function takes at least 2 arguments but 1 argument was supplied
- --> $DIR/variadic-ffi-1.rs:24:9
+ --> $DIR/variadic-ffi-1.rs:29:9
|
LL | foo(1);
| ^^^--- argument #2 of type `u8` is missing
|
note: function defined here
- --> $DIR/variadic-ffi-1.rs:16:8
+ --> $DIR/variadic-ffi-1.rs:21:8
|
LL | fn foo(f: isize, x: u8, ...);
| ^^^ -
@@ -37,7 +43,7 @@
| ++++++++++
error[E0308]: mismatched types
- --> $DIR/variadic-ffi-1.rs:26:56
+ --> $DIR/variadic-ffi-1.rs:31:56
|
LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo;
| ------------------------------------- ^^^ expected non-variadic fn, found variadic function
@@ -48,7 +54,7 @@
found fn item `unsafe extern "C" fn(_, _, ...) {foo}`
error[E0308]: mismatched types
- --> $DIR/variadic-ffi-1.rs:27:54
+ --> $DIR/variadic-ffi-1.rs:32:54
|
LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar;
| ----------------------------------- ^^^ expected variadic fn, found non-variadic function
@@ -59,7 +65,7 @@
found fn item `extern "C" fn(_, _) {bar}`
error[E0617]: can't pass `f32` to variadic function
- --> $DIR/variadic-ffi-1.rs:29:19
+ --> $DIR/variadic-ffi-1.rs:34:19
|
LL | foo(1, 2, 3f32);
| ^^^^
@@ -70,7 +76,7 @@
| +++++++++++
error[E0617]: can't pass `bool` to variadic function
- --> $DIR/variadic-ffi-1.rs:30:19
+ --> $DIR/variadic-ffi-1.rs:35:19
|
LL | foo(1, 2, true);
| ^^^^
@@ -81,7 +87,7 @@
| ++++++++
error[E0617]: can't pass `i8` to variadic function
- --> $DIR/variadic-ffi-1.rs:31:19
+ --> $DIR/variadic-ffi-1.rs:36:19
|
LL | foo(1, 2, 1i8);
| ^^^
@@ -92,7 +98,7 @@
| ++++++++
error[E0617]: can't pass `u8` to variadic function
- --> $DIR/variadic-ffi-1.rs:32:19
+ --> $DIR/variadic-ffi-1.rs:37:19
|
LL | foo(1, 2, 1u8);
| ^^^
@@ -103,7 +109,7 @@
| +++++++++
error[E0617]: can't pass `i16` to variadic function
- --> $DIR/variadic-ffi-1.rs:33:19
+ --> $DIR/variadic-ffi-1.rs:38:19
|
LL | foo(1, 2, 1i16);
| ^^^^
@@ -114,7 +120,7 @@
| ++++++++
error[E0617]: can't pass `u16` to variadic function
- --> $DIR/variadic-ffi-1.rs:34:19
+ --> $DIR/variadic-ffi-1.rs:39:19
|
LL | foo(1, 2, 1u16);
| ^^^^
@@ -124,7 +130,7 @@
LL | foo(1, 2, 1u16 as c_uint);
| +++++++++
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
Some errors have detailed explanations: E0045, E0060, E0308, E0617.
For more information about an error, try `rustc --explain E0045`.
diff --git a/tests/ui/c-variadic/variadic-ffi-2-arm.rs b/tests/ui/c-variadic/variadic-ffi-2-arm.rs
deleted file mode 100644
index 3b0a710..0000000
--- a/tests/ui/c-variadic/variadic-ffi-2-arm.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ only-arm
-//@ build-pass
-#![feature(extended_varargs_abi_support)]
-
-fn aapcs(f: extern "aapcs" fn(usize, ...)) {
- f(22, 44);
-}
-
-fn main() {}
diff --git a/tests/ui/c-variadic/variadic-ffi-2.rs b/tests/ui/c-variadic/variadic-ffi-2.rs
deleted file mode 100644
index adfd9bf..0000000
--- a/tests/ui/c-variadic/variadic-ffi-2.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-#![feature(extended_varargs_abi_support)]
-
-fn baz(f: extern "Rust" fn(usize, ...)) {
- //~^ ERROR: C-variadic functions with the "Rust" calling convention are not supported
- f(22, 44);
-}
-
-#[cfg(target_arch = "x86_64")]
-fn sysv(f: extern "sysv64" fn(usize, ...)) {
- f(22, 44);
-}
-#[cfg(target_arch = "x86_64")]
-fn win(f: extern "win64" fn(usize, ...)) {
- f(22, 44);
-}
-#[cfg(any(
- target_arch = "arm",
- target_arch = "aarch64",
- target_arch = "riscv32",
- target_arch = "riscv64",
- target_arch = "x86",
- target_arch = "x86_64"
-))]
-fn efiapi(f: extern "efiapi" fn(usize, ...)) {
- f(22, 44);
-}
-
-fn main() {}
diff --git a/tests/ui/c-variadic/variadic-ffi-2.stderr b/tests/ui/c-variadic/variadic-ffi-2.stderr
deleted file mode 100644
index 2ac0a9f..0000000
--- a/tests/ui/c-variadic/variadic-ffi-2.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0045]: C-variadic functions with the "Rust" calling convention are not supported
- --> $DIR/variadic-ffi-2.rs:3:11
- |
-LL | fn baz(f: extern "Rust" fn(usize, ...)) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0045`.
diff --git a/tests/ui/issues/issue-4333.rs b/tests/ui/cast/trait-object-cast-segfault-4333.rs
similarity index 75%
rename from tests/ui/issues/issue-4333.rs
rename to tests/ui/cast/trait-object-cast-segfault-4333.rs
index dccaa6f..24e86d4 100644
--- a/tests/ui/issues/issue-4333.rs
+++ b/tests/ui/cast/trait-object-cast-segfault-4333.rs
@@ -7,3 +7,5 @@ pub fn main() {
let stdout = &mut io::stdout() as &mut dyn io::Write;
stdout.write(b"Hello!");
}
+
+// https://github.com/rust-lang/rust/issues/4333
diff --git a/tests/ui/cfg/cfg-panic-abort.rs b/tests/ui/cfg/cfg-panic-abort.rs
index 448fde2..b398885 100644
--- a/tests/ui/cfg/cfg-panic-abort.rs
+++ b/tests/ui/cfg/cfg-panic-abort.rs
@@ -1,6 +1,7 @@
//@ build-pass
//@ compile-flags: -C panic=abort
//@ no-prefer-dynamic
+//@ ignore-backends: gcc
#[cfg(panic = "unwind")]
pub fn bad() -> i32 { }
diff --git a/tests/ui/issues/issue-11085.rs b/tests/ui/cfg/conditional-compilation-struct-11085.rs
similarity index 87%
rename from tests/ui/issues/issue-11085.rs
rename to tests/ui/cfg/conditional-compilation-struct-11085.rs
index c3f1319..cd6dded 100644
--- a/tests/ui/issues/issue-11085.rs
+++ b/tests/ui/cfg/conditional-compilation-struct-11085.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/11085
+
//@ run-pass
#![allow(dead_code)]
diff --git a/tests/ui/cfg/conditional-compile-arch.rs b/tests/ui/cfg/conditional-compile-arch.rs
index 594d934..f168054 100644
--- a/tests/ui/cfg/conditional-compile-arch.rs
+++ b/tests/ui/cfg/conditional-compile-arch.rs
@@ -38,3 +38,6 @@ pub fn main() { }
#[cfg(target_arch = "loongarch64")]
pub fn main() { }
+
+#[cfg(target_arch = "arm64ec")]
+pub fn main() { }
diff --git a/tests/ui/check-cfg/my-awesome-platform.json b/tests/ui/check-cfg/my-awesome-platform.json
index 03b08b7..4c16d06 100644
--- a/tests/ui/check-cfg/my-awesome-platform.json
+++ b/tests/ui/check-cfg/my-awesome-platform.json
@@ -4,7 +4,6 @@
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
- "target-c-int-width": "32",
"os": "ericos",
"linker-flavor": "ld.lld",
"linker": "rust-lld",
diff --git a/tests/ui/closures/2229_closure_analysis/issue-90465.stderr b/tests/ui/closures/2229_closure_analysis/issue-90465.stderr
index ccca247..94bbd79 100644
--- a/tests/ui/closures/2229_closure_analysis/issue-90465.stderr
+++ b/tests/ui/closures/2229_closure_analysis/issue-90465.stderr
@@ -10,7 +10,7 @@
LL | }
| - in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
note: the lint level is defined here
--> $DIR/issue-90465.rs:3:9
|
diff --git a/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2018.stderr b/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2018.stderr
index 394629c..057960e 100644
--- a/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2018.stderr
+++ b/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2018.stderr
@@ -26,6 +26,15 @@
...
LL | let x = value;
| ^^^^^ value used here after move
+ |
+note: if `E` implemented `Clone`, you could clone the value
+ --> $DIR/if-let-guards-errors.rs:32:1
+ |
+LL | E::Number(_) if let E::String(s) = *value => { }
+ | ------ you could clone this value
+...
+LL | enum E {
+ | ^^^^^^ consider implementing `Clone` for this type
error: aborting due to 2 previous errors
diff --git a/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2021.stderr b/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2021.stderr
index 5672845..4a6e390 100644
--- a/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2021.stderr
+++ b/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2021.stderr
@@ -26,6 +26,15 @@
...
LL | let x = value;
| ^^^^^ value used here after move
+ |
+note: if `E` implemented `Clone`, you could clone the value
+ --> $DIR/if-let-guards-errors.rs:32:1
+ |
+LL | E::Number(_) if let E::String(s) = *value => { }
+ | ------ you could clone this value
+...
+LL | enum E {
+ | ^^^^^^ consider implementing `Clone` for this type
error: aborting due to 2 previous errors
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
index fdcada4..b981ef6 100644
--- a/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
+++ b/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
@@ -7,7 +7,7 @@
LL | *fptr.0 = 20;
| ------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0`
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
note: the lint level is defined here
--> $DIR/auto_traits.rs:2:9
|
@@ -34,7 +34,7 @@
LL | *fptr.0.0 = 20;
| --------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0.0`
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `fptr` to be fully captured
|
LL ~ thread::spawn(move || { let _ = &fptr; unsafe {
@@ -56,7 +56,7 @@
LL | }
| - in Rust 2018, `f` is dropped here, but in Rust 2021, only `f.1` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `f` to be fully captured
|
LL ~ let c = || {
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr b/tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
index bb17e3a..c49b1d2 100644
--- a/tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
+++ b/tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
@@ -15,7 +15,7 @@
LL | | });
| |______- in this macro invocation
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
note: the lint level is defined here
--> $DIR/closure-body-macro-fragment.rs:4:9
|
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr
index a0795c1..3381b9e 100644
--- a/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr
+++ b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr
@@ -10,7 +10,7 @@
LL | }
| - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
note: the lint level is defined here
--> $DIR/insignificant_drop_attr_migrations.rs:3:9
|
@@ -34,7 +34,7 @@
LL | }
| - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `t` to be fully captured
|
LL ~ let c = move || {
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/macro.stderr b/tests/ui/closures/2229_closure_analysis/migrations/macro.stderr
index 7ea5136..7d90b7b 100644
--- a/tests/ui/closures/2229_closure_analysis/migrations/macro.stderr
+++ b/tests/ui/closures/2229_closure_analysis/migrations/macro.stderr
@@ -7,7 +7,7 @@
LL | }
| - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
note: the lint level is defined here
--> $DIR/macro.rs:5:9
|
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr b/tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr
index 9452648..7d937f5 100644
--- a/tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr
+++ b/tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr
@@ -10,7 +10,7 @@
LL | }
| - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
note: the lint level is defined here
--> $DIR/migrations_rustfix.rs:2:9
|
@@ -31,7 +31,7 @@
LL | }
| - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `t` to be fully captured
|
LL | let c = || { let _ = &t; t.0 };
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr
index 2b76dec..6a9266e 100644
--- a/tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr
+++ b/tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr
@@ -10,7 +10,7 @@
LL | f.0()
| --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.0`
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
note: the lint level is defined here
--> $DIR/mir_calls_to_shims.rs:4:9
|
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
index 138778f..81ffe86 100644
--- a/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
+++ b/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
@@ -13,7 +13,7 @@
LL | }
| - in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
note: the lint level is defined here
--> $DIR/multi_diagnostics.rs:2:9
|
@@ -34,7 +34,7 @@
LL | let _f_1 = f1.0;
| ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `f1` to be fully captured
|
LL ~ let c = || {
@@ -56,7 +56,7 @@
LL | let _f_2 = f1.2;
| ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.2`
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `f1` to be fully captured
|
LL ~ let c = || {
@@ -81,7 +81,7 @@
| in Rust 2018, `f1` is dropped here, but in Rust 2021, only `f1.0` will be dropped here as part of the closure
| in Rust 2018, `f1` is dropped here, but in Rust 2021, only `f1.1` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `f1` to be fully captured
|
LL ~ let c = || {
@@ -104,7 +104,7 @@
LL | *fptr2.0 = 20;
| -------- in Rust 2018, this closure captures all of `fptr2`, but in Rust 2021, it will only capture `fptr2.0`
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `fptr1`, `fptr2` to be fully captured
|
LL ~ thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe {
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/precise.stderr b/tests/ui/closures/2229_closure_analysis/migrations/precise.stderr
index eff26a4..5fb7675 100644
--- a/tests/ui/closures/2229_closure_analysis/migrations/precise.stderr
+++ b/tests/ui/closures/2229_closure_analysis/migrations/precise.stderr
@@ -10,7 +10,7 @@
LL | }
| - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
note: the lint level is defined here
--> $DIR/precise.rs:3:9
|
@@ -44,7 +44,7 @@
| in Rust 2018, `u` is dropped here, but in Rust 2021, only `u.0.1` will be dropped here as part of the closure
| in Rust 2018, `u` is dropped here, but in Rust 2021, only `u.1.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `u` to be fully captured
|
LL ~ let c = || {
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr b/tests/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr
index 54ad20f..3f4d38a 100644
--- a/tests/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr
+++ b/tests/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr
@@ -20,7 +20,7 @@
| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
| in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
note: the lint level is defined here
--> $DIR/significant_drop.rs:2:9
|
@@ -50,7 +50,7 @@
| in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `t`, `t1` to be fully captured
|
LL ~ let c = || {
@@ -69,7 +69,7 @@
LL | }
| - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `t` to be fully captured
|
LL ~ let c = || {
@@ -88,7 +88,7 @@
LL | }
| - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `t` to be fully captured
|
LL ~ let c = || {
@@ -107,7 +107,7 @@
LL | }
| - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `t` to be fully captured
|
LL ~ let c = || {
@@ -126,7 +126,7 @@
LL | }
| - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `t` to be fully captured
|
LL ~ let c = || {
@@ -150,7 +150,7 @@
| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure
| in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `t1`, `t` to be fully captured
|
LL ~ let c = move || {
@@ -169,7 +169,7 @@
LL | }
| - in Rust 2018, `tuple` is dropped here, but in Rust 2021, only `tuple.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `tuple` to be fully captured
|
LL ~ let c = || {
@@ -188,7 +188,7 @@
LL | };
| - in Rust 2018, `tuple` is dropped here, but in Rust 2021, only `tuple.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `tuple` to be fully captured
|
LL ~ let c = || {
@@ -204,7 +204,7 @@
LL | }
| - in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `tup` to be fully captured
|
LL | let _c = || { let _ = &tup; tup.0 };
diff --git a/tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs b/tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs
index a4646d6..40d838b 100644
--- a/tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs
+++ b/tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs
@@ -1,4 +1,6 @@
//@ run-pass
+//@ ignore-backends: gcc
+
#![allow(dead_code)]
// check that we don't have linear stack usage with multiple calls to `push`
diff --git a/tests/ui/issues/issue-36278-prefix-nesting.rs b/tests/ui/codegen/dynamic-size-of-prefix-correctly-36278.rs
similarity index 91%
rename from tests/ui/issues/issue-36278-prefix-nesting.rs
rename to tests/ui/codegen/dynamic-size-of-prefix-correctly-36278.rs
index 3f2ca7a..78c0129 100644
--- a/tests/ui/issues/issue-36278-prefix-nesting.rs
+++ b/tests/ui/codegen/dynamic-size-of-prefix-correctly-36278.rs
@@ -18,3 +18,5 @@ fn main() {
size_of_unsized = mem::size_of_val::<Ack<_>>(&y);
assert_eq!(size_of_sized, size_of_unsized);
}
+
+// https://github.com/rust-lang/rust/issues/36278
diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs
index d13fd4b..53e29e7 100644
--- a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs
@@ -1,6 +1,7 @@
//@ known-bug: #107975
//@ compile-flags: -Copt-level=2
//@ run-pass
+//@ ignore-backends: gcc
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs
index 5ec3c7c..4763976 100644
--- a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs
@@ -1,6 +1,7 @@
//@ known-bug: #107975
//@ compile-flags: -Copt-level=2
//@ run-pass
+//@ ignore-backends: gcc
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs
index 97a875f..70cbb9a 100644
--- a/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs
@@ -1,6 +1,7 @@
//@ known-bug: #107975
//@ compile-flags: -Copt-level=2
//@ run-pass
+//@ ignore-backends: gcc
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs
index 731c5b6..694fb34 100644
--- a/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs
@@ -1,6 +1,7 @@
//@ known-bug: #107975
//@ compile-flags: -Copt-level=2
//@ run-pass
+//@ ignore-backends: gcc
// Derived from https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs
index cdf07ea..ade3266 100644
--- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs
@@ -1,6 +1,7 @@
//@ known-bug: #107975
//@ compile-flags: -Copt-level=2
//@ run-pass
+//@ ignore-backends: gcc
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs
index 9473970..d8feaee 100644
--- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs
@@ -1,6 +1,7 @@
//@ known-bug: #107975
//@ compile-flags: -Copt-level=2
//@ run-pass
+//@ ignore-backends: gcc
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs
index b163c28..ad1d7b5 100644
--- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs
@@ -1,6 +1,7 @@
//@ known-bug: #107975
//@ compile-flags: -Copt-level=2
//@ run-pass
+//@ ignore-backends: gcc
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs
index b7824f5..a50369b 100644
--- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs
@@ -1,6 +1,7 @@
//@ known-bug: #107975
//@ compile-flags: -Copt-level=2
//@ run-pass
+//@ ignore-backends: gcc
// Derived from https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs
index 5f4ee73..0b5b2df 100644
--- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs
@@ -1,6 +1,7 @@
//@ known-bug: #107975
//@ compile-flags: -Copt-level=2
//@ run-pass
+//@ ignore-backends: gcc
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs
index 0f838af..1812a11 100644
--- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs
@@ -1,6 +1,7 @@
//@ known-bug: #107975
//@ compile-flags: -Copt-level=2
//@ run-pass
+//@ ignore-backends: gcc
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs
index fea41e0..637f004 100644
--- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs
@@ -1,6 +1,7 @@
//@ known-bug: #107975
//@ compile-flags: -Copt-level=2
//@ run-pass
+//@ ignore-backends: gcc
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs
index 20ed991..5879b3f 100644
--- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs
@@ -1,6 +1,7 @@
//@ known-bug: #107975
//@ compile-flags: -Copt-level=2
//@ run-pass
+//@ ignore-backends: gcc
// Derived from https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
diff --git a/tests/ui/codegen/mismatched-data-layout.json b/tests/ui/codegen/mismatched-data-layout.json
index 7adc883..f8c510c 100644
--- a/tests/ui/codegen/mismatched-data-layout.json
+++ b/tests/ui/codegen/mismatched-data-layout.json
@@ -4,7 +4,6 @@
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
- "target-c-int-width": "32",
"os": "none",
"linker-flavor": "ld.lld",
"linker": "rust-lld",
diff --git a/tests/ui/codegen/mismatched-data-layouts.rs b/tests/ui/codegen/mismatched-data-layouts.rs
index 6428b8c..ea14571 100644
--- a/tests/ui/codegen/mismatched-data-layouts.rs
+++ b/tests/ui/codegen/mismatched-data-layouts.rs
@@ -5,6 +5,7 @@
//@ compile-flags: --crate-type=lib --target={{src-base}}/codegen/mismatched-data-layout.json -Z unstable-options
//@ normalize-stderr: "`, `[A-Za-z0-9-:]*`" -> "`, `normalized data layout`"
//@ normalize-stderr: "layout, `[A-Za-z0-9-:]*`" -> "layout, `normalized data layout`"
+//@ normalize-stderr: "`mismatched-data-layout-\d+`" -> "`mismatched-data-layout-<hash>`"
#![feature(lang_items, no_core, auto_traits)]
#![no_core]
diff --git a/tests/ui/codegen/mismatched-data-layouts.stderr b/tests/ui/codegen/mismatched-data-layouts.stderr
index b7d5d82..d111756 100644
--- a/tests/ui/codegen/mismatched-data-layouts.stderr
+++ b/tests/ui/codegen/mismatched-data-layouts.stderr
@@ -1,4 +1,4 @@
-error: data-layout for target `mismatched-data-layout-7193370089426056427`, `normalized data layout`, differs from LLVM target's `x86_64-unknown-none-gnu` default layout, `normalized data layout`
+error: data-layout for target `mismatched-data-layout-<hash>`, `normalized data layout`, differs from LLVM target's `x86_64-unknown-none-gnu` default layout, `normalized data layout`
error: aborting due to 1 previous error
diff --git a/tests/ui/codemap_tests/unicode.expanded.stdout b/tests/ui/codemap_tests/unicode.expanded.stdout
index c88035d..af37510 100644
--- a/tests/ui/codemap_tests/unicode.expanded.stdout
+++ b/tests/ui/codemap_tests/unicode.expanded.stdout
@@ -1,9 +1,9 @@
#![feature(prelude_import)]
#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ revisions: normal expanded
//@[expanded] check-pass
//@[expanded]compile-flags: -Zunpretty=expanded
diff --git a/tests/ui/issues/issue-11205.rs b/tests/ui/coercion/trait-object-arrays-11205.rs
similarity index 95%
rename from tests/ui/issues/issue-11205.rs
rename to tests/ui/coercion/trait-object-arrays-11205.rs
index 8530514..45d69dc 100644
--- a/tests/ui/issues/issue-11205.rs
+++ b/tests/ui/coercion/trait-object-arrays-11205.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/11205
+
//@ run-pass
#![allow(dead_code)]
diff --git a/tests/ui/compiletest-self-test/ui-testing-optout.stderr b/tests/ui/compiletest-self-test/ui-testing-optout.stderr
index 652c472..f1d03ea 100644
--- a/tests/ui/compiletest-self-test/ui-testing-optout.stderr
+++ b/tests/ui/compiletest-self-test/ui-testing-optout.stderr
@@ -16,7 +16,7 @@
error[E0412]: cannot find type `F` in this scope
--> $DIR/ui-testing-optout.rs:92:10
|
-4 | type A = B;
+ 4 | type A = B;
| ----------- similarly named type alias `A` defined here
...
92 | type E = F;
diff --git a/tests/ui/const-generics/defaults/pretty-printing-ast.stdout b/tests/ui/const-generics/defaults/pretty-printing-ast.stdout
index b6cb7fa..030fcec 100644
--- a/tests/ui/const-generics/defaults/pretty-printing-ast.stdout
+++ b/tests/ui/const-generics/defaults/pretty-printing-ast.stdout
@@ -6,10 +6,10 @@
//@ edition: 2015
#![crate_type = "lib"]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
trait Foo<const KIND : bool = true> {}
diff --git a/tests/ui/issues/issue-39211.rs b/tests/ui/const-generics/generic-parameter-in-const-expression-39211.rs
similarity index 83%
rename from tests/ui/issues/issue-39211.rs
rename to tests/ui/const-generics/generic-parameter-in-const-expression-39211.rs
index ab86afc..b2566e5 100644
--- a/tests/ui/issues/issue-39211.rs
+++ b/tests/ui/const-generics/generic-parameter-in-const-expression-39211.rs
@@ -12,3 +12,5 @@ fn m<M: Mat>() {
}
fn main() {
}
+
+// https://github.com/rust-lang/rust/issues/39211
diff --git a/tests/ui/issues/issue-39211.stderr b/tests/ui/const-generics/generic-parameter-in-const-expression-39211.stderr
similarity index 77%
rename from tests/ui/issues/issue-39211.stderr
rename to tests/ui/const-generics/generic-parameter-in-const-expression-39211.stderr
index 2124bc6..2a80aff 100644
--- a/tests/ui/issues/issue-39211.stderr
+++ b/tests/ui/const-generics/generic-parameter-in-const-expression-39211.stderr
@@ -1,5 +1,5 @@
error: constant expression depends on a generic parameter
- --> $DIR/issue-39211.rs:9:17
+ --> $DIR/generic-parameter-in-const-expression-39211.rs:9:17
|
LL | let a = [3; M::Row::DIM];
| ^^^^^^^^^^^
@@ -7,7 +7,7 @@
= note: this may fail depending on what value the parameter takes
error: constant expression depends on a generic parameter
- --> $DIR/issue-39211.rs:9:13
+ --> $DIR/generic-parameter-in-const-expression-39211.rs:9:13
|
LL | let a = [3; M::Row::DIM];
| ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/const-generics/generic_const_exprs/auxiliary/feature-attribute-missing-in-dependent-crate-ice-aux.rs b/tests/ui/const-generics/generic_const_exprs/auxiliary/feature-attribute-missing-in-dependent-crate-ice-aux.rs
new file mode 100644
index 0000000..3902454
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/auxiliary/feature-attribute-missing-in-dependent-crate-ice-aux.rs
@@ -0,0 +1,9 @@
+#![feature(generic_const_exprs)]
+
+pub struct Error(());
+
+pub trait FromSlice: Sized {
+ const SIZE: usize = std::mem::size_of::<Self>();
+
+ fn validate_slice(bytes: &[[u8; Self::SIZE]]) -> Result<(), Error>;
+}
diff --git a/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.rs b/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.rs
new file mode 100644
index 0000000..b953701
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.rs
@@ -0,0 +1,19 @@
+//! Regression test to ensure that using the `generic_const_exprs` feature in a library crate
+//! without enabling it in a dependent crate does not lead to an ICE.
+//!
+//! Issue: <https://github.com/rust-lang/rust/issues/129882>
+
+//@ aux-build:feature-attribute-missing-in-dependent-crate-ice-aux.rs
+
+extern crate feature_attribute_missing_in_dependent_crate_ice_aux as aux;
+
+struct Wrapper<const F: usize>(i64);
+
+impl<const F: usize> aux::FromSlice for Wrapper<F> {
+ fn validate_slice(_: &[[u8; Self::SIZE]]) -> Result<(), aux::Error> {
+ //~^ ERROR generic `Self` types are currently not permitted in anonymous constants
+ Ok(())
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.stderr b/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.stderr
new file mode 100644
index 0000000..5c330665
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.stderr
@@ -0,0 +1,14 @@
+error: generic `Self` types are currently not permitted in anonymous constants
+ --> $DIR/feature-attribute-missing-in-dependent-crate-ice.rs:13:33
+ |
+LL | fn validate_slice(_: &[[u8; Self::SIZE]]) -> Result<(), aux::Error> {
+ | ^^^^
+ |
+note: not a concrete type
+ --> $DIR/feature-attribute-missing-in-dependent-crate-ice.rs:12:41
+ |
+LL | impl<const F: usize> aux::FromSlice for Wrapper<F> {
+ | ^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/const-generics/min_const_generics/macro-fail-const.rs b/tests/ui/const-generics/min_const_generics/macro-fail-const.rs
new file mode 100644
index 0000000..619d6de
--- /dev/null
+++ b/tests/ui/const-generics/min_const_generics/macro-fail-const.rs
@@ -0,0 +1,23 @@
+trait Marker<const N: usize> {}
+struct Example<const N: usize>;
+impl<const N: usize> Marker<N> for Example<N> {}
+
+fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
+ //~^ ERROR: type provided when a constant was expected
+ //~| ERROR: type provided when a constant was expected
+ Example::<gimme_a_const!(marker)>
+ //~^ ERROR: type provided when a constant was expected
+}
+
+fn main() {
+ let _ok = Example::<{
+ #[macro_export]
+ macro_rules! gimme_a_const {
+ ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
+ //~^ ERROR expected type
+ //~| ERROR expected type
+ }
+ gimme_a_const!(run)
+ }>;
+ let _ok = Example::<{gimme_a_const!(marker)}>;
+}
diff --git a/tests/ui/const-generics/min_const_generics/macro-fail-const.stderr b/tests/ui/const-generics/min_const_generics/macro-fail-const.stderr
new file mode 100644
index 0000000..2d8cb50
--- /dev/null
+++ b/tests/ui/const-generics/min_const_generics/macro-fail-const.stderr
@@ -0,0 +1,51 @@
+error: expected type, found `{`
+ --> $DIR/macro-fail-const.rs:16:27
+ |
+LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
+ | ----------------------
+ | |
+ | this macro call doesn't expand to a type
+ | in this macro invocation
+...
+LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
+ | ^ expected type
+ |
+ = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected type, found `{`
+ --> $DIR/macro-fail-const.rs:16:27
+ |
+LL | Example::<gimme_a_const!(marker)>
+ | ----------------------
+ | |
+ | this macro call doesn't expand to a type
+ | in this macro invocation
+...
+LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
+ | ^ expected type
+ |
+ = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0747]: type provided when a constant was expected
+ --> $DIR/macro-fail-const.rs:5:33
+ |
+LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0747]: type provided when a constant was expected
+ --> $DIR/macro-fail-const.rs:5:33
+ |
+LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0747]: type provided when a constant was expected
+ --> $DIR/macro-fail-const.rs:8:13
+ |
+LL | Example::<gimme_a_const!(marker)>
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/tests/ui/const-generics/min_const_generics/macro-fail.rs b/tests/ui/const-generics/min_const_generics/macro-fail.rs
index 8cfa529..ada9400 100644
--- a/tests/ui/const-generics/min_const_generics/macro-fail.rs
+++ b/tests/ui/const-generics/min_const_generics/macro-fail.rs
@@ -12,10 +12,7 @@ trait Marker<const N: usize> {}
impl<const N: usize> Marker<N> for Example<N> {}
fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
- //~^ ERROR: type provided when a constant was expected
- //~| ERROR: type provided when a constant was expected
Example::<gimme_a_const!(marker)>
- //~^ ERROR: type provided when a constant was expected
}
fn from_marker(_: impl Marker<{
@@ -35,9 +32,7 @@ macro_rules! gimme_a_const {
}>;
let _fail = Example::<external_macro!()>;
- //~^ ERROR: type provided when a constant
let _fail = Example::<gimme_a_const!()>;
- //~^ ERROR unexpected end of macro invocation
- //~| ERROR: type provided when a constant was expected
+ //~^ ERROR: unexpected end of macro invocation
}
diff --git a/tests/ui/const-generics/min_const_generics/macro-fail.stderr b/tests/ui/const-generics/min_const_generics/macro-fail.stderr
index 3476498..b1d766c 100644
--- a/tests/ui/const-generics/min_const_generics/macro-fail.stderr
+++ b/tests/ui/const-generics/min_const_generics/macro-fail.stderr
@@ -1,5 +1,5 @@
error: expected type, found `{`
- --> $DIR/macro-fail.rs:30:27
+ --> $DIR/macro-fail.rs:27:27
|
LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
| ----------------------
@@ -13,7 +13,7 @@
= note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected type, found `{`
- --> $DIR/macro-fail.rs:30:27
+ --> $DIR/macro-fail.rs:27:27
|
LL | Example::<gimme_a_const!(marker)>
| ----------------------
@@ -41,7 +41,7 @@
= note: this error originates in the macro `external_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
error: unexpected end of macro invocation
- --> $DIR/macro-fail.rs:40:25
+ --> $DIR/macro-fail.rs:36:25
|
LL | macro_rules! gimme_a_const {
| -------------------------- when calling this macro
@@ -50,43 +50,10 @@
| ^^^^^^^^^^^^^^^^ missing tokens in macro arguments
|
note: while trying to match meta-variable `$rusty:ident`
- --> $DIR/macro-fail.rs:30:8
+ --> $DIR/macro-fail.rs:27:8
|
LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
| ^^^^^^^^^^^^^
-error[E0747]: type provided when a constant was expected
- --> $DIR/macro-fail.rs:14:33
- |
-LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
- | ^^^^^^^^^^^^^^^^^^^^^^
+error: aborting due to 4 previous errors
-error[E0747]: type provided when a constant was expected
- --> $DIR/macro-fail.rs:14:33
- |
-LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
- | ^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0747]: type provided when a constant was expected
- --> $DIR/macro-fail.rs:17:13
- |
-LL | Example::<gimme_a_const!(marker)>
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0747]: type provided when a constant was expected
- --> $DIR/macro-fail.rs:37:25
- |
-LL | let _fail = Example::<external_macro!()>;
- | ^^^^^^^^^^^^^^^^^
-
-error[E0747]: type provided when a constant was expected
- --> $DIR/macro-fail.rs:40:25
- |
-LL | let _fail = Example::<gimme_a_const!()>;
- | ^^^^^^^^^^^^^^^^
-
-error: aborting due to 9 previous errors
-
-For more information about this error, try `rustc --explain E0747`.
diff --git a/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr b/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr
index 3553a18..b3ccd24 100644
--- a/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr
+++ b/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
= note: `#[warn(non_fmt_panics)]` on by default
help: add a "{}" format string to `Display` the message
|
diff --git a/tests/ui/consts/const-eval/parse_ints.rs b/tests/ui/consts/const-eval/parse_ints.rs
index 409fae9..6a7e157 100644
--- a/tests/ui/consts/const-eval/parse_ints.rs
+++ b/tests/ui/consts/const-eval/parse_ints.rs
@@ -1,3 +1,5 @@
+//@ ignore-backends: gcc
+
const _OK: () = match i32::from_str_radix("-1234", 10) {
Ok(x) => assert!(x == -1234),
Err(_) => panic!(),
diff --git a/tests/ui/consts/const-eval/parse_ints.stderr b/tests/ui/consts/const-eval/parse_ints.stderr
index 7e529c0..9c9d083 100644
--- a/tests/ui/consts/const-eval/parse_ints.stderr
+++ b/tests/ui/consts/const-eval/parse_ints.stderr
@@ -1,5 +1,5 @@
error[E0080]: evaluation panicked: from_ascii_radix: radix must lie in the range `[2, 36]`
- --> $DIR/parse_ints.rs:5:24
+ --> $DIR/parse_ints.rs:7:24
|
LL | const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_TOO_LOW` failed inside this call
@@ -11,7 +11,7 @@
= note: this error originates in the macro `from_str_int_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0080]: evaluation panicked: from_ascii_radix: radix must lie in the range `[2, 36]`
- --> $DIR/parse_ints.rs:6:25
+ --> $DIR/parse_ints.rs:8:25
|
LL | const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_TOO_HIGH` failed inside this call
diff --git a/tests/ui/consts/const-unsized.rs b/tests/ui/consts/const-unsized.rs
index e8af332..4140563 100644
--- a/tests/ui/consts/const-unsized.rs
+++ b/tests/ui/consts/const-unsized.rs
@@ -10,14 +10,10 @@
static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
//~^ ERROR the size for values of type
-//~| ERROR cannot move out of a shared reference
static STATIC_BAR: str = *"bar";
//~^ ERROR the size for values of type
-//~| ERROR cannot move out of a shared reference
fn main() {
println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR);
- //~^ ERROR: cannot move a value of type `str`
- //~| ERROR: cannot move a value of type `dyn Debug + Sync`
}
diff --git a/tests/ui/consts/const-unsized.stderr b/tests/ui/consts/const-unsized.stderr
index c92fbc1..a37a6df 100644
--- a/tests/ui/consts/const-unsized.stderr
+++ b/tests/ui/consts/const-unsized.stderr
@@ -26,7 +26,7 @@
= note: statics and constants must have a statically known size
error[E0277]: the size for values of type `str` cannot be known at compilation time
- --> $DIR/const-unsized.rs:15:1
+ --> $DIR/const-unsized.rs:14:1
|
LL | static STATIC_BAR: str = *"bar";
| ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -46,31 +46,7 @@
LL | const CONST_FOO: str = *"foo";
| ^^^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait
-error[E0507]: cannot move out of a shared reference
- --> $DIR/const-unsized.rs:11:37
- |
-LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `dyn Debug + Sync`, which does not implement the `Copy` trait
+error: aborting due to 6 previous errors
-error[E0507]: cannot move out of a shared reference
- --> $DIR/const-unsized.rs:15:26
- |
-LL | static STATIC_BAR: str = *"bar";
- | ^^^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait
-
-error[E0161]: cannot move a value of type `dyn Debug + Sync`
- --> $DIR/const-unsized.rs:20:38
- |
-LL | println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR);
- | ^^^^^^^ the size of `dyn Debug + Sync` cannot be statically determined
-
-error[E0161]: cannot move a value of type `str`
- --> $DIR/const-unsized.rs:20:48
- |
-LL | println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR);
- | ^^^^^^^^^ the size of `str` cannot be statically determined
-
-error: aborting due to 10 previous errors
-
-Some errors have detailed explanations: E0161, E0277, E0507.
-For more information about an error, try `rustc --explain E0161`.
+Some errors have detailed explanations: E0277, E0507.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs
index db2d50f..8c21f7b 100644
--- a/tests/ui/consts/const_cmp_type_id.rs
+++ b/tests/ui/consts/const_cmp_type_id.rs
@@ -1,3 +1,4 @@
+//@ ignore-backends: gcc
//@ compile-flags: -Znext-solver
#![feature(const_type_id, const_trait_impl, const_cmp)]
diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr
index 540eec5..05b94ca 100644
--- a/tests/ui/consts/const_cmp_type_id.stderr
+++ b/tests/ui/consts/const_cmp_type_id.stderr
@@ -1,5 +1,5 @@
error[E0015]: cannot call non-const operator in constants
- --> $DIR/const_cmp_type_id.rs:10:18
+ --> $DIR/const_cmp_type_id.rs:11:18
|
LL | let _a = TypeId::of::<u8>() < TypeId::of::<u16>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/consts/const_let_assign2.stderr b/tests/ui/consts/const_let_assign2.stderr
index 1bb5604..e8bed6d 100644
--- a/tests/ui/consts/const_let_assign2.stderr
+++ b/tests/ui/consts/const_let_assign2.stderr
@@ -4,7 +4,7 @@
LL | let ptr = unsafe { &mut BB };
| ^^^^^^^ mutable reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
= note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
= note: `#[warn(static_mut_refs)]` on by default
help: use `&raw mut` instead to create a raw pointer
diff --git a/tests/ui/consts/const_refs_to_static-ice-121413.stderr b/tests/ui/consts/const_refs_to_static-ice-121413.stderr
index 1263dee..e354110 100644
--- a/tests/ui/consts/const_refs_to_static-ice-121413.stderr
+++ b/tests/ui/consts/const_refs_to_static-ice-121413.stderr
@@ -16,7 +16,7 @@
| ^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/consts/issue-73976-monomorphic.rs b/tests/ui/consts/issue-73976-monomorphic.rs
index 5f364cd..f43823f 100644
--- a/tests/ui/consts/issue-73976-monomorphic.rs
+++ b/tests/ui/consts/issue-73976-monomorphic.rs
@@ -1,3 +1,4 @@
+//@ ignore-backends: gcc
//@ check-pass
//
// This test is complement to the test in issue-73976-polymorphic.rs.
diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs
index 22791e7..f2ddc92 100644
--- a/tests/ui/consts/issue-94675.rs
+++ b/tests/ui/consts/issue-94675.rs
@@ -1,3 +1,5 @@
+//@ ignore-backends: gcc
+
#![feature(const_trait_impl)]
struct Foo<'a> {
diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr
index 608ce0c..d7664de 100644
--- a/tests/ui/consts/issue-94675.stderr
+++ b/tests/ui/consts/issue-94675.stderr
@@ -1,17 +1,17 @@
error[E0277]: the trait bound `Vec<usize>: [const] Index<_>` is not satisfied
- --> $DIR/issue-94675.rs:9:9
+ --> $DIR/issue-94675.rs:11:9
|
LL | self.bar[0] = baz.len();
| ^^^^^^^^^^^
error[E0277]: the trait bound `Vec<usize>: [const] IndexMut<usize>` is not satisfied
- --> $DIR/issue-94675.rs:9:9
+ --> $DIR/issue-94675.rs:11:9
|
LL | self.bar[0] = baz.len();
| ^^^^^^^^^^^
error[E0277]: the trait bound `Vec<usize>: [const] Index<usize>` is not satisfied
- --> $DIR/issue-94675.rs:9:9
+ --> $DIR/issue-94675.rs:11:9
|
LL | self.bar[0] = baz.len();
| ^^^^^^^^^^^
diff --git a/tests/ui/consts/issue-miri-1910.rs b/tests/ui/consts/issue-miri-1910.rs
index 6eae885..78587bb 100644
--- a/tests/ui/consts/issue-miri-1910.rs
+++ b/tests/ui/consts/issue-miri-1910.rs
@@ -1,3 +1,4 @@
+//@ ignore-backends: gcc
//@ error-pattern unable to turn pointer into raw bytes
//@ normalize-stderr: "alloc[0-9]+\+0x[a-z0-9]+" -> "ALLOC"
diff --git a/tests/ui/consts/issue-miri-1910.stderr b/tests/ui/consts/issue-miri-1910.stderr
index 140b186..2b6e079 100644
--- a/tests/ui/consts/issue-miri-1910.stderr
+++ b/tests/ui/consts/issue-miri-1910.stderr
@@ -1,5 +1,5 @@
error[E0080]: unable to turn pointer into integer
- --> $DIR/issue-miri-1910.rs:7:5
+ --> $DIR/issue-miri-1910.rs:8:5
|
LL | (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `C` failed here
diff --git a/tests/ui/consts/missing_span_in_backtrace.rs b/tests/ui/consts/missing_span_in_backtrace.rs
index 893dc32..4f3f9aa 100644
--- a/tests/ui/consts/missing_span_in_backtrace.rs
+++ b/tests/ui/consts/missing_span_in_backtrace.rs
@@ -1,3 +1,4 @@
+//@ ignore-backends: gcc
//@ compile-flags: -Z ui-testing=no
use std::{
diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr
index de4acbf..0ac1e28 100644
--- a/tests/ui/consts/missing_span_in_backtrace.stderr
+++ b/tests/ui/consts/missing_span_in_backtrace.stderr
@@ -1,11 +1,11 @@
error[E0080]: unable to copy parts of a pointer from memory at ALLOC0
- --> $DIR/missing_span_in_backtrace.rs:14:9
+ --> $DIR/missing_span_in_backtrace.rs:15:9
|
-14 | / ptr::swap_nonoverlapping(
-15 | | &mut ptr1 as *mut _ as *mut MaybeUninit<u8>,
-16 | | &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
-17 | | mem::size_of::<&i32>(),
-18 | | );
+15 | / ptr::swap_nonoverlapping(
+16 | | &mut ptr1 as *mut _ as *mut MaybeUninit<u8>,
+17 | | &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
+18 | | mem::size_of::<&i32>(),
+19 | | );
| |_________^ evaluation of `X` failed inside this call
|
= help: this code performed an operation that depends on the underlying bytes representing a pointer
diff --git a/tests/ui/consts/try-operator.rs b/tests/ui/consts/try-operator.rs
index 59d9fcb..cd0bf8e 100644
--- a/tests/ui/consts/try-operator.rs
+++ b/tests/ui/consts/try-operator.rs
@@ -1,3 +1,4 @@
+//@ ignore-backends: gcc
//@ run-pass
#![feature(try_trait_v2)]
diff --git a/tests/ui/coroutine/layout-error.rs b/tests/ui/coroutine/layout-error.rs
index 6cf3213..7f67145 100644
--- a/tests/ui/coroutine/layout-error.rs
+++ b/tests/ui/coroutine/layout-error.rs
@@ -17,6 +17,7 @@ fn spawn(&self, _: impl FnOnce() -> F) {
}
pub type F = impl Future;
+
#[define_opaque(F)]
fn foo()
where
diff --git a/tests/ui/coroutine/layout-error.stderr b/tests/ui/coroutine/layout-error.stderr
index 91e3521..f3b3843 100644
--- a/tests/ui/coroutine/layout-error.stderr
+++ b/tests/ui/coroutine/layout-error.stderr
@@ -1,5 +1,5 @@
error[E0425]: cannot find value `Foo` in this scope
- --> $DIR/layout-error.rs:26:17
+ --> $DIR/layout-error.rs:27:17
|
LL | let a = Foo;
| ^^^ not found in this scope
diff --git a/tests/ui/coroutine/panic-drops-resume.rs b/tests/ui/coroutine/panic-drops-resume.rs
index b23666b..ee58dab 100644
--- a/tests/ui/coroutine/panic-drops-resume.rs
+++ b/tests/ui/coroutine/panic-drops-resume.rs
@@ -2,6 +2,7 @@
//@ run-pass
//@ needs-unwind
+//@ ignore-backends: gcc
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
diff --git a/tests/ui/coroutine/panic-drops.rs b/tests/ui/coroutine/panic-drops.rs
index 8c2cf56..c8ac401 100644
--- a/tests/ui/coroutine/panic-drops.rs
+++ b/tests/ui/coroutine/panic-drops.rs
@@ -1,5 +1,6 @@
//@ run-pass
//@ needs-unwind
+//@ ignore-backends: gcc
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
diff --git a/tests/ui/coroutine/panic-safe.rs b/tests/ui/coroutine/panic-safe.rs
index 6b9b4cb..cee2afa 100644
--- a/tests/ui/coroutine/panic-safe.rs
+++ b/tests/ui/coroutine/panic-safe.rs
@@ -1,6 +1,6 @@
//@ run-pass
//@ needs-unwind
-
+//@ ignore-backends: gcc
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
diff --git a/tests/ui/coroutine/postfix-yield-after-cast.rs b/tests/ui/coroutine/postfix-yield-after-cast.rs
new file mode 100644
index 0000000..472efb9
--- /dev/null
+++ b/tests/ui/coroutine/postfix-yield-after-cast.rs
@@ -0,0 +1,10 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/144527>.
+
+#![feature(yield_expr, coroutines)]
+
+fn main() {
+ #[coroutine] || {
+ 0 as u8.yield
+ //~^ ERROR cast cannot be followed by `.yield`
+ };
+}
diff --git a/tests/ui/coroutine/postfix-yield-after-cast.stderr b/tests/ui/coroutine/postfix-yield-after-cast.stderr
new file mode 100644
index 0000000..a4de064
--- /dev/null
+++ b/tests/ui/coroutine/postfix-yield-after-cast.stderr
@@ -0,0 +1,13 @@
+error: cast cannot be followed by `.yield`
+ --> $DIR/postfix-yield-after-cast.rs:7:9
+ |
+LL | 0 as u8.yield
+ | ^^^^^^^
+ |
+help: try surrounding the expression in parentheses
+ |
+LL | (0 as u8).yield
+ | + +
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/coroutine/resume-after-return.rs b/tests/ui/coroutine/resume-after-return.rs
index 7028e1e..f566bd3 100644
--- a/tests/ui/coroutine/resume-after-return.rs
+++ b/tests/ui/coroutine/resume-after-return.rs
@@ -1,3 +1,4 @@
+//@ ignore-backends: gcc
//@ run-pass
//@ needs-unwind
diff --git a/tests/ui/coroutine/unwind-abort-mix.rs b/tests/ui/coroutine/unwind-abort-mix.rs
index 517c661..175c292 100644
--- a/tests/ui/coroutine/unwind-abort-mix.rs
+++ b/tests/ui/coroutine/unwind-abort-mix.rs
@@ -6,6 +6,7 @@
//@ aux-build:unwind-aux.rs
//@ compile-flags: -Cpanic=abort
//@ needs-unwind
+//@ ignore-backends: gcc
extern crate unwind_aux;
pub fn main() {
diff --git a/tests/ui/issues/auxiliary/issue-2472-b.rs b/tests/ui/cross-crate/auxiliary/exporting-impl-from-root-causes-ice-2472-b.rs
similarity index 100%
rename from tests/ui/issues/auxiliary/issue-2472-b.rs
rename to tests/ui/cross-crate/auxiliary/exporting-impl-from-root-causes-ice-2472-b.rs
diff --git a/tests/ui/cross-crate/exporting-impl-from-root-causes-ice-2472.rs b/tests/ui/cross-crate/exporting-impl-from-root-causes-ice-2472.rs
new file mode 100644
index 0000000..86d637b
--- /dev/null
+++ b/tests/ui/cross-crate/exporting-impl-from-root-causes-ice-2472.rs
@@ -0,0 +1,15 @@
+//@ run-pass
+//@ aux-build:exporting-impl-from-root-causes-ice-2472-b.rs
+
+
+extern crate exporting_impl_from_root_causes_ice_2472_b as lib;
+
+use lib::{S, T};
+
+pub fn main() {
+ let s = S(());
+ s.foo();
+ s.bar();
+}
+
+// https://github.com/rust-lang/rust/issues/2472
diff --git a/tests/ui/delegation/fn-header.rs b/tests/ui/delegation/fn-header.rs
index 9de0d54..608aef8 100644
--- a/tests/ui/delegation/fn-header.rs
+++ b/tests/ui/delegation/fn-header.rs
@@ -1,6 +1,7 @@
//@ check-pass
//@ edition:2018
//@ aux-crate:fn_header_aux=fn-header-aux.rs
+//@ ignore-backends: gcc
#![feature(c_variadic)]
#![feature(fn_delegation)]
diff --git a/tests/ui/issues/issue-34229.rs b/tests/ui/derives/invalid-derive-comparison-34229.rs
similarity index 74%
rename from tests/ui/issues/issue-34229.rs
rename to tests/ui/derives/invalid-derive-comparison-34229.rs
index 13e627a..d77ca78 100644
--- a/tests/ui/issues/issue-34229.rs
+++ b/tests/ui/derives/invalid-derive-comparison-34229.rs
@@ -3,3 +3,5 @@
//~^ ERROR can't compare `Comparable`
fn main() {}
+
+// https://github.com/rust-lang/rust/issues/34229
diff --git a/tests/ui/issues/issue-34229.stderr b/tests/ui/derives/invalid-derive-comparison-34229.stderr
similarity index 92%
rename from tests/ui/issues/issue-34229.stderr
rename to tests/ui/derives/invalid-derive-comparison-34229.stderr
index 2385284..e3a9970 100644
--- a/tests/ui/issues/issue-34229.stderr
+++ b/tests/ui/derives/invalid-derive-comparison-34229.stderr
@@ -1,5 +1,5 @@
error[E0277]: can't compare `Comparable` with `Comparable`
- --> $DIR/issue-34229.rs:2:46
+ --> $DIR/invalid-derive-comparison-34229.rs:2:46
|
LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable);
| ---------- ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable`
diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/deriving/built-in-proc-macro-scope.stdout
index 2697618..4fbce5e 100644
--- a/tests/ui/deriving/built-in-proc-macro-scope.stdout
+++ b/tests/ui/deriving/built-in-proc-macro-scope.stdout
@@ -6,10 +6,10 @@
//@ edition:2015
#![feature(derive_coerce_pointee)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate another_proc_macro;
diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout
index fa8f249..0e4bfa3 100644
--- a/tests/ui/deriving/deriving-all-codegen.stdout
+++ b/tests/ui/deriving/deriving-all-codegen.stdout
@@ -17,10 +17,10 @@
#![crate_type = "lib"]
#![allow(dead_code)]
#![allow(deprecated)]
-#[prelude_import]
-use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use std::prelude::rust_2021::*;
// Empty struct.
struct Empty;
diff --git a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
index 84f8e9a..89300a5 100644
--- a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
+++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
@@ -4,10 +4,10 @@
//@ compile-flags: -Zunpretty=expanded
//@ edition: 2015
#![feature(derive_coerce_pointee)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
use std::marker::CoercePointee;
pub trait MyTrait<T: ?Sized> {}
diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.stdout b/tests/ui/deriving/proc-macro-attribute-mixing.stdout
index faa9c02..b811106 100644
--- a/tests/ui/deriving/proc-macro-attribute-mixing.stdout
+++ b/tests/ui/deriving/proc-macro-attribute-mixing.stdout
@@ -12,10 +12,10 @@
//@ edition: 2015
#![feature(derive_coerce_pointee)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate another_proc_macro;
diff --git a/tests/ui/issues/issue-106755.rs b/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.rs
similarity index 88%
copy from tests/ui/issues/issue-106755.rs
copy to tests/ui/diagnostics-infra/primary-fluent-bundle-missing.rs
index d7e7122..f296577 100644
--- a/tests/ui/issues/issue-106755.rs
+++ b/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/106755
+
//@ compile-flags:-Ztranslate-lang=en_US
#![feature(negative_impls)]
diff --git a/tests/ui/issues/issue-106755.stderr b/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.stderr
similarity index 84%
rename from tests/ui/issues/issue-106755.stderr
rename to tests/ui/diagnostics-infra/primary-fluent-bundle-missing.stderr
index da6b8c5..1dc31e1 100644
--- a/tests/ui/issues/issue-106755.stderr
+++ b/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.stderr
@@ -1,5 +1,5 @@
error[E0751]: found both positive and negative implementation of trait `Send` for type `TestType<_>`:
- --> $DIR/issue-106755.rs:13:1
+ --> $DIR/primary-fluent-bundle-missing.rs:15:1
|
LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
| ------------------------------------------------------ positive implementation here
@@ -8,7 +8,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here
error[E0119]: conflicting implementations of trait `Send` for type `TestType<_>`
- --> $DIR/issue-106755.rs:17:1
+ --> $DIR/primary-fluent-bundle-missing.rs:19:1
|
LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
| ------------------------------------------------------ first implementation here
@@ -17,26 +17,26 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>`
error[E0367]: `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not
- --> $DIR/issue-106755.rs:13:9
+ --> $DIR/primary-fluent-bundle-missing.rs:15:9
|
LL | impl<T: MyTrait> !Send for TestType<T> {}
| ^^^^^^^
|
note: the implementor must specify the same requirement
- --> $DIR/issue-106755.rs:9:1
+ --> $DIR/primary-fluent-bundle-missing.rs:11:1
|
LL | struct TestType<T>(::std::marker::PhantomData<T>);
| ^^^^^^^^^^^^^^^^^^
error[E0366]: `!Send` impls cannot be specialized
- --> $DIR/issue-106755.rs:19:1
+ --> $DIR/primary-fluent-bundle-missing.rs:21:1
|
LL | impl !Send for TestType<i32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `i32` is not a generic parameter
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
- --> $DIR/issue-106755.rs:9:1
+ --> $DIR/primary-fluent-bundle-missing.rs:11:1
|
LL | struct TestType<T>(::std::marker::PhantomData<T>);
| ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr b/tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr
index ed6e5c3..416ff35 100644
--- a/tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr
+++ b/tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr
@@ -186,7 +186,7 @@
| ^^^^^^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/issues/issue-10734.rs b/tests/ui/drop/conditional-drop-10734.rs
similarity index 92%
rename from tests/ui/issues/issue-10734.rs
rename to tests/ui/drop/conditional-drop-10734.rs
index 6d815ae..25f492b 100644
--- a/tests/ui/issues/issue-10734.rs
+++ b/tests/ui/drop/conditional-drop-10734.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10734
+
//@ run-pass
#![allow(non_upper_case_globals)]
diff --git a/tests/ui/issues/issue-9446.rs b/tests/ui/drop/drop-immediate-non-box-ty-9446.rs
similarity index 91%
rename from tests/ui/issues/issue-9446.rs
rename to tests/ui/drop/drop-immediate-non-box-ty-9446.rs
index a6ea91e..ad3f7b6 100644
--- a/tests/ui/issues/issue-9446.rs
+++ b/tests/ui/drop/drop-immediate-non-box-ty-9446.rs
@@ -28,3 +28,5 @@ pub fn main() {
Wrapper::new("Bob".to_string()).say_hi();
}
}
+
+// https://github.com/rust-lang/rust/issues/9446
diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr
index 15a3f27..d928403 100644
--- a/tests/ui/drop/drop-order-comparisons.e2021.stderr
+++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr
@@ -27,7 +27,7 @@
| `#1` will be dropped later as of Edition 2024
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: `#3` invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -75,7 +75,7 @@
| `#1` will be dropped later as of Edition 2024
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: `#2` invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -107,7 +107,7 @@
| `#1` will be dropped later as of Edition 2024
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: `#2` invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -139,7 +139,7 @@
| `#1` will be dropped later as of Edition 2024
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: `#2` invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -171,7 +171,7 @@
| `#1` will be dropped later as of Edition 2024
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: `#2` invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -193,7 +193,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -223,7 +223,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -252,7 +252,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -281,7 +281,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -310,7 +310,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -339,7 +339,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -368,7 +368,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -397,7 +397,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -426,7 +426,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
@@ -455,7 +455,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/drop-order-comparisons.rs:504:1
|
diff --git a/tests/ui/drop/dynamic-drop-async.rs b/tests/ui/drop/dynamic-drop-async.rs
index e7a32d3..64de699 100644
--- a/tests/ui/drop/dynamic-drop-async.rs
+++ b/tests/ui/drop/dynamic-drop-async.rs
@@ -6,6 +6,7 @@
//@ run-pass
//@ needs-unwind
//@ edition:2018
+//@ ignore-backends: gcc
#![allow(unused)]
diff --git a/tests/ui/drop/dynamic-drop.rs b/tests/ui/drop/dynamic-drop.rs
index b695b57..1bd75e1 100644
--- a/tests/ui/drop/dynamic-drop.rs
+++ b/tests/ui/drop/dynamic-drop.rs
@@ -1,5 +1,6 @@
//@ run-pass
//@ needs-unwind
+//@ ignore-backends: gcc
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
#![feature(if_let_guard)]
diff --git a/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr
index 0d6974d..5f04273 100644
--- a/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr
+++ b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr
@@ -7,7 +7,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/lint-if-let-rescope-gated.rs:14:1
|
diff --git a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
index a0afb8e..63e30f1 100644
--- a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
+++ b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
@@ -14,7 +14,7 @@
| |_____- in this macro invocation
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/lint-if-let-rescope-with-macro.rs:22:1
|
diff --git a/tests/ui/drop/lint-if-let-rescope.stderr b/tests/ui/drop/lint-if-let-rescope.stderr
index ca2416e..7cab733 100644
--- a/tests/ui/drop/lint-if-let-rescope.stderr
+++ b/tests/ui/drop/lint-if-let-rescope.stderr
@@ -7,7 +7,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/lint-if-let-rescope.rs:11:1
|
@@ -47,7 +47,7 @@
| -------- this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/lint-if-let-rescope.rs:11:1
|
@@ -89,7 +89,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/lint-if-let-rescope.rs:11:1
|
@@ -120,7 +120,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/lint-if-let-rescope.rs:11:1
|
@@ -146,7 +146,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/lint-if-let-rescope.rs:11:1
|
@@ -172,7 +172,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/lint-if-let-rescope.rs:11:1
|
@@ -198,7 +198,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
note: value invokes this custom destructor
--> $DIR/lint-if-let-rescope.rs:11:1
|
@@ -224,7 +224,7 @@
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html>
help: the value is now dropped here in Edition 2024
--> $DIR/lint-if-let-rescope.rs:97:51
|
diff --git a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr
index a55e366..2eeda8a 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr
+++ b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr
@@ -7,7 +7,7 @@
| this temporary value will be dropped at the end of the block
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: the lint level is defined here
--> $DIR/lint-tail-expr-drop-order-borrowck.rs:6:9
|
@@ -23,7 +23,7 @@
| this temporary value will be dropped at the end of the block
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
error: relative drop order changing in Rust 2024
--> $DIR/lint-tail-expr-drop-order-borrowck.rs:31:9
@@ -35,7 +35,7 @@
| borrow later used here
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
error: relative drop order changing in Rust 2024
--> $DIR/lint-tail-expr-drop-order-borrowck.rs:43:9
@@ -46,7 +46,7 @@
| borrow later used by call
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
error: aborting due to 4 previous errors
diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr
index e124e98..c69c58a 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order.stderr
+++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr
@@ -17,7 +17,7 @@
| - now the temporary value is dropped here, before the local variables in the block or statement
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: `#1` invokes this custom destructor
--> $DIR/lint-tail-expr-drop-order.rs:10:1
|
@@ -54,7 +54,7 @@
| - now the temporary value is dropped here, before the local variables in the block or statement
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: `#1` invokes this custom destructor
--> $DIR/lint-tail-expr-drop-order.rs:10:1
|
@@ -86,7 +86,7 @@
| - now the temporary value is dropped here, before the local variables in the block or statement
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: `#1` invokes this custom destructor
--> $DIR/lint-tail-expr-drop-order.rs:10:1
|
@@ -118,7 +118,7 @@
| - now the temporary value is dropped here, before the local variables in the block or statement
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: `#1` invokes this custom destructor
--> $DIR/lint-tail-expr-drop-order.rs:10:1
|
@@ -145,7 +145,7 @@
| - now the temporary value is dropped here, before the local variables in the block or statement
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
= note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
error: relative drop order changing in Rust 2024
@@ -167,7 +167,7 @@
| - now the temporary value is dropped here, before the local variables in the block or statement
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: `#1` invokes this custom destructor
--> $DIR/lint-tail-expr-drop-order.rs:10:1
|
@@ -199,7 +199,7 @@
| - now the temporary value is dropped here, before the local variables in the block or statement
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: `#1` invokes this custom destructor
--> $DIR/lint-tail-expr-drop-order.rs:193:5
|
@@ -231,7 +231,7 @@
| - now the temporary value is dropped here, before the local variables in the block or statement
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: `#1` invokes this custom destructor
--> $DIR/lint-tail-expr-drop-order.rs:10:1
|
diff --git a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr
index 7bf452e..9497718 100644
--- a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr
+++ b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr
@@ -23,7 +23,7 @@
| - now the temporary value is dropped here, before the local variables in the block or statement
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/temporary-tail-expr-scope.html>
note: `#2` invokes this custom destructor
--> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:9:1
|
diff --git a/tests/ui/issues/issue-10802.rs b/tests/ui/drop/trait-object-drop-10802.rs
similarity index 92%
rename from tests/ui/issues/issue-10802.rs
rename to tests/ui/drop/trait-object-drop-10802.rs
index eca701c..a8a955a 100644
--- a/tests/ui/issues/issue-10802.rs
+++ b/tests/ui/drop/trait-object-drop-10802.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10802
+
//@ run-pass
#![allow(dead_code)]
diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr
index b811ef4..687799c 100644
--- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr
+++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr
@@ -5,7 +5,7 @@
| ^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
@@ -19,7 +19,7 @@
| ^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr
index 8b4f3f5..4cfac94 100644
--- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr
+++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr
@@ -5,7 +5,7 @@
| ^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
@@ -19,7 +19,7 @@
| ^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | trait B { fn f(a: A) -> dyn A; }
@@ -32,7 +32,7 @@
| ^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | trait A { fn g(b: dyn B) -> B; }
@@ -45,7 +45,7 @@
| ^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | trait A { fn g(b: B) -> dyn B; }
@@ -58,7 +58,7 @@
| ^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: if this is a dyn-compatible trait, use `dyn`
|
@@ -100,7 +100,7 @@
| ^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning.old.stderr
index dbfe91e..4645b35 100644
--- a/tests/ui/dyn-compatibility/avoid-ice-on-warning.old.stderr
+++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning.old.stderr
@@ -23,7 +23,7 @@
| ^^^^^^^^^^^^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr
index 7be6cb0..3cbdd19 100644
--- a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr
+++ b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr
@@ -5,7 +5,7 @@
| ^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
note: the lint level is defined here
--> $DIR/bare-trait-dont-suggest-dyn.rs:5:9
|
diff --git a/tests/ui/dyn-compatibility/taint-const-eval.rs b/tests/ui/dyn-compatibility/taint-const-eval.rs
index a5c01e1..3d1b3b8 100644
--- a/tests/ui/dyn-compatibility/taint-const-eval.rs
+++ b/tests/ui/dyn-compatibility/taint-const-eval.rs
@@ -6,6 +6,5 @@ trait Qux {
static FOO: &(dyn Qux + Sync) = "desc";
//~^ ERROR the trait `Qux` is not dyn compatible
-//~| ERROR the trait `Qux` is not dyn compatible
fn main() {}
diff --git a/tests/ui/dyn-compatibility/taint-const-eval.stderr b/tests/ui/dyn-compatibility/taint-const-eval.stderr
index 585c1f0..e4be987 100644
--- a/tests/ui/dyn-compatibility/taint-const-eval.stderr
+++ b/tests/ui/dyn-compatibility/taint-const-eval.stderr
@@ -21,30 +21,6 @@
LL | fn bar() where Self: Sized;
| +++++++++++++++++
-error[E0038]: the trait `Qux` is not dyn compatible
- --> $DIR/taint-const-eval.rs:7:15
- |
-LL | static FOO: &(dyn Qux + Sync) = "desc";
- | ^^^^^^^^^^^^^^ `Qux` is not dyn compatible
- |
-note: for a trait to be dyn compatible it needs to allow building a vtable
- for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
- --> $DIR/taint-const-eval.rs:4:8
- |
-LL | trait Qux {
- | --- this trait is not dyn compatible...
-LL | fn bar();
- | ^^^ ...because associated function `bar` has no `self` parameter
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: consider turning `bar` into a method by giving it a `&self` argument
- |
-LL | fn bar(&self);
- | +++++
-help: alternatively, consider constraining `bar` so it does not apply to trait objects
- |
-LL | fn bar() where Self: Sized;
- | +++++++++++++++++
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/dyn-keyword/dyn-2018-edition-lint.stderr b/tests/ui/dyn-keyword/dyn-2018-edition-lint.stderr
index b930815..b034c5d 100644
--- a/tests/ui/dyn-keyword/dyn-2018-edition-lint.stderr
+++ b/tests/ui/dyn-keyword/dyn-2018-edition-lint.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
note: the lint level is defined here
--> $DIR/dyn-2018-edition-lint.rs:2:8
|
@@ -23,7 +23,7 @@
| ^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | fn function(x: &SomeTrait, y: Box<dyn SomeTrait>) {
@@ -36,7 +36,7 @@
| ^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | let _x: &dyn SomeTrait = todo!();
diff --git a/tests/ui/dyn-keyword/dyn-angle-brackets.stderr b/tests/ui/dyn-keyword/dyn-angle-brackets.stderr
index 6a29dab..3006963 100644
--- a/tests/ui/dyn-keyword/dyn-angle-brackets.stderr
+++ b/tests/ui/dyn-keyword/dyn-angle-brackets.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
note: the lint level is defined here
--> $DIR/dyn-angle-brackets.rs:4:9
|
diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs
index f8d2755..df47394 100644
--- a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs
+++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs
@@ -26,7 +26,7 @@ pub fn check_async() {
module::async(); //~ ERROR expected identifier, found keyword `async`
module::r#async(); // OK
- let _recovery_witness: () = 0; //~ ERROR mismatched types
+ let _recovery_witness: () = 0; // not emitted because of the macro parsing error
}
//~? ERROR macro expansion ends with an incomplete expression
diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
index 34f5c7d..4d69df9 100644
--- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
@@ -61,14 +61,5 @@
LL | if passes_tt!(async) == 1 {}
| ^ expected one of `move`, `use`, `{`, `|`, or `||`
-error[E0308]: mismatched types
- --> $DIR/edition-keywords-2018-2015-parsing.rs:29:33
- |
-LL | let _recovery_witness: () = 0;
- | -- ^ expected `()`, found integer
- | |
- | expected due to this
+error: aborting due to 6 previous errors
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs
index f443847..34aaf16 100644
--- a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs
+++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs
@@ -36,8 +36,6 @@ pub fn check_async() {
if local_passes_tt!(r#async) == 1 {} // OK
module::async(); //~ ERROR expected identifier, found keyword `async`
module::r#async(); // OK
-
- let _recovery_witness: () = 0; //~ ERROR mismatched types
}
//~? ERROR macro expansion ends with an incomplete expression
diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
index dd3f493..753dac6 100644
--- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
@@ -73,14 +73,5 @@
LL | if local_passes_tt!(async) == 1 {}
| ^ expected one of `move`, `use`, `{`, `|`, or `||`
-error[E0308]: mismatched types
- --> $DIR/edition-keywords-2018-2018-parsing.rs:40:33
- |
-LL | let _recovery_witness: () = 0;
- | -- ^ expected `()`, found integer
- | |
- | expected due to this
+error: aborting due to 8 previous errors
-error: aborting due to 9 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr
index 6b84a64..e30c0ad 100644
--- a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr
+++ b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr
@@ -5,7 +5,7 @@
| ^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/never-type-fallback-breaking.rs:22:17
@@ -25,7 +25,7 @@
| ^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/never-type-fallback-breaking.rs:37:5
@@ -44,7 +44,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `(): From<!>` will fail
--> $DIR/never-type-fallback-breaking.rs:50:5
@@ -63,7 +63,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/never-type-fallback-breaking.rs:62:19
@@ -82,7 +82,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/never-type-fallback-breaking.rs:76:17
@@ -104,7 +104,7 @@
| ^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/never-type-fallback-breaking.rs:22:17
@@ -125,7 +125,7 @@
| ^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/never-type-fallback-breaking.rs:37:5
@@ -146,7 +146,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `(): From<!>` will fail
--> $DIR/never-type-fallback-breaking.rs:50:5
@@ -167,7 +167,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/never-type-fallback-breaking.rs:62:19
@@ -188,7 +188,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/never-type-fallback-breaking.rs:76:17
diff --git a/tests/ui/entry-point/auxiliary/main_functions.rs b/tests/ui/entry-point/auxiliary/main_functions.rs
index cc7992a..ab4a09b 100644
--- a/tests/ui/entry-point/auxiliary/main_functions.rs
+++ b/tests/ui/entry-point/auxiliary/main_functions.rs
@@ -1 +1,4 @@
pub fn boilerplate() {}
+
+#[inline]
+pub fn local_codegen() {}
diff --git a/tests/ui/entry-point/imported_main_local_codegen.rs b/tests/ui/entry-point/imported_main_local_codegen.rs
new file mode 100644
index 0000000..1e46c10
--- /dev/null
+++ b/tests/ui/entry-point/imported_main_local_codegen.rs
@@ -0,0 +1,11 @@
+//@ run-pass
+//@ aux-build:main_functions.rs
+//@ compile-flags: -Ccodegen-units=1024
+
+// This is a regression test for https://github.com/rust-lang/rust/issues/144052.
+// Entrypoint functions call each other in ways that CGU partitioning doesn't know about. So there
+// is a special check to not internalize any of them. But internalizing them can be okay if there
+// are few enough CGUs, so we use a lot of CGUs in this test to hit the bad case.
+
+extern crate main_functions;
+pub use main_functions::local_codegen as main;
diff --git a/tests/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs b/tests/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs
index a6e5f70..6bbafbf 100644
--- a/tests/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs
+++ b/tests/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs
@@ -1,8 +1,17 @@
-#![crate_type="lib"]
+#![crate_type = "lib"]
+// Test that if any variant is non-unit,
+// we need a repr.
enum Enum {
-//~^ ERROR `#[repr(inttype)]` must be specified
- Unit = 1,
- Tuple() = 2,
- Struct{} = 3,
+ //~^ ERROR `#[repr(inttype)]` must be specified
+ Unit = 1,
+ Tuple(),
+ Struct {},
+}
+
+// Test that if any non-unit variant has an explicit
+// discriminant we need a repr.
+enum Enum2 {
+ //~^ ERROR `#[repr(inttype)]` must be specified
+ Tuple() = 2,
}
diff --git a/tests/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr b/tests/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr
index 3b718c6..35c0208 100644
--- a/tests/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr
+++ b/tests/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr
@@ -1,9 +1,23 @@
-error[E0732]: `#[repr(inttype)]` must be specified
- --> $DIR/arbitrary_enum_discriminant-no-repr.rs:3:1
+error[E0732]: `#[repr(inttype)]` must be specified for enums with explicit discriminants and non-unit variants
+ --> $DIR/arbitrary_enum_discriminant-no-repr.rs:5:1
|
LL | enum Enum {
| ^^^^^^^^^
+LL |
+LL | Unit = 1,
+ | - explicit discriminant specified here
+LL | Tuple(),
+ | ----- non-unit discriminant declared here
-error: aborting due to 1 previous error
+error[E0732]: `#[repr(inttype)]` must be specified for enums with explicit discriminants and non-unit variants
+ --> $DIR/arbitrary_enum_discriminant-no-repr.rs:14:1
+ |
+LL | enum Enum2 {
+ | ^^^^^^^^^^
+LL |
+LL | Tuple() = 2,
+ | - explicit discriminant on non-unit variant specified here
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0732`.
diff --git a/tests/ui/enum-discriminant/wrapping_niche.rs b/tests/ui/enum-discriminant/wrapping_niche.rs
new file mode 100644
index 0000000..8097414
--- /dev/null
+++ b/tests/ui/enum-discriminant/wrapping_niche.rs
@@ -0,0 +1,24 @@
+//! Test that we produce the same niche range no
+//! matter of signendess if the discriminants are the same.
+
+#![feature(rustc_attrs)]
+
+#[repr(u16)]
+#[rustc_layout(debug)]
+enum UnsignedAroundZero {
+ //~^ ERROR: layout_of
+ A = 65535,
+ B = 0,
+ C = 1,
+}
+
+#[repr(i16)]
+#[rustc_layout(debug)]
+enum SignedAroundZero {
+ //~^ ERROR: layout_of
+ A = -1,
+ B = 0,
+ C = 1,
+}
+
+fn main() {}
diff --git a/tests/ui/enum-discriminant/wrapping_niche.stderr b/tests/ui/enum-discriminant/wrapping_niche.stderr
new file mode 100644
index 0000000..e3e1755
--- /dev/null
+++ b/tests/ui/enum-discriminant/wrapping_niche.stderr
@@ -0,0 +1,238 @@
+error: layout_of(UnsignedAroundZero) = Layout {
+ size: Size(2 bytes),
+ align: AbiAlign {
+ abi: Align(2 bytes),
+ },
+ backend_repr: Scalar(
+ Initialized {
+ value: Int(
+ I16,
+ false,
+ ),
+ valid_range: (..=1) | (65535..),
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I16,
+ false,
+ ),
+ valid_range: (..=1) | (65535..),
+ },
+ ),
+ uninhabited: false,
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I16,
+ false,
+ ),
+ valid_range: (..=1) | (65535..),
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAlign {
+ abi: Align(2 bytes),
+ },
+ backend_repr: Memory {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ uninhabited: false,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: Align(2 bytes),
+ randomization_seed: 9885373149222004003,
+ },
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAlign {
+ abi: Align(2 bytes),
+ },
+ backend_repr: Memory {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ uninhabited: false,
+ variants: Single {
+ index: 1,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: Align(2 bytes),
+ randomization_seed: 9885373149222004003,
+ },
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAlign {
+ abi: Align(2 bytes),
+ },
+ backend_repr: Memory {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ uninhabited: false,
+ variants: Single {
+ index: 2,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: Align(2 bytes),
+ randomization_seed: 9885373149222004003,
+ },
+ ],
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: Align(2 bytes),
+ randomization_seed: 2648004449468912780,
+ }
+ --> $DIR/wrapping_niche.rs:8:1
+ |
+LL | enum UnsignedAroundZero {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: layout_of(SignedAroundZero) = Layout {
+ size: Size(2 bytes),
+ align: AbiAlign {
+ abi: Align(2 bytes),
+ },
+ backend_repr: Scalar(
+ Initialized {
+ value: Int(
+ I16,
+ true,
+ ),
+ valid_range: (..=1) | (65535..),
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I16,
+ true,
+ ),
+ valid_range: (..=1) | (65535..),
+ },
+ ),
+ uninhabited: false,
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I16,
+ true,
+ ),
+ valid_range: (..=1) | (65535..),
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAlign {
+ abi: Align(2 bytes),
+ },
+ backend_repr: Memory {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ uninhabited: false,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: Align(2 bytes),
+ randomization_seed: 2684536712112553499,
+ },
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAlign {
+ abi: Align(2 bytes),
+ },
+ backend_repr: Memory {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ uninhabited: false,
+ variants: Single {
+ index: 1,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: Align(2 bytes),
+ randomization_seed: 2684536712112553499,
+ },
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAlign {
+ abi: Align(2 bytes),
+ },
+ backend_repr: Memory {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ uninhabited: false,
+ variants: Single {
+ index: 2,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: Align(2 bytes),
+ randomization_seed: 2684536712112553499,
+ },
+ ],
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: Align(2 bytes),
+ randomization_seed: 10738146848450213996,
+ }
+ --> $DIR/wrapping_niche.rs:17:1
+ |
+LL | enum SignedAroundZero {
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/issues/issue-32326.rs b/tests/ui/enum/recursive-enum-memory-32326.rs
similarity index 81%
rename from tests/ui/issues/issue-32326.rs
rename to tests/ui/enum/recursive-enum-memory-32326.rs
index e928c66..6b8b04a 100644
--- a/tests/ui/issues/issue-32326.rs
+++ b/tests/ui/enum/recursive-enum-memory-32326.rs
@@ -8,3 +8,5 @@ enum Expr { //~ ERROR E0072
}
fn main() { }
+
+// https://github.com/rust-lang/rust/issues/32326
diff --git a/tests/ui/issues/issue-32326.stderr b/tests/ui/enum/recursive-enum-memory-32326.stderr
similarity index 89%
rename from tests/ui/issues/issue-32326.stderr
rename to tests/ui/enum/recursive-enum-memory-32326.stderr
index 1989a91..0260a67 100644
--- a/tests/ui/issues/issue-32326.stderr
+++ b/tests/ui/enum/recursive-enum-memory-32326.stderr
@@ -1,5 +1,5 @@
error[E0072]: recursive type `Expr` has infinite size
- --> $DIR/issue-32326.rs:5:1
+ --> $DIR/recursive-enum-memory-32326.rs:5:1
|
LL | enum Expr {
| ^^^^^^^^^
diff --git a/tests/ui/ergonomic-clones/closure/rfc2229-migration.stderr b/tests/ui/ergonomic-clones/closure/rfc2229-migration.stderr
index b980be6..f4f3e51 100644
--- a/tests/ui/ergonomic-clones/closure/rfc2229-migration.stderr
+++ b/tests/ui/ergonomic-clones/closure/rfc2229-migration.stderr
@@ -10,7 +10,7 @@
LL | }
| - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/disjoint-capture-in-closures.html>
note: the lint level is defined here
--> $DIR/rfc2229-migration.rs:5:9
|
diff --git a/tests/ui/errors/dynless-turbofish-e0191-issue-91997.stderr b/tests/ui/errors/dynless-turbofish-e0191-issue-91997.stderr
index 7f3022c..0004ea8 100644
--- a/tests/ui/errors/dynless-turbofish-e0191-issue-91997.stderr
+++ b/tests/ui/errors/dynless-turbofish-e0191-issue-91997.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/errors/remap-path-prefix-sysroot.rs b/tests/ui/errors/remap-path-prefix-sysroot.rs
index 5e2e4fa..f4a2766 100644
--- a/tests/ui/errors/remap-path-prefix-sysroot.rs
+++ b/tests/ui/errors/remap-path-prefix-sysroot.rs
@@ -2,7 +2,7 @@
//@ compile-flags: -g -Ztranslate-remapped-path-to-local-path=yes
//@ [with-remap]compile-flags: --remap-path-prefix={{rust-src-base}}=remapped
//@ [with-remap]compile-flags: --remap-path-prefix={{src-base}}=remapped-tests-ui
-//@ [without-remap]compile-flags:
+// [without-remap] no extra compile-flags
// The $SRC_DIR*.rs:LL:COL normalisation doesn't kick in automatically
// as the remapped revision will not begin with $SRC_DIR_REAL,
diff --git a/tests/ui/errors/wrong-target-spec.rs b/tests/ui/errors/wrong-target-spec.rs
index a3a0e05..1a97688 100644
--- a/tests/ui/errors/wrong-target-spec.rs
+++ b/tests/ui/errors/wrong-target-spec.rs
@@ -2,6 +2,7 @@
// checks that such invalid target specs are rejected by the compiler.
// See https://github.com/rust-lang/rust/issues/33329
+// ignore-tidy-target-specific-tests
//@ needs-llvm-components: x86
//@ compile-flags: --target x86_64_unknown-linux-musl
diff --git a/tests/ui/extern/extern-rust-fn-type-error-10764.rs b/tests/ui/extern/extern-rust-fn-type-error-10764.rs
new file mode 100644
index 0000000..f172f6e
--- /dev/null
+++ b/tests/ui/extern/extern-rust-fn-type-error-10764.rs
@@ -0,0 +1,7 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10764
+
+fn f(_: extern "Rust" fn()) {}
+extern "C" fn bar() {}
+
+fn main() { f(bar) }
+//~^ ERROR mismatched types
diff --git a/tests/ui/issues/issue-10764.stderr b/tests/ui/extern/extern-rust-fn-type-error-10764.stderr
similarity index 82%
rename from tests/ui/issues/issue-10764.stderr
rename to tests/ui/extern/extern-rust-fn-type-error-10764.stderr
index f3bd010..fa72d7d 100644
--- a/tests/ui/issues/issue-10764.stderr
+++ b/tests/ui/extern/extern-rust-fn-type-error-10764.stderr
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
- --> $DIR/issue-10764.rs:4:15
+ --> $DIR/extern-rust-fn-type-error-10764.rs:6:15
|
LL | fn main() { f(bar) }
| - ^^^ expected "Rust" fn, found "C" fn
@@ -9,7 +9,7 @@
= note: expected fn pointer `fn()`
found fn item `extern "C" fn() {bar}`
note: function defined here
- --> $DIR/issue-10764.rs:1:4
+ --> $DIR/extern-rust-fn-type-error-10764.rs:3:4
|
LL | fn f(_: extern "Rust" fn()) {}
| ^ ---------------------
diff --git a/tests/ui/issues/issue-10877.rs b/tests/ui/extern/foreign-fn-pattern-error-10877.rs
similarity index 87%
rename from tests/ui/issues/issue-10877.rs
rename to tests/ui/extern/foreign-fn-pattern-error-10877.rs
index 15a3831..9a047d4 100644
--- a/tests/ui/issues/issue-10877.rs
+++ b/tests/ui/extern/foreign-fn-pattern-error-10877.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10877
+
struct Foo {
x: isize,
}
diff --git a/tests/ui/issues/issue-10877.stderr b/tests/ui/extern/foreign-fn-pattern-error-10877.stderr
similarity index 78%
rename from tests/ui/issues/issue-10877.stderr
rename to tests/ui/extern/foreign-fn-pattern-error-10877.stderr
index bd3797c..cab7b6a 100644
--- a/tests/ui/issues/issue-10877.stderr
+++ b/tests/ui/extern/foreign-fn-pattern-error-10877.stderr
@@ -1,23 +1,23 @@
error[E0130]: patterns aren't allowed in foreign function declarations
- --> $DIR/issue-10877.rs:5:12
+ --> $DIR/foreign-fn-pattern-error-10877.rs:7:12
|
LL | fn foo(1: ());
| ^ pattern not allowed in foreign function
error[E0130]: patterns aren't allowed in foreign function declarations
- --> $DIR/issue-10877.rs:7:12
+ --> $DIR/foreign-fn-pattern-error-10877.rs:9:12
|
LL | fn bar((): isize);
| ^^ pattern not allowed in foreign function
error[E0130]: patterns aren't allowed in foreign function declarations
- --> $DIR/issue-10877.rs:9:12
+ --> $DIR/foreign-fn-pattern-error-10877.rs:11:12
|
LL | fn baz(Foo { x }: isize);
| ^^^^^^^^^ pattern not allowed in foreign function
error[E0130]: patterns aren't allowed in foreign function declarations
- --> $DIR/issue-10877.rs:11:12
+ --> $DIR/foreign-fn-pattern-error-10877.rs:13:12
|
LL | fn qux((x, y): ());
| ^^^^^^ pattern not allowed in foreign function
diff --git a/tests/ui/extern/issue-36122-accessing-externed-dst.rs b/tests/ui/extern/issue-36122-accessing-externed-dst.rs
index 9fb7780..5f886ff 100644
--- a/tests/ui/extern/issue-36122-accessing-externed-dst.rs
+++ b/tests/ui/extern/issue-36122-accessing-externed-dst.rs
@@ -3,5 +3,4 @@
static symbol: [usize]; //~ ERROR: the size for values of type
}
println!("{}", symbol[0]);
- //~^ ERROR: extern static is unsafe
}
diff --git a/tests/ui/extern/issue-36122-accessing-externed-dst.stderr b/tests/ui/extern/issue-36122-accessing-externed-dst.stderr
index 8007c3f..c617cf4 100644
--- a/tests/ui/extern/issue-36122-accessing-externed-dst.stderr
+++ b/tests/ui/extern/issue-36122-accessing-externed-dst.stderr
@@ -7,15 +7,6 @@
= help: the trait `Sized` is not implemented for `[usize]`
= note: statics and constants must have a statically known size
-error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-36122-accessing-externed-dst.rs:5:20
- |
-LL | println!("{}", symbol[0]);
- | ^^^^^^ use of extern static
- |
- = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+error: aborting due to 1 previous error
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0133, E0277.
-For more information about an error, try `rustc --explain E0133`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
index 9740eaa..b93cb2e 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
@@ -57,7 +57,7 @@
// see gated-link-args.rs
// see issue-43106-gating-of-macro_escape.rs for crate-level; but non crate-level is below at "2700"
// (cannot easily test gating of crate-level #[no_std]; but non crate-level is below at "2600")
-#![proc_macro_derive()] //~ WARN `#[proc_macro_derive]` only has an effect
+#![proc_macro_derive(Test)] //~ WARN `#[proc_macro_derive]` only has an effect
#![doc = "2400"]
#![cold] //~ WARN attribute should be applied to a function
//~^ WARN this was previously accepted
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
index 9016ca1..8bac1f6 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
@@ -367,12 +367,6 @@
LL | #![should_panic]
| ^^^^^^^^^^^^^^^^
-warning: `#[proc_macro_derive]` only has an effect on functions
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1
- |
-LL | #![proc_macro_derive()]
- | ^^^^^^^^^^^^^^^^^^^^^^^
-
warning: attribute should be applied to an `extern` block with non-Rust ABI
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1
|
@@ -409,6 +403,12 @@
LL | #![must_use]
| ^^^^^^^^^^^^
+warning: `#[proc_macro_derive]` only has an effect on functions
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1
+ |
+LL | #![proc_macro_derive(Test)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
warning: attribute should be applied to a function definition
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1
|
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs
index a94ffd6..392880e 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs
@@ -7,27 +7,27 @@
// signal errors, making it incompatible with the "warnings only"
// nature of issue-43106-gating-of-builtin-attrs.rs
-#[proc_macro_derive()]
+#[proc_macro_derive(Test)]
//~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions
mod proc_macro_derive1 {
- mod inner { #![proc_macro_derive()] }
+ mod inner { #![proc_macro_derive(Test)] }
// (no error issued here if there was one on outer module)
}
mod proc_macro_derive2 {
- mod inner { #![proc_macro_derive()] }
+ mod inner { #![proc_macro_derive(Test)] }
//~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions
- #[proc_macro_derive()] fn f() { }
+ #[proc_macro_derive(Test)] fn f() { }
//~^ ERROR the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro`
- #[proc_macro_derive()] struct S;
+ #[proc_macro_derive(Test)] struct S;
//~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions
- #[proc_macro_derive()] type T = S;
+ #[proc_macro_derive(Test)] type T = S;
//~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions
- #[proc_macro_derive()] impl S { }
+ #[proc_macro_derive(Test)] impl S { }
//~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions
}
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr
index e202b47..537032d 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr
@@ -1,38 +1,38 @@
error: the `#[proc_macro_derive]` attribute may only be used on bare functions
--> $DIR/issue-43106-gating-of-proc_macro_derive.rs:10:1
|
-LL | #[proc_macro_derive()]
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #[proc_macro_derive(Test)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the `#[proc_macro_derive]` attribute may only be used on bare functions
--> $DIR/issue-43106-gating-of-proc_macro_derive.rs:18:17
|
-LL | mod inner { #![proc_macro_derive()] }
- | ^^^^^^^^^^^^^^^^^^^^^^^
+LL | mod inner { #![proc_macro_derive(Test)] }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
--> $DIR/issue-43106-gating-of-proc_macro_derive.rs:21:5
|
-LL | #[proc_macro_derive()] fn f() { }
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #[proc_macro_derive(Test)] fn f() { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the `#[proc_macro_derive]` attribute may only be used on bare functions
--> $DIR/issue-43106-gating-of-proc_macro_derive.rs:24:5
|
-LL | #[proc_macro_derive()] struct S;
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #[proc_macro_derive(Test)] struct S;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the `#[proc_macro_derive]` attribute may only be used on bare functions
--> $DIR/issue-43106-gating-of-proc_macro_derive.rs:27:5
|
-LL | #[proc_macro_derive()] type T = S;
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #[proc_macro_derive(Test)] type T = S;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the `#[proc_macro_derive]` attribute may only be used on bare functions
--> $DIR/issue-43106-gating-of-proc_macro_derive.rs:30:5
|
-LL | #[proc_macro_derive()] impl S { }
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #[proc_macro_derive(Test)] impl S { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 6 previous errors
diff --git a/tests/ui/float/target-has-reliable-nightly-float.rs b/tests/ui/float/target-has-reliable-nightly-float.rs
index ad8600f..399f101 100644
--- a/tests/ui/float/target-has-reliable-nightly-float.rs
+++ b/tests/ui/float/target-has-reliable-nightly-float.rs
@@ -19,8 +19,10 @@ pub fn has_f128() {}
pub fn has_f128_math() {}
fn main() {
- if cfg!(target_arch = "aarch64") && cfg!(target_os = "linux") {
- // Aarch64+Linux is one target that has support for all features, so use it to spot
+ if cfg!(target_arch = "aarch64") &&
+ cfg!(target_os = "linux") &&
+ cfg!(not(target_env = "musl")) {
+ // Aarch64+GNU+Linux is one target that has support for all features, so use it to spot
// check that the compiler does indeed enable these gates.
assert!(cfg!(target_has_reliable_f16));
diff --git a/tests/ui/issues/auxiliary/issue-18514.rs b/tests/ui/generics/auxiliary/generic-impl-method-match-autoderef-18514.rs
similarity index 100%
rename from tests/ui/issues/auxiliary/issue-18514.rs
rename to tests/ui/generics/auxiliary/generic-impl-method-match-autoderef-18514.rs
diff --git a/tests/ui/issues/issue-18514.rs b/tests/ui/generics/generic-impl-method-match-autoderef-18514.rs
similarity index 67%
rename from tests/ui/issues/issue-18514.rs
rename to tests/ui/generics/generic-impl-method-match-autoderef-18514.rs
index 89f58d3..3520e93 100644
--- a/tests/ui/issues/issue-18514.rs
+++ b/tests/ui/generics/generic-impl-method-match-autoderef-18514.rs
@@ -5,12 +5,14 @@
// expression that autoderefs through an overloaded generic deref
// impl.
-//@ aux-build:issue-18514.rs
+//@ aux-build:generic-impl-method-match-autoderef-18514.rs
-extern crate issue_18514 as ice;
+extern crate generic_impl_method_match_autoderef_18514 as ice;
use ice::{Tr, St};
fn main() {
let st: St<()> = St(vec![]);
st.tr();
}
+
+// https://github.com/rust-lang/rust/issues/18514
diff --git a/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr b/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr
index 418f9ac..46b6772 100644
--- a/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr
+++ b/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
@@ -19,7 +19,7 @@
| ^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.stderr
index 35fff9e..980dded 100644
--- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.stderr
+++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/rpit-lifetime-capture.html>
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
--> $DIR/overcaptures-2024-machine-applicable.rs:9:10
|
diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr
index 3f8511a..dc9f1c2 100644
--- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr
+++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/rpit-lifetime-capture.html>
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
--> $DIR/overcaptures-2024.rs:7:10
|
@@ -29,7 +29,7 @@
| ^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/rpit-lifetime-capture.html>
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
--> $DIR/overcaptures-2024.rs:11:16
|
@@ -48,7 +48,7 @@
| ^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/rpit-lifetime-capture.html>
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
--> $DIR/overcaptures-2024.rs:17:24
|
@@ -67,7 +67,7 @@
| ^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/rpit-lifetime-capture.html>
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
--> $DIR/overcaptures-2024.rs:29:23
|
@@ -86,7 +86,7 @@
| ^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/rpit-lifetime-capture.html>
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
--> $DIR/overcaptures-2024.rs:33:12
|
@@ -111,7 +111,7 @@
| ^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/rpit-lifetime-capture.html>
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
--> $DIR/overcaptures-2024.rs:37:16
|
@@ -136,7 +136,7 @@
| ^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/rpit-lifetime-capture.html>
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
--> $DIR/overcaptures-2024.rs:41:19
|
@@ -155,7 +155,7 @@
| ^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/rpit-lifetime-capture.html>
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
--> $DIR/overcaptures-2024.rs:45:18
|
diff --git a/tests/ui/issues/issue-10806.rs b/tests/ui/imports/use-declaration-no-path-segment-prefix.rs
similarity index 86%
rename from tests/ui/issues/issue-10806.rs
rename to tests/ui/imports/use-declaration-no-path-segment-prefix.rs
index 31315dc..f7fbc08 100644
--- a/tests/ui/issues/issue-10806.rs
+++ b/tests/ui/imports/use-declaration-no-path-segment-prefix.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10806
+
//@ edition: 2015
//@ run-pass
#![allow(unused_imports)]
diff --git a/tests/ui/inference/fnonce-closure-call.rs b/tests/ui/inference/fnonce-closure-call.rs
new file mode 100644
index 0000000..262a193
--- /dev/null
+++ b/tests/ui/inference/fnonce-closure-call.rs
@@ -0,0 +1,12 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10718
+
+//@ run-pass
+
+fn f<F:FnOnce()>(p: F) {
+ p();
+}
+
+pub fn main() {
+ let p = || ();
+ f(p);
+}
diff --git a/tests/ui/issues/issue-10436.rs b/tests/ui/inference/generic-type-inference-10436.rs
similarity index 76%
rename from tests/ui/issues/issue-10436.rs
rename to tests/ui/inference/generic-type-inference-10436.rs
index 672aa24..456a9b8 100644
--- a/tests/ui/issues/issue-10436.rs
+++ b/tests/ui/inference/generic-type-inference-10436.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10436
+
//@ run-pass
fn works<T>(x: T) -> Vec<T> { vec![x] }
diff --git a/tests/ui/intrinsics/panic-uninitialized-zeroed.rs b/tests/ui/intrinsics/panic-uninitialized-zeroed.rs
index 346a94c..cdf8aa8 100644
--- a/tests/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/tests/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -4,6 +4,7 @@
//@ revisions: default strict
//@ [strict]compile-flags: -Zstrict-init-checks
//@ needs-subprocess
+//@ ignore-backends: gcc
#![allow(deprecated, invalid_value)]
#![feature(never_type)]
diff --git a/tests/ui/issues/issue-10545.rs b/tests/ui/issues/issue-10545.rs
deleted file mode 100644
index acd0714..0000000
--- a/tests/ui/issues/issue-10545.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-mod a {
- struct S;
- impl S { }
-}
-
-fn foo(_: a::S) { //~ ERROR: struct `S` is private
-}
-
-fn main() {}
diff --git a/tests/ui/issues/issue-10718.rs b/tests/ui/issues/issue-10718.rs
deleted file mode 100644
index 68ac0bb..0000000
--- a/tests/ui/issues/issue-10718.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ run-pass
-
-fn f<F:FnOnce()>(p: F) {
- p();
-}
-
-pub fn main() {
- let p = || ();
- f(p);
-}
diff --git a/tests/ui/issues/issue-10764.rs b/tests/ui/issues/issue-10764.rs
deleted file mode 100644
index bb915f5..0000000
--- a/tests/ui/issues/issue-10764.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn f(_: extern "Rust" fn()) {}
-extern "C" fn bar() {}
-
-fn main() { f(bar) }
-//~^ ERROR mismatched types
diff --git a/tests/ui/issues/issue-10767.rs b/tests/ui/issues/issue-10767.rs
deleted file mode 100644
index 2060d15..0000000
--- a/tests/ui/issues/issue-10767.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ run-pass
-
-pub fn main() {
- fn f() {
- }
- let _: Box<fn()> = Box::new(f as fn());
-}
diff --git a/tests/ui/issues/issue-14875.rs b/tests/ui/issues/issue-14875.rs
index 235d255..e330c64 100644
--- a/tests/ui/issues/issue-14875.rs
+++ b/tests/ui/issues/issue-14875.rs
@@ -1,5 +1,6 @@
//@ run-pass
//@ needs-unwind
+//@ ignore-backends: gcc
// Check that values are not leaked when a dtor panics (#14875)
diff --git a/tests/ui/issues/issue-2472.rs b/tests/ui/issues/issue-2472.rs
deleted file mode 100644
index f8f539e..0000000
--- a/tests/ui/issues/issue-2472.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ run-pass
-//@ aux-build:issue-2472-b.rs
-
-
-extern crate issue_2472_b;
-
-use issue_2472_b::{S, T};
-
-pub fn main() {
- let s = S(());
- s.foo();
- s.bar();
-}
diff --git a/tests/ui/issues/issue-28344.stderr b/tests/ui/issues/issue-28344.stderr
index 7bc9655..dfd4951 100644
--- a/tests/ui/issues/issue-28344.stderr
+++ b/tests/ui/issues/issue-28344.stderr
@@ -5,7 +5,7 @@
| ^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
@@ -25,7 +25,7 @@
| ^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | let g = <dyn BitXor>::bitor;
diff --git a/tests/ui/issues/issue-29948.rs b/tests/ui/issues/issue-29948.rs
index 77e1f68..77a3885 100644
--- a/tests/ui/issues/issue-29948.rs
+++ b/tests/ui/issues/issue-29948.rs
@@ -1,5 +1,6 @@
//@ run-pass
//@ needs-unwind
+//@ ignore-backends: gcc
use std::panic;
diff --git a/tests/ui/issues/issue-39367.stderr b/tests/ui/issues/issue-39367.stderr
index df21c09..6507637 100644
--- a/tests/ui/issues/issue-39367.stderr
+++ b/tests/ui/issues/issue-39367.stderr
@@ -9,7 +9,7 @@
LL | | });
| |______________^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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: `#[warn(static_mut_refs)]` on by default
diff --git a/tests/ui/issues/issue-4335.stderr b/tests/ui/issues/issue-4335.stderr
index 14b5cfa..42ac632 100644
--- a/tests/ui/issues/issue-4335.stderr
+++ b/tests/ui/issues/issue-4335.stderr
@@ -2,9 +2,11 @@
--> $DIR/issue-4335.rs:6:20
|
LL | fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> {
- | - captured outer variable
+ | - ----- move occurs because `*v` has type `T`, which does not implement the `Copy` trait
+ | |
+ | captured outer variable
LL | id(Box::new(|| *v))
- | -- ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait
+ | -- ^^ `*v` is moved here
| |
| captured by this `FnMut` closure
|
diff --git a/tests/ui/issues/issue-49544.rs b/tests/ui/issues/issue-49544.rs
deleted file mode 100644
index bb05250..0000000
--- a/tests/ui/issues/issue-49544.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ aux-build:issue-49544.rs
-//@ check-pass
-
-extern crate issue_49544;
-use issue_49544::foo;
-
-fn main() {
- let _ = foo();
-}
diff --git a/tests/ui/issues/issue-54062.rs b/tests/ui/issues/issue-54062.rs
deleted file mode 100644
index 093d660..0000000
--- a/tests/ui/issues/issue-54062.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-use std::sync::Mutex;
-
-struct Test {
- comps: Mutex<String>,
-}
-
-fn main() {}
-
-fn testing(test: Test) {
- let _ = test.comps.inner.try_lock();
- //~^ ERROR: field `inner` of struct `Mutex` is private
-}
diff --git a/tests/ui/issues/issue-58734.stderr b/tests/ui/issues/issue-58734.stderr
index e5dad00..c246d1f 100644
--- a/tests/ui/issues/issue-58734.stderr
+++ b/tests/ui/issues/issue-58734.stderr
@@ -5,7 +5,7 @@
| ^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/issues/issue-86756.stderr b/tests/ui/issues/issue-86756.stderr
index 0f68b76..b650b32 100644
--- a/tests/ui/issues/issue-86756.stderr
+++ b/tests/ui/issues/issue-86756.stderr
@@ -19,7 +19,7 @@
| ^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/issues/auxiliary/issue-49544.rs b/tests/ui/iterators/auxiliary/iterator-adapter-undeclared-type-49544.rs
similarity index 100%
rename from tests/ui/issues/auxiliary/issue-49544.rs
rename to tests/ui/iterators/auxiliary/iterator-adapter-undeclared-type-49544.rs
diff --git a/tests/ui/iterators/into-iter-on-arrays-2018.stderr b/tests/ui/iterators/into-iter-on-arrays-2018.stderr
index d4055c7..8818ef8 100644
--- a/tests/ui/iterators/into-iter-on-arrays-2018.stderr
+++ b/tests/ui/iterators/into-iter-on-arrays-2018.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
= note: `#[warn(array_into_iter)]` on by default
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
@@ -25,7 +25,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-2018.rs:22:43
@@ -34,7 +34,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-2018.rs:25:41
@@ -43,7 +43,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-2018.rs:32:24
@@ -52,7 +52,7 @@
| ^^^^^^^^^
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL - for _ in [1, 2, 3].into_iter() {}
diff --git a/tests/ui/iterators/into-iter-on-arrays-lint.stderr b/tests/ui/iterators/into-iter-on-arrays-lint.stderr
index fb8fe79..a9dfa58 100644
--- a/tests/ui/iterators/into-iter-on-arrays-lint.stderr
+++ b/tests/ui/iterators/into-iter-on-arrays-lint.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
= note: `#[warn(array_into_iter)]` on by default
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
@@ -25,7 +25,7 @@
| ^^^^^^^^^
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL - [1, 2].into_iter();
@@ -44,7 +44,7 @@
| ^^^^^^^^^
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL - big.into_iter();
@@ -63,7 +63,7 @@
| ^^^^^^^^^
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL - [0u8; 33].into_iter();
@@ -82,7 +82,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:27:22
@@ -91,7 +91,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:30:19
@@ -100,7 +100,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:33:25
@@ -109,7 +109,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:37:31
@@ -118,7 +118,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:40:32
@@ -127,7 +127,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:43:29
@@ -136,7 +136,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:46:35
@@ -145,7 +145,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
warning: 12 warnings emitted
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr b/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr
index 7a5a2be..a0c1432 100644
--- a/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/intoiterator-box-slice.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/intoiterator-box-slice.html>
= note: `#[warn(boxed_slice_into_iter)]` on by default
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
@@ -25,7 +25,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/intoiterator-box-slice.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/intoiterator-box-slice.html>
warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
--> $DIR/into-iter-on-boxed-slices-2021.rs:22:57
@@ -34,7 +34,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/intoiterator-box-slice.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/intoiterator-box-slice.html>
warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
--> $DIR/into-iter-on-boxed-slices-2021.rs:25:55
@@ -43,7 +43,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/intoiterator-box-slice.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/intoiterator-box-slice.html>
warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
--> $DIR/into-iter-on-boxed-slices-2021.rs:32:48
@@ -52,7 +52,7 @@
| ^^^^^^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/intoiterator-box-slice.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/intoiterator-box-slice.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL - for _ in (Box::new([1, 2, 3]) as Box<[_]>).into_iter() {}
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr b/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr
index 6762ed2..377455d 100644
--- a/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/intoiterator-box-slice.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/intoiterator-box-slice.html>
= note: `#[warn(boxed_slice_into_iter)]` on by default
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
@@ -25,7 +25,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/intoiterator-box-slice.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/intoiterator-box-slice.html>
warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
--> $DIR/into-iter-on-boxed-slices-lint.rs:16:39
@@ -34,7 +34,7 @@
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/intoiterator-box-slice.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/intoiterator-box-slice.html>
warning: 3 warnings emitted
diff --git a/tests/ui/iterators/iter-sum-overflow-debug.rs b/tests/ui/iterators/iter-sum-overflow-debug.rs
index 32efc92..974282b 100644
--- a/tests/ui/iterators/iter-sum-overflow-debug.rs
+++ b/tests/ui/iterators/iter-sum-overflow-debug.rs
@@ -1,5 +1,6 @@
//@ run-pass
//@ needs-unwind
+//@ ignore-backends: gcc
//@ compile-flags: -C debug_assertions=yes
use std::panic;
diff --git a/tests/ui/iterators/iter-sum-overflow-overflow-checks.rs b/tests/ui/iterators/iter-sum-overflow-overflow-checks.rs
index 8fffd19..aba6f9a 100644
--- a/tests/ui/iterators/iter-sum-overflow-overflow-checks.rs
+++ b/tests/ui/iterators/iter-sum-overflow-overflow-checks.rs
@@ -1,5 +1,6 @@
//@ run-pass
//@ needs-unwind
+//@ ignore-backends: gcc
//@ compile-flags: -C overflow-checks
use std::panic;
diff --git a/tests/ui/iterators/iterator-adapter-undeclared-type-49544.rs b/tests/ui/iterators/iterator-adapter-undeclared-type-49544.rs
new file mode 100644
index 0000000..f2532ce
--- /dev/null
+++ b/tests/ui/iterators/iterator-adapter-undeclared-type-49544.rs
@@ -0,0 +1,11 @@
+//@ aux-build:iterator-adapter-undeclared-type-49544.rs
+//@ check-pass
+
+extern crate iterator_adapter_undeclared_type_49544 as lib;
+use lib::foo;
+
+fn main() {
+ let _ = foo();
+}
+
+// https://github.com/rust-lang/rust/issues/49544
diff --git a/tests/ui/layout/issue-84108.rs b/tests/ui/layout/issue-84108.rs
index 974d531..3388461 100644
--- a/tests/ui/layout/issue-84108.rs
+++ b/tests/ui/layout/issue-84108.rs
@@ -14,5 +14,3 @@
static BAZ: ([u8], usize) = ([], 0);
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
-//~| ERROR the size for values of type `[u8]` cannot be known at compilation time
-//~| ERROR mismatched types
diff --git a/tests/ui/layout/issue-84108.stderr b/tests/ui/layout/issue-84108.stderr
index e296abf..62a6ae3 100644
--- a/tests/ui/layout/issue-84108.stderr
+++ b/tests/ui/layout/issue-84108.stderr
@@ -57,26 +57,7 @@
= note: expected slice `[u8]`
found array `[_; 0]`
-error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
- --> $DIR/issue-84108.rs:15:13
- |
-LL | static BAZ: ([u8], usize) = ([], 0);
- | ^^^^^^^^^^^^^ doesn't have a size known at compile-time
- |
- = help: the trait `Sized` is not implemented for `[u8]`
- = note: only the last element of a tuple may have a dynamically sized type
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0308]: mismatched types
- --> $DIR/issue-84108.rs:15:30
- |
-LL | static BAZ: ([u8], usize) = ([], 0);
- | ^^ expected `[u8]`, found `[_; 0]`
- |
- = note: expected slice `[u8]`
- found array `[_; 0]`
-
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
Some errors have detailed explanations: E0277, E0308, E0412.
For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/issues/issue-10396.rs b/tests/ui/lifetimes/array-pattern-matching-10396.rs
similarity index 70%
rename from tests/ui/issues/issue-10396.rs
rename to tests/ui/lifetimes/array-pattern-matching-10396.rs
index 082216d..5fc141b 100644
--- a/tests/ui/issues/issue-10396.rs
+++ b/tests/ui/lifetimes/array-pattern-matching-10396.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10396
+
//@ check-pass
#![allow(dead_code)]
#[derive(Debug)]
diff --git a/tests/ui/issues/issue-10291.rs b/tests/ui/lifetimes/closure-lifetime-bounds-10291.rs
similarity index 72%
rename from tests/ui/issues/issue-10291.rs
rename to tests/ui/lifetimes/closure-lifetime-bounds-10291.rs
index 31b9e12..42dc6c2 100644
--- a/tests/ui/issues/issue-10291.rs
+++ b/tests/ui/lifetimes/closure-lifetime-bounds-10291.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10291
+
fn test<'x>(x: &'x isize) {
drop::<Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
x
diff --git a/tests/ui/issues/issue-10291.stderr b/tests/ui/lifetimes/closure-lifetime-bounds-10291.stderr
similarity index 86%
rename from tests/ui/issues/issue-10291.stderr
rename to tests/ui/lifetimes/closure-lifetime-bounds-10291.stderr
index 68ed9a0..34f8ca4 100644
--- a/tests/ui/issues/issue-10291.stderr
+++ b/tests/ui/lifetimes/closure-lifetime-bounds-10291.stderr
@@ -1,5 +1,5 @@
error: lifetime may not live long enough
- --> $DIR/issue-10291.rs:3:9
+ --> $DIR/closure-lifetime-bounds-10291.rs:5:9
|
LL | fn test<'x>(x: &'x isize) {
| -- lifetime `'x` defined here
diff --git a/tests/ui/issues/issue-11374.rs b/tests/ui/lifetimes/container-lifetime-error-11374.rs
similarity index 88%
rename from tests/ui/issues/issue-11374.rs
rename to tests/ui/lifetimes/container-lifetime-error-11374.rs
index 60ee256..59d13d0 100644
--- a/tests/ui/issues/issue-11374.rs
+++ b/tests/ui/lifetimes/container-lifetime-error-11374.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/11374
+
use std::io::{self, Read};
use std::vec;
diff --git a/tests/ui/issues/issue-11374.stderr b/tests/ui/lifetimes/container-lifetime-error-11374.stderr
similarity index 86%
rename from tests/ui/issues/issue-11374.stderr
rename to tests/ui/lifetimes/container-lifetime-error-11374.stderr
index 3ae5cfc..a29b5ae 100644
--- a/tests/ui/issues/issue-11374.stderr
+++ b/tests/ui/lifetimes/container-lifetime-error-11374.stderr
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
- --> $DIR/issue-11374.rs:27:15
+ --> $DIR/container-lifetime-error-11374.rs:29:15
|
LL | c.read_to(v);
| ------- ^ expected `&mut [u8]`, found `Vec<_>`
@@ -9,7 +9,7 @@
= note: expected mutable reference `&mut [u8]`
found struct `Vec<_>`
note: method defined here
- --> $DIR/issue-11374.rs:13:12
+ --> $DIR/container-lifetime-error-11374.rs:15:12
|
LL | pub fn read_to(&mut self, vec: &mut [u8]) {
| ^^^^^^^ --------------
@@ -19,7 +19,7 @@
| ++++
error[E0515]: cannot return value referencing local variable `r`
- --> $DIR/issue-11374.rs:20:5
+ --> $DIR/container-lifetime-error-11374.rs:22:5
|
LL | Container::wrap(&mut r as &mut dyn io::Read)
| ^^^^^^^^^^^^^^^^------^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/issues/issue-10228.rs b/tests/ui/lifetimes/enum-lifetime-container-10228.rs
similarity index 79%
rename from tests/ui/issues/issue-10228.rs
rename to tests/ui/lifetimes/enum-lifetime-container-10228.rs
index a59ccf9..ebbefb6 100644
--- a/tests/ui/issues/issue-10228.rs
+++ b/tests/ui/lifetimes/enum-lifetime-container-10228.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10228
+
//@ run-pass
#![allow(dead_code)]
#![allow(unused_variables)]
diff --git a/tests/ui/issues/issue-10412.rs b/tests/ui/lifetimes/keyword-self-lifetime-error-10412.rs
similarity index 91%
rename from tests/ui/issues/issue-10412.rs
rename to tests/ui/lifetimes/keyword-self-lifetime-error-10412.rs
index 68ce0c2..a5b303d 100644
--- a/tests/ui/issues/issue-10412.rs
+++ b/tests/ui/lifetimes/keyword-self-lifetime-error-10412.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10412
+
trait Serializable<'self, T> {
//~^ ERROR lifetimes cannot use keyword names
fn serialize(val: &'self T) -> Vec<u8>; //~ ERROR lifetimes cannot use keyword names
diff --git a/tests/ui/issues/issue-10412.stderr b/tests/ui/lifetimes/keyword-self-lifetime-error-10412.stderr
similarity index 75%
rename from tests/ui/issues/issue-10412.stderr
rename to tests/ui/lifetimes/keyword-self-lifetime-error-10412.stderr
index c74ba13..236bdf1 100644
--- a/tests/ui/issues/issue-10412.stderr
+++ b/tests/ui/lifetimes/keyword-self-lifetime-error-10412.stderr
@@ -1,47 +1,47 @@
error: lifetimes cannot use keyword names
- --> $DIR/issue-10412.rs:1:20
+ --> $DIR/keyword-self-lifetime-error-10412.rs:3:20
|
LL | trait Serializable<'self, T> {
| ^^^^^
error: lifetimes cannot use keyword names
- --> $DIR/issue-10412.rs:3:24
+ --> $DIR/keyword-self-lifetime-error-10412.rs:5:24
|
LL | fn serialize(val: &'self T) -> Vec<u8>;
| ^^^^^
error: lifetimes cannot use keyword names
- --> $DIR/issue-10412.rs:4:37
+ --> $DIR/keyword-self-lifetime-error-10412.rs:6:37
|
LL | fn deserialize(repr: &[u8]) -> &'self T;
| ^^^^^
error: lifetimes cannot use keyword names
- --> $DIR/issue-10412.rs:7:6
+ --> $DIR/keyword-self-lifetime-error-10412.rs:9:6
|
LL | impl<'self> Serializable<str> for &'self str {
| ^^^^^
error: lifetimes cannot use keyword names
- --> $DIR/issue-10412.rs:7:36
+ --> $DIR/keyword-self-lifetime-error-10412.rs:9:36
|
LL | impl<'self> Serializable<str> for &'self str {
| ^^^^^
error: lifetimes cannot use keyword names
- --> $DIR/issue-10412.rs:11:24
+ --> $DIR/keyword-self-lifetime-error-10412.rs:13:24
|
LL | fn serialize(val: &'self str) -> Vec<u8> {
| ^^^^^
error: lifetimes cannot use keyword names
- --> $DIR/issue-10412.rs:15:37
+ --> $DIR/keyword-self-lifetime-error-10412.rs:17:37
|
LL | fn deserialize(repr: &[u8]) -> &'self str {
| ^^^^^
error[E0726]: implicit elided lifetime not allowed here
- --> $DIR/issue-10412.rs:7:13
+ --> $DIR/keyword-self-lifetime-error-10412.rs:9:13
|
LL | impl<'self> Serializable<str> for &'self str {
| ^^^^^^^^^^^^^^^^^ expected lifetime parameter
diff --git a/tests/ui/issues/issue-10902.rs b/tests/ui/lifetimes/tuple-struct-vs-struct-with-fields-borrowck-10902.rs
similarity index 86%
rename from tests/ui/issues/issue-10902.rs
rename to tests/ui/lifetimes/tuple-struct-vs-struct-with-fields-borrowck-10902.rs
index 7cdf880..97c0d0b 100644
--- a/tests/ui/issues/issue-10902.rs
+++ b/tests/ui/lifetimes/tuple-struct-vs-struct-with-fields-borrowck-10902.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10902
+
//@ check-pass
#![allow(dead_code)]
diff --git a/tests/ui/linkage-attr/incompatible-flavor.rs b/tests/ui/linkage-attr/incompatible-flavor.rs
index 7f583f4..4711343 100644
--- a/tests/ui/linkage-attr/incompatible-flavor.rs
+++ b/tests/ui/linkage-attr/incompatible-flavor.rs
@@ -1,5 +1,5 @@
//@ compile-flags: --target=x86_64-unknown-linux-gnu -C linker-flavor=msvc --crate-type=rlib
-//@ needs-llvm-components:
+//@ needs-llvm-components: x86
#![feature(no_core)]
#![no_core]
diff --git a/tests/ui/linkage-attr/raw-dylib/elf/empty.rs b/tests/ui/linkage-attr/raw-dylib/elf/empty.rs
new file mode 100644
index 0000000..2e48a5f
--- /dev/null
+++ b/tests/ui/linkage-attr/raw-dylib/elf/empty.rs
@@ -0,0 +1,11 @@
+//@ only-x86_64-unknown-linux-gnu
+//@ needs-dynamic-linking
+//@ build-pass
+
+#![allow(incomplete_features)]
+#![feature(raw_dylib_elf)]
+
+#[link(name = "hack", kind = "raw-dylib")]
+unsafe extern "C" {}
+
+fn main() {}
diff --git a/tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs b/tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs
new file mode 100644
index 0000000..57492ed
--- /dev/null
+++ b/tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs
@@ -0,0 +1,80 @@
+//@ only-x86_64-unknown-linux-gnu
+//@ needs-dynamic-linking
+//@ run-pass
+//@ compile-flags: -Cpanic=abort
+//@ edition: 2024
+
+#![allow(incomplete_features)]
+#![feature(raw_dylib_elf)]
+#![no_std]
+#![no_main]
+
+use core::ffi::{c_char, c_int};
+
+extern "C" fn callback(
+ _fpath: *const c_char,
+ _sb: *const (),
+ _tflag: c_int,
+ _ftwbuf: *const (),
+) -> c_int {
+ 0
+}
+
+// `libc.so` is a linker script that provides the paths to `libc.so.6` and `libc_nonshared.a`.
+// In earlier versions of glibc, `libc_nonshared.a` provides the symbols `__libc_csu_init` and
+// `__libc_csu_fini` required by `Scrt1.o`.
+#[link(name = "c_nonshared", kind = "static")]
+unsafe extern "C" {}
+
+#[link(name = "libc.so.6", kind = "raw-dylib", modifiers = "+verbatim")]
+unsafe extern "C" {
+ #[link_name = "nftw@GLIBC_2.2.5"]
+ unsafe fn nftw_2_2_5(
+ dirpath: *const c_char,
+ f: extern "C" fn(*const c_char, *const (), c_int, *const ()) -> c_int,
+ nopenfd: c_int,
+ flags: c_int,
+ ) -> c_int;
+ #[link_name = "nftw@GLIBC_2.3.3"]
+ unsafe fn nftw_2_3_3(
+ dirpath: *const c_char,
+ f: extern "C" fn(*const c_char, *const (), c_int, *const ()) -> c_int,
+ nopenfd: c_int,
+ flags: c_int,
+ ) -> c_int;
+ #[link_name = "exit@GLIBC_2.2.5"]
+ safe fn exit(status: i32) -> !;
+ unsafe fn __libc_start_main() -> c_int;
+}
+
+#[unsafe(no_mangle)]
+extern "C" fn main() -> ! {
+ unsafe {
+ // The old `nftw` does not check whether unknown flags are set.
+ let res = nftw_2_2_5(c".".as_ptr(), callback, 20, 1 << 30);
+ assert_eq!(res, 0);
+ }
+ unsafe {
+ // The new `nftw` does.
+ let res = nftw_2_3_3(c".".as_ptr(), callback, 20, 1 << 30);
+ assert_eq!(res, -1);
+ }
+ exit(0);
+}
+
+#[cfg(not(test))]
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! {
+ exit(1);
+}
+
+#[unsafe(no_mangle)]
+extern "C" fn rust_eh_personality(
+ _version: i32,
+ _actions: i32,
+ _exception_class: u64,
+ _exception_object: *mut (),
+ _context: *mut (),
+) -> i32 {
+ exit(1);
+}
diff --git a/tests/ui/linkage-attr/raw-dylib/elf/malformed-link-name.rs b/tests/ui/linkage-attr/raw-dylib/elf/malformed-link-name.rs
new file mode 100644
index 0000000..46e3798
--- /dev/null
+++ b/tests/ui/linkage-attr/raw-dylib/elf/malformed-link-name.rs
@@ -0,0 +1,20 @@
+//@ only-elf
+//@ needs-dynamic-linking
+//@ check-fail
+
+#![feature(raw_dylib_elf)]
+#![allow(incomplete_features)]
+
+#[link(name = "libc.so.6", kind = "raw-dylib", modifiers = "+verbatim")]
+unsafe extern "C" {
+ #[link_name = "exit@"]
+ pub safe fn exit_0(status: i32) -> !; //~ ERROR link name must be well-formed if link kind is `raw-dylib`
+ #[link_name = "@GLIBC_2.2.5"]
+ pub safe fn exit_1(status: i32) -> !; //~ ERROR link name must be well-formed if link kind is `raw-dylib`
+ #[link_name = "ex\0it@GLIBC_2.2.5"]
+ pub safe fn exit_2(status: i32) -> !; //~ ERROR link name must be well-formed if link kind is `raw-dylib`
+ #[link_name = "exit@@GLIBC_2.2.5"]
+ pub safe fn exit_3(status: i32) -> !; //~ ERROR link name must be well-formed if link kind is `raw-dylib`
+}
+
+fn main() {}
diff --git a/tests/ui/linkage-attr/raw-dylib/elf/malformed-link-name.stderr b/tests/ui/linkage-attr/raw-dylib/elf/malformed-link-name.stderr
new file mode 100644
index 0000000..5a979e7
--- /dev/null
+++ b/tests/ui/linkage-attr/raw-dylib/elf/malformed-link-name.stderr
@@ -0,0 +1,26 @@
+error: link name must be well-formed if link kind is `raw-dylib`
+ --> $DIR/malformed-link-name.rs:11:5
+ |
+LL | pub safe fn exit_0(status: i32) -> !;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: link name must be well-formed if link kind is `raw-dylib`
+ --> $DIR/malformed-link-name.rs:13:5
+ |
+LL | pub safe fn exit_1(status: i32) -> !;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: link name must be well-formed if link kind is `raw-dylib`
+ --> $DIR/malformed-link-name.rs:15:5
+ |
+LL | pub safe fn exit_2(status: i32) -> !;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: link name must be well-formed if link kind is `raw-dylib`
+ --> $DIR/malformed-link-name.rs:17:5
+ |
+LL | pub safe fn exit_3(status: i32) -> !;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/linkage-attr/unstable-flavor.rs b/tests/ui/linkage-attr/unstable-flavor.rs
index 6aa9efb..5412e24 100644
--- a/tests/ui/linkage-attr/unstable-flavor.rs
+++ b/tests/ui/linkage-attr/unstable-flavor.rs
@@ -4,9 +4,9 @@
//
//@ revisions: bpf ptx
//@ [bpf] compile-flags: --target=bpfel-unknown-none -C linker-flavor=bpf --crate-type=rlib
-//@ [bpf] needs-llvm-components:
+//@ [bpf] needs-llvm-components: bpf
//@ [ptx] compile-flags: --target=nvptx64-nvidia-cuda -C linker-flavor=ptx --crate-type=rlib
-//@ [ptx] needs-llvm-components:
+//@ [ptx] needs-llvm-components: nvptx
#![feature(no_core)]
#![no_core]
diff --git a/tests/ui/lint/bare-trait-objects-path.stderr b/tests/ui/lint/bare-trait-objects-path.stderr
index 25f3e85..8da63a9 100644
--- a/tests/ui/lint/bare-trait-objects-path.stderr
+++ b/tests/ui/lint/bare-trait-objects-path.stderr
@@ -5,7 +5,7 @@
| ^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
@@ -19,7 +19,7 @@
| ^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | <dyn (::Dyn)>::func();
@@ -32,7 +32,7 @@
| ^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | <dyn Dyn>::CONST;
@@ -45,7 +45,7 @@
| ^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | let _: <dyn Dyn>::Ty;
diff --git a/tests/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr
index a1aa29d..2be7416 100644
--- a/tests/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr
+++ b/tests/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: requested on the command line with `--force-warn bare-trait-objects`
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/lint/force-warn/cap-lints-allow.stderr b/tests/ui/lint/force-warn/cap-lints-allow.stderr
index 0d10a43..92bcde1 100644
--- a/tests/ui/lint/force-warn/cap-lints-allow.stderr
+++ b/tests/ui/lint/force-warn/cap-lints-allow.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: requested on the command line with `--force-warn bare-trait-objects`
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr
index d1b764b..74b34de 100644
--- a/tests/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr
+++ b/tests/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr
@@ -5,7 +5,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `--force-warn ellipsis-inclusive-range-patterns` implied by `--force-warn rust-2021-compatibility`
warning: 1 warning emitted
diff --git a/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
index d52bd67..5bfbc95 100644
--- a/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
+++ b/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr b/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
index 22483a3..dabf12b 100644
--- a/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
+++ b/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
index aa183b9..23a3a91 100644
--- a/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
+++ b/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/lint/inclusive-range-pattern-syntax.stderr b/tests/ui/lint/inclusive-range-pattern-syntax.stderr
index ed9fa0d..a41082b 100644
--- a/tests/ui/lint/inclusive-range-pattern-syntax.stderr
+++ b/tests/ui/lint/inclusive-range-pattern-syntax.stderr
@@ -5,7 +5,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
note: the lint level is defined here
--> $DIR/inclusive-range-pattern-syntax.rs:4:9
|
@@ -19,7 +19,7 @@
| ^^^^^^ help: use `..=` for an inclusive range: `&(1..=2)`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
warning: 2 warnings emitted
diff --git a/tests/ui/lint/lint-attr-everywhere-early.stderr b/tests/ui/lint/lint-attr-everywhere-early.stderr
index fac0eb4..2389b69 100644
--- a/tests/ui/lint/lint-attr-everywhere-early.stderr
+++ b/tests/ui/lint/lint-attr-everywhere-early.stderr
@@ -391,7 +391,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
note: the lint level is defined here
--> $DIR/lint-attr-everywhere-early.rs:138:16
|
@@ -489,7 +489,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
note: the lint level is defined here
--> $DIR/lint-attr-everywhere-early.rs:174:20
|
diff --git a/tests/ui/issues/issue-10853.rs b/tests/ui/lint/missing-doc-unsugard-doc-attr-10853.rs
similarity index 68%
rename from tests/ui/issues/issue-10853.rs
rename to tests/ui/lint/missing-doc-unsugard-doc-attr-10853.rs
index 4c22393..ec13ae9 100644
--- a/tests/ui/issues/issue-10853.rs
+++ b/tests/ui/lint/missing-doc-unsugard-doc-attr-10853.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10853
+
//@ check-pass
#![deny(missing_docs)]
diff --git a/tests/ui/lint/must_not_suspend/mutex.rs b/tests/ui/lint/must_not_suspend/mutex.rs
index d14f713..8dd4cc1 100644
--- a/tests/ui/lint/must_not_suspend/mutex.rs
+++ b/tests/ui/lint/must_not_suspend/mutex.rs
@@ -5,7 +5,7 @@
async fn other() {}
pub async fn uhoh(m: std::sync::Mutex<()>) {
- let _guard = m.lock().unwrap(); //~ ERROR `MutexGuard` held across
+ let _guard = m.lock().unwrap(); //~ ERROR `std::sync::MutexGuard` held across
other().await;
}
diff --git a/tests/ui/lint/must_not_suspend/mutex.stderr b/tests/ui/lint/must_not_suspend/mutex.stderr
index ca53a75..0db1f25 100644
--- a/tests/ui/lint/must_not_suspend/mutex.stderr
+++ b/tests/ui/lint/must_not_suspend/mutex.stderr
@@ -1,4 +1,4 @@
-error: `MutexGuard` held across a suspend point, but should not be
+error: `std::sync::MutexGuard` held across a suspend point, but should not be
--> $DIR/mutex.rs:8:9
|
LL | let _guard = m.lock().unwrap();
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 d63abea..80abac4 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
@@ -1,9 +1,9 @@
#![feature(prelude_import)]
#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
// This ensures that ICEs like rust#94953 don't happen
//@ check-pass
//@ compile-flags: -Z unpretty=expanded
diff --git a/tests/ui/lint/static-mut-refs.e2021.stderr b/tests/ui/lint/static-mut-refs.e2021.stderr
index 320e0cee8..75a7e60 100644
--- a/tests/ui/lint/static-mut-refs.e2021.stderr
+++ b/tests/ui/lint/static-mut-refs.e2021.stderr
@@ -4,7 +4,7 @@
LL | let _y = &X;
| ^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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: `#[warn(static_mut_refs)]` on by default
help: use `&raw const` instead to create a raw pointer
@@ -18,7 +18,7 @@
LL | let _y = &mut X;
| ^^^^^^ mutable reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
= note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
help: use `&raw mut` instead to create a raw pointer
|
@@ -31,7 +31,7 @@
LL | let ref _a = X;
| ^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
warning: creating a shared reference to mutable static
@@ -40,7 +40,7 @@
LL | let (_b, _c) = (&X, &Y);
| ^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
help: use `&raw const` instead to create a raw pointer
|
@@ -53,7 +53,7 @@
LL | let (_b, _c) = (&X, &Y);
| ^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
help: use `&raw const` instead to create a raw pointer
|
@@ -66,7 +66,7 @@
LL | foo(&X);
| ^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
help: use `&raw const` instead to create a raw pointer
|
@@ -79,7 +79,7 @@
LL | let _ = Z.len();
| ^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
warning: creating a shared reference to mutable static
@@ -88,7 +88,7 @@
LL | let _ = format!("{:?}", Z);
| ^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
warning: creating a shared reference to mutable static
@@ -97,7 +97,7 @@
LL | let _v = &A.value;
| ^^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
help: use `&raw const` instead to create a raw pointer
|
@@ -110,7 +110,7 @@
LL | let _s = &A.s.value;
| ^^^^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
help: use `&raw const` instead to create a raw pointer
|
@@ -123,7 +123,7 @@
LL | let ref _v = A.value;
| ^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
warning: creating a mutable reference to mutable static
@@ -135,7 +135,7 @@
LL | let _x = bar!(FOO);
| --------- in this macro invocation
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
= note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
= note: this warning originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/lint/static-mut-refs.e2024.stderr b/tests/ui/lint/static-mut-refs.e2024.stderr
index bf7ffc6..42a96ba 100644
--- a/tests/ui/lint/static-mut-refs.e2024.stderr
+++ b/tests/ui/lint/static-mut-refs.e2024.stderr
@@ -4,7 +4,7 @@
LL | let _y = &X;
| ^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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: `#[deny(static_mut_refs)]` on by default
help: use `&raw const` instead to create a raw pointer
@@ -18,7 +18,7 @@
LL | let _y = &mut X;
| ^^^^^^ mutable reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
= note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
help: use `&raw mut` instead to create a raw pointer
|
@@ -31,7 +31,7 @@
LL | let ref _a = X;
| ^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
error: creating a shared reference to mutable static
@@ -40,7 +40,7 @@
LL | let (_b, _c) = (&X, &Y);
| ^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
help: use `&raw const` instead to create a raw pointer
|
@@ -53,7 +53,7 @@
LL | let (_b, _c) = (&X, &Y);
| ^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
help: use `&raw const` instead to create a raw pointer
|
@@ -66,7 +66,7 @@
LL | foo(&X);
| ^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
help: use `&raw const` instead to create a raw pointer
|
@@ -79,7 +79,7 @@
LL | let _ = Z.len();
| ^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
error: creating a shared reference to mutable static
@@ -88,7 +88,7 @@
LL | let _ = format!("{:?}", Z);
| ^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
error: creating a shared reference to mutable static
@@ -97,7 +97,7 @@
LL | let _v = &A.value;
| ^^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
help: use `&raw const` instead to create a raw pointer
|
@@ -110,7 +110,7 @@
LL | let _s = &A.s.value;
| ^^^^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
help: use `&raw const` instead to create a raw pointer
|
@@ -123,7 +123,7 @@
LL | let ref _v = A.value;
| ^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
error: creating a mutable reference to mutable static
@@ -135,7 +135,7 @@
LL | let _x = bar!(FOO);
| --------- in this macro invocation
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
= note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
= note: this error originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.fixed b/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.fixed
new file mode 100644
index 0000000..4b0bca3
--- /dev/null
+++ b/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.fixed
@@ -0,0 +1,12 @@
+//@ run-rustfix
+
+#![deny(unused_parens)]
+#![allow(warnings)]
+trait MyTrait {}
+
+fn foo(_: Box<dyn FnMut(&mut u32) -> &mut (dyn MyTrait) + Send + Sync>) {}
+
+//~v ERROR unnecessary parentheses around type
+fn bar(_: Box<dyn FnMut(&mut u32) -> &mut dyn MyTrait>) {}
+
+fn main() {}
diff --git a/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.rs b/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.rs
new file mode 100644
index 0000000..4eefd3d
--- /dev/null
+++ b/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.rs
@@ -0,0 +1,12 @@
+//@ run-rustfix
+
+#![deny(unused_parens)]
+#![allow(warnings)]
+trait MyTrait {}
+
+fn foo(_: Box<dyn FnMut(&mut u32) -> &mut (dyn MyTrait) + Send + Sync>) {}
+
+//~v ERROR unnecessary parentheses around type
+fn bar(_: Box<dyn FnMut(&mut u32) -> &mut (dyn MyTrait)>) {}
+
+fn main() {}
diff --git a/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.stderr b/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.stderr
new file mode 100644
index 0000000..89455e3
--- /dev/null
+++ b/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.stderr
@@ -0,0 +1,19 @@
+error: unnecessary parentheses around type
+ --> $DIR/unused-parens-false-positive-issue-143653.rs:10:43
+ |
+LL | fn bar(_: Box<dyn FnMut(&mut u32) -> &mut (dyn MyTrait)>) {}
+ | ^ ^
+ |
+note: the lint level is defined here
+ --> $DIR/unused-parens-false-positive-issue-143653.rs:3:9
+ |
+LL | #![deny(unused_parens)]
+ | ^^^^^^^^^^^^^
+help: remove these parentheses
+ |
+LL - fn bar(_: Box<dyn FnMut(&mut u32) -> &mut (dyn MyTrait)>) {}
+LL + fn bar(_: Box<dyn FnMut(&mut u32) -> &mut dyn MyTrait>) {}
+ |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/loop-match/suggest-const-item.rs b/tests/ui/loop-match/suggest-const-item.rs
new file mode 100644
index 0000000..f921b43
--- /dev/null
+++ b/tests/ui/loop-match/suggest-const-item.rs
@@ -0,0 +1,174 @@
+#![allow(incomplete_features)]
+#![feature(loop_match)]
+#![feature(generic_const_items)]
+#![crate_type = "lib"]
+
+const fn const_fn() -> i32 {
+ 1
+}
+
+#[unsafe(no_mangle)]
+fn suggest_const_block<const N: i32>() -> i32 {
+ let mut state = 0;
+ #[loop_match]
+ loop {
+ state = 'blk: {
+ match state {
+ 0 => {
+ #[const_continue]
+ break 'blk const_fn();
+ //~^ ERROR could not determine the target branch for this `#[const_continue]`
+ }
+ 1 => {
+ #[const_continue]
+ break 'blk const { const_fn() };
+ //~^ ERROR could not determine the target branch for this `#[const_continue]`
+ }
+ 2 => {
+ #[const_continue]
+ break 'blk N;
+ //~^ ERROR could not determine the target branch for this `#[const_continue]`
+ }
+ _ => {
+ #[const_continue]
+ break 'blk 1 + 1;
+ //~^ ERROR could not determine the target branch for this `#[const_continue]`
+ }
+ }
+ }
+ }
+ state
+}
+
+struct S;
+
+impl S {
+ const M: usize = 42;
+
+ fn g() {
+ let mut state = 0;
+ #[loop_match]
+ loop {
+ state = 'blk: {
+ match state {
+ 0 => {
+ #[const_continue]
+ break 'blk Self::M;
+ }
+ _ => panic!(),
+ }
+ }
+ }
+ }
+}
+
+trait T {
+ const N: usize;
+
+ fn f() {
+ let mut state = 0;
+ #[loop_match]
+ loop {
+ state = 'blk: {
+ match state {
+ 0 => {
+ #[const_continue]
+ break 'blk Self::N;
+ //~^ ERROR could not determine the target branch for this `#[const_continue]`
+ }
+ _ => panic!(),
+ }
+ }
+ }
+ }
+}
+
+impl T for S {
+ const N: usize = 1;
+}
+
+impl S {
+ fn h() {
+ let mut state = 0;
+ #[loop_match]
+ loop {
+ state = 'blk: {
+ match state {
+ 0 => {
+ #[const_continue]
+ break 'blk Self::N;
+ }
+ _ => panic!(),
+ }
+ }
+ }
+ }
+}
+
+trait T2<U> {
+ const L: u32;
+
+ fn p() {
+ let mut state = 0;
+ #[loop_match]
+ loop {
+ state = 'blk: {
+ match state {
+ 0 => {
+ #[const_continue]
+ break 'blk Self::L;
+ //~^ ERROR could not determine the target branch for this `#[const_continue]`
+ }
+ _ => panic!(),
+ }
+ }
+ }
+ }
+}
+
+const SIZE_OF<T>: usize = size_of::<T>();
+
+fn q<T>() {
+ let mut state = 0;
+ #[loop_match]
+ loop {
+ state = 'blk: {
+ match state {
+ 0 => {
+ #[const_continue]
+ break 'blk SIZE_OF::<T>;
+ //~^ ERROR could not determine the target branch for this `#[const_continue]`
+ }
+ _ => panic!(),
+ }
+ }
+ }
+}
+
+trait Trait<T> {
+ const X: usize = 9000;
+ const Y: usize = size_of::<T>();
+}
+
+impl<T> Trait<T> for () {}
+
+fn r<T>() {
+ let mut state = 0;
+ #[loop_match]
+ loop {
+ state = 'blk: {
+ match state {
+ 0 => {
+ #[const_continue]
+ break 'blk <() as Trait<T>>::X;
+ }
+ 1 => {
+ #[const_continue]
+ break 'blk <() as Trait<T>>::Y;
+ //~^ ERROR could not determine the target branch for this `#[const_continue]`
+ }
+ _ => panic!(),
+ }
+ }
+ }
+}
diff --git a/tests/ui/loop-match/suggest-const-item.stderr b/tests/ui/loop-match/suggest-const-item.stderr
new file mode 100644
index 0000000..7874744
--- /dev/null
+++ b/tests/ui/loop-match/suggest-const-item.stderr
@@ -0,0 +1,58 @@
+error: could not determine the target branch for this `#[const_continue]`
+ --> $DIR/suggest-const-item.rs:19:32
+ |
+LL | break 'blk const_fn();
+ | ^^^^^^^^^^ this value must be a literal or a monomorphic const
+ |
+ = help: try extracting the expression into a `const` item
+
+error: could not determine the target branch for this `#[const_continue]`
+ --> $DIR/suggest-const-item.rs:24:32
+ |
+LL | break 'blk const { const_fn() };
+ | ^^^^^^^^^^^^^^^^^^^^ `const` blocks may use generics, and are not evaluated early enough
+ |
+ = help: try extracting the expression into a `const` item
+
+error: could not determine the target branch for this `#[const_continue]`
+ --> $DIR/suggest-const-item.rs:29:32
+ |
+LL | break 'blk N;
+ | ^ constant parameters may use generics, and are not evaluated early enough
+ |
+ = help: try extracting the expression into a `const` item
+
+error: could not determine the target branch for this `#[const_continue]`
+ --> $DIR/suggest-const-item.rs:34:32
+ |
+LL | break 'blk 1 + 1;
+ | ^^^^^ this value must be a literal or a monomorphic const
+ |
+ = help: try extracting the expression into a `const` item
+
+error: could not determine the target branch for this `#[const_continue]`
+ --> $DIR/suggest-const-item.rs:76:36
+ |
+LL | break 'blk Self::N;
+ | ^^^^^^^ this value is too generic
+
+error: could not determine the target branch for this `#[const_continue]`
+ --> $DIR/suggest-const-item.rs:119:36
+ |
+LL | break 'blk Self::L;
+ | ^^^^^^^ this value is too generic
+
+error: could not determine the target branch for this `#[const_continue]`
+ --> $DIR/suggest-const-item.rs:139:32
+ |
+LL | break 'blk SIZE_OF::<T>;
+ | ^^^^^^^^^^^^ this value is too generic
+
+error: could not determine the target branch for this `#[const_continue]`
+ --> $DIR/suggest-const-item.rs:167:32
+ |
+LL | break 'blk <() as Trait<T>>::Y;
+ | ^^^^^^^^^^^^^^^^^^^ this value is too generic
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/loop-match/upvar-scrutinee.rs b/tests/ui/loop-match/upvar-scrutinee.rs
new file mode 100644
index 0000000..a93e3a0
--- /dev/null
+++ b/tests/ui/loop-match/upvar-scrutinee.rs
@@ -0,0 +1,81 @@
+#![allow(incomplete_features)]
+#![feature(loop_match)]
+
+#[derive(Clone, Copy)]
+enum State {
+ A,
+ B,
+}
+
+fn main() {
+ let mut state = State::A;
+
+ #[loop_match]
+ loop {
+ state = 'blk: {
+ match state {
+ State::A => {
+ #[const_continue]
+ break 'blk State::B;
+ }
+ State::B => {
+ return;
+ }
+ }
+ }
+ }
+
+ || {
+ #[loop_match]
+ loop {
+ state = 'blk: {
+ match state {
+ //~^ ERROR invalid match on `#[loop_match]` state
+ State::A => {
+ #[const_continue]
+ break 'blk State::B;
+ }
+ State::B => {
+ return;
+ }
+ }
+ }
+ }
+ };
+
+ || {
+ let mut state = state;
+ #[loop_match]
+ loop {
+ state = 'blk: {
+ match state {
+ State::A => {
+ #[const_continue]
+ break 'blk State::B;
+ }
+ State::B => {
+ return;
+ }
+ }
+ }
+ }
+ };
+
+ move || {
+ #[loop_match]
+ loop {
+ state = 'blk: {
+ match state {
+ //~^ ERROR invalid match on `#[loop_match]` state
+ State::A => {
+ #[const_continue]
+ break 'blk State::B;
+ }
+ State::B => {
+ return;
+ }
+ }
+ }
+ }
+ };
+}
diff --git a/tests/ui/loop-match/upvar-scrutinee.stderr b/tests/ui/loop-match/upvar-scrutinee.stderr
new file mode 100644
index 0000000..b7a0a90
--- /dev/null
+++ b/tests/ui/loop-match/upvar-scrutinee.stderr
@@ -0,0 +1,18 @@
+error: invalid match on `#[loop_match]` state
+ --> $DIR/upvar-scrutinee.rs:32:23
+ |
+LL | match state {
+ | ^^^^^
+ |
+ = note: a local variable must be the scrutinee within a `#[loop_match]`
+
+error: invalid match on `#[loop_match]` state
+ --> $DIR/upvar-scrutinee.rs:68:23
+ |
+LL | match state {
+ | ^^^^^
+ |
+ = note: a local variable must be the scrutinee within a `#[loop_match]`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lto/all-crates.rs b/tests/ui/lto/all-crates.rs
index ceabf9f..fa17684 100644
--- a/tests/ui/lto/all-crates.rs
+++ b/tests/ui/lto/all-crates.rs
@@ -2,6 +2,7 @@
//@ compile-flags: -Clto=thin
//@ no-prefer-dynamic
+//@ ignore-backends: gcc
fn main() {
println!("hello!");
diff --git a/tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs b/tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs
index a38d0e2..8579fd5 100644
--- a/tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs
+++ b/tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs
@@ -1,3 +1,4 @@
+//@ ignore-backends: gcc
//@ compile-flags: -C lto=thin
//@ aux-build:lto-rustc-loads-linker-plugin.rs
//@ run-pass
diff --git a/tests/ui/lto/thin-lto-inlines2.rs b/tests/ui/lto/thin-lto-inlines2.rs
index 735557a..4c7b927 100644
--- a/tests/ui/lto/thin-lto-inlines2.rs
+++ b/tests/ui/lto/thin-lto-inlines2.rs
@@ -4,6 +4,7 @@
//@ aux-build:thin-lto-inlines-aux.rs
//@ no-prefer-dynamic
//@ ignore-emscripten can't inspect instructions on emscripten
+//@ ignore-backends: gcc
// We want to assert here that ThinLTO will inline across codegen units. There's
// not really a great way to do that in general so we sort of hack around it by
diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.stderr b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr
index a2c281d..795d994 100644
--- a/tests/ui/macros/expr_2021_cargo_fix_edition.stderr
+++ b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr
@@ -5,7 +5,7 @@
| ^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see Migration Guide <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/macro-fragment-specifiers.html>
+ = note: for more information, see Migration Guide <https://doc.rust-lang.org/edition-guide/rust-2024/macro-fragment-specifiers.html>
note: the lint level is defined here
--> $DIR/expr_2021_cargo_fix_edition.rs:4:9
|
@@ -23,7 +23,7 @@
| ^^^^
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see Migration Guide <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/macro-fragment-specifiers.html>
+ = note: for more information, see Migration Guide <https://doc.rust-lang.org/edition-guide/rust-2024/macro-fragment-specifiers.html>
help: to keep the existing behavior, use the `expr_2021` fragment specifier
|
LL | ($($i:expr_2021)*) => { };
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 6b03001..ba93384 100644
--- a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout
+++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ compile-flags: -Zunpretty=hir
//@ edition: 2015
diff --git a/tests/ui/issues/issue-34418.rs b/tests/ui/macros/macro-invocation-with-curly-braces-34418.rs
similarity index 78%
rename from tests/ui/issues/issue-34418.rs
rename to tests/ui/macros/macro-invocation-with-curly-braces-34418.rs
index 0dcefb0..46dbdd3 100644
--- a/tests/ui/issues/issue-34418.rs
+++ b/tests/ui/macros/macro-invocation-with-curly-braces-34418.rs
@@ -17,3 +17,5 @@ fn g() {
}
fn main() {}
+
+// https://github.com/rust-lang/rust/issues/34418
diff --git a/tests/ui/macros/macro-or-patterns-back-compat.stderr b/tests/ui/macros/macro-or-patterns-back-compat.stderr
index e04dfef..67794f0 100644
--- a/tests/ui/macros/macro-or-patterns-back-compat.stderr
+++ b/tests/ui/macros/macro-or-patterns-back-compat.stderr
@@ -5,7 +5,7 @@
| ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html>
note: the lint level is defined here
--> $DIR/macro-or-patterns-back-compat.rs:4:9
|
@@ -19,7 +19,7 @@
| ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html>
error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
--> $DIR/macro-or-patterns-back-compat.rs:19:21
@@ -28,7 +28,7 @@
| ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html>
error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
--> $DIR/macro-or-patterns-back-compat.rs:23:26
@@ -37,7 +37,7 @@
| ^^^^^^^^ help: use pat_param to preserve semantics: `$pat:pat_param`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html>
error: aborting due to 4 previous errors
diff --git a/tests/ui/macros/non-fmt-panic.stderr b/tests/ui/macros/non-fmt-panic.stderr
index 30b63cb..83410d3 100644
--- a/tests/ui/macros/non-fmt-panic.stderr
+++ b/tests/ui/macros/non-fmt-panic.stderr
@@ -74,7 +74,7 @@
| ^
|
= note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | assert!(false, "{}", S);
@@ -87,7 +87,7 @@
| ^^^
|
= note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | assert!(false, "{}", 123);
@@ -100,7 +100,7 @@
| ^^^^^^^^^
|
= note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{:?}" format string to use the `Debug` implementation of `Option<i32>`
|
LL | assert!(false, "{:?}", Some(123));
@@ -125,7 +125,7 @@
| ^
|
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | panic!("{}", C);
@@ -138,7 +138,7 @@
| ^
|
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | panic!("{}", S);
@@ -151,7 +151,7 @@
| ^
|
= note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | unreachable!("{}", S);
@@ -164,7 +164,7 @@
| ^
|
= note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | unreachable!("{}", S);
@@ -177,7 +177,7 @@
| ^^^
|
= note: this usage of `std::panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | std::panic!("{}", 123);
@@ -195,7 +195,7 @@
| ^^^^^^^
|
= note: this usage of `core::panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | core::panic!("{}", &*"abc");
@@ -208,7 +208,7 @@
| ^^^^^^^^^
|
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{:?}" format string to use the `Debug` implementation of `Option<i32>`
|
LL | panic!("{:?}", Some(123));
@@ -262,7 +262,7 @@
| ^^^^
|
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | panic!("{}", a!());
@@ -280,7 +280,7 @@
| ^^^^
|
= note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | unreachable!("{}", a!());
@@ -293,7 +293,7 @@
| ^^^^^^^^^^^^^^^^
|
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
= note: the `panic!()` macro supports formatting, so there's no need for the `format!()` macro here
help: remove the `format!(..)` macro call
|
@@ -308,7 +308,7 @@
| ^^^^^^^^^^^^^^^^
|
= note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
= note: the `unreachable!()` macro supports formatting, so there's no need for the `format!()` macro here
help: remove the `format!(..)` macro call
|
@@ -323,7 +323,7 @@
| ^^^^^^^^^^^^^^^^
|
= note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
= note: the `assert!()` macro supports formatting, so there's no need for the `format!()` macro here
help: remove the `format!(..)` macro call
|
@@ -338,7 +338,7 @@
| ^^^^^^^^^^^^^^^^
|
= note: this usage of `debug_assert!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
= note: the `debug_assert!()` macro supports formatting, so there's no need for the `format!()` macro here
help: remove the `format!(..)` macro call
|
@@ -353,7 +353,7 @@
| ^^^
|
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | panic!["{}", 123];
@@ -371,7 +371,7 @@
| ^^^
|
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | panic!{"{}", 123};
@@ -391,7 +391,7 @@
| help: use std::panic::panic_any instead: `std::panic::panic_any`
|
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
warning: panic message is not a string literal
--> $DIR/non-fmt-panic.rs:79:20
@@ -400,7 +400,7 @@
| ^
|
= note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
warning: panic message is not a string literal
--> $DIR/non-fmt-panic.rs:83:12
@@ -409,7 +409,7 @@
| ^
|
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{:?}" format string to use the `Debug` implementation of `T`
|
LL | panic!("{:?}", v);
@@ -427,7 +427,7 @@
| ^
|
= note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{:?}" format string to use the `Debug` implementation of `T`
|
LL | assert!(false, "{:?}", v);
@@ -440,7 +440,7 @@
| ^
|
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | panic!("{}", v);
@@ -458,7 +458,7 @@
| ^
|
= note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | assert!(false, "{}", v);
@@ -471,7 +471,7 @@
| ^
|
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | panic!("{}", v);
@@ -489,7 +489,7 @@
| ^
|
= note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
|
LL | assert!(false, "{}", v);
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 33193c7..e29655f 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
@@ -5,10 +5,10 @@
//@ edition: 2015
#![feature(core_intrinsics, generic_assert)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
fn arbitrary_consuming_method_for_demonstration_purposes() {
let elem = 1i32;
diff --git a/tests/ui/macros/trace-macro.rs b/tests/ui/macros/trace-macro.rs
index ecc6aab..a85f8f4 100644
--- a/tests/ui/macros/trace-macro.rs
+++ b/tests/ui/macros/trace-macro.rs
@@ -3,4 +3,7 @@
fn main() {
println!("Hello, World!");
+ //~^ NOTE trace_macro
+ //~| NOTE expanding `println!
+ //~| NOTE to `{
}
diff --git a/tests/ui/issues/issue-106755.rs b/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.rs
similarity index 91%
rename from tests/ui/issues/issue-106755.rs
rename to tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.rs
index d7e7122..891b8c1 100644
--- a/tests/ui/issues/issue-106755.rs
+++ b/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.rs
@@ -20,3 +20,5 @@ impl !Send for TestType<i32> {}
//~^ ERROR `!Send` impls cannot be specialized
fn main() {}
+
+// https://github.com/rust-lang/rust/issues/106755
diff --git a/tests/ui/issues/issue-106755.stderr b/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.stderr
similarity index 79%
copy from tests/ui/issues/issue-106755.stderr
copy to tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.stderr
index da6b8c5..100b3bf 100644
--- a/tests/ui/issues/issue-106755.stderr
+++ b/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.stderr
@@ -1,5 +1,5 @@
error[E0751]: found both positive and negative implementation of trait `Send` for type `TestType<_>`:
- --> $DIR/issue-106755.rs:13:1
+ --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:13:1
|
LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
| ------------------------------------------------------ positive implementation here
@@ -8,7 +8,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here
error[E0119]: conflicting implementations of trait `Send` for type `TestType<_>`
- --> $DIR/issue-106755.rs:17:1
+ --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:17:1
|
LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
| ------------------------------------------------------ first implementation here
@@ -17,26 +17,26 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>`
error[E0367]: `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not
- --> $DIR/issue-106755.rs:13:9
+ --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:13:9
|
LL | impl<T: MyTrait> !Send for TestType<T> {}
| ^^^^^^^
|
note: the implementor must specify the same requirement
- --> $DIR/issue-106755.rs:9:1
+ --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:9:1
|
LL | struct TestType<T>(::std::marker::PhantomData<T>);
| ^^^^^^^^^^^^^^^^^^
error[E0366]: `!Send` impls cannot be specialized
- --> $DIR/issue-106755.rs:19:1
+ --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:19:1
|
LL | impl !Send for TestType<i32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `i32` is not a generic parameter
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
- --> $DIR/issue-106755.rs:9:1
+ --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:9:1
|
LL | struct TestType<T>(::std::marker::PhantomData<T>);
| ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/issues/issue-46964.rs b/tests/ui/match/innocent-looking-match-crash-46964.rs
similarity index 87%
rename from tests/ui/issues/issue-46964.rs
rename to tests/ui/match/innocent-looking-match-crash-46964.rs
index 6a29d91..c3efe87 100644
--- a/tests/ui/issues/issue-46964.rs
+++ b/tests/ui/match/innocent-looking-match-crash-46964.rs
@@ -17,3 +17,5 @@ pub fn crash() -> bool {
}
fn main() {}
+
+// https://github.com/rust-lang/rust/issues/46964
diff --git a/tests/ui/match/issue-82392.stdout b/tests/ui/match/issue-82392.stdout
index 3efc964..d7eef04 100644
--- a/tests/ui/match/issue-82392.stdout
+++ b/tests/ui/match/issue-82392.stdout
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
// https://github.com/rust-lang/rust/issues/82329
//@ compile-flags: -Zunpretty=hir,typed
//@ check-pass
diff --git a/tests/ui/issues/issue-53843.rs b/tests/ui/methods/inherent-method-resolution-on-deref-type-53843.rs
similarity index 85%
rename from tests/ui/issues/issue-53843.rs
rename to tests/ui/methods/inherent-method-resolution-on-deref-type-53843.rs
index d4b0b1e..0b2ab9a 100644
--- a/tests/ui/issues/issue-53843.rs
+++ b/tests/ui/methods/inherent-method-resolution-on-deref-type-53843.rs
@@ -24,3 +24,5 @@ fn main() {
let pin = Pin(&mut unit);
pin.poll();
}
+
+// https://github.com/rust-lang/rust/issues/53843
diff --git a/tests/ui/mir/mir_drop_order.rs b/tests/ui/mir/mir_drop_order.rs
index 21d1054c..a7a1a26 100644
--- a/tests/ui/mir/mir_drop_order.rs
+++ b/tests/ui/mir/mir_drop_order.rs
@@ -1,5 +1,6 @@
//@ run-pass
//@ needs-unwind
+//@ ignore-backends: gcc
use std::cell::RefCell;
use std::panic;
diff --git a/tests/ui/mir/mir_let_chains_drop_order.rs b/tests/ui/mir/mir_let_chains_drop_order.rs
index 8a54f21..1579e29 100644
--- a/tests/ui/mir/mir_let_chains_drop_order.rs
+++ b/tests/ui/mir/mir_let_chains_drop_order.rs
@@ -1,5 +1,6 @@
//@ run-pass
//@ needs-unwind
+//@ ignore-backends: gcc
//@ edition: 2024
// See `mir_drop_order.rs` for more information
diff --git a/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs b/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs
index e98d57d..3196513 100644
--- a/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs
+++ b/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs
@@ -1,5 +1,6 @@
//@ run-pass
//@ needs-unwind
+//@ ignore-backends: gcc
//@ revisions: edition2021 edition2024
//@ [edition2021] edition: 2021
//@ [edition2024] edition: 2024
diff --git a/tests/ui/mir/static-by-value-dyn.rs b/tests/ui/mir/static-by-value-dyn.rs
new file mode 100644
index 0000000..f1154ef
--- /dev/null
+++ b/tests/ui/mir/static-by-value-dyn.rs
@@ -0,0 +1,14 @@
+//! Regression test for #121176
+//! KnownPanicsLint used to assert ABI compatibility in the interpreter,
+//! which ICEs with unsized statics.
+//@ needs-rustc-debug-assertions
+
+use std::fmt::Debug;
+
+static STATIC_1: dyn Debug + Sync = *();
+//~^ ERROR the size for values of type `(dyn Debug + Sync + 'static)` cannot be known
+//~| ERROR type `()` cannot be dereferenced
+
+fn main() {
+ println!("{:?}", &STATIC_1);
+}
diff --git a/tests/ui/mir/static-by-value-dyn.stderr b/tests/ui/mir/static-by-value-dyn.stderr
new file mode 100644
index 0000000..25ed813
--- /dev/null
+++ b/tests/ui/mir/static-by-value-dyn.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time
+ --> $DIR/static-by-value-dyn.rs:8:1
+ |
+LL | static STATIC_1: dyn Debug + Sync = *();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)`
+ = note: statics and constants must have a statically known size
+
+error[E0614]: type `()` cannot be dereferenced
+ --> $DIR/static-by-value-dyn.rs:8:37
+ |
+LL | static STATIC_1: dyn Debug + Sync = *();
+ | ^^^ can't be dereferenced
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0614.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/mir/static-by-value-slice.rs b/tests/ui/mir/static-by-value-slice.rs
new file mode 100644
index 0000000..af98be6
--- /dev/null
+++ b/tests/ui/mir/static-by-value-slice.rs
@@ -0,0 +1,10 @@
+//! Regression test for #140332
+//! KnownPanicsLint used to assert ABI compatibility in the interpreter,
+//! which ICEs with unsized statics.
+
+static mut S: [i8] = ["Some thing"; 1];
+//~^ ERROR the size for values of type `[i8]` cannot be known
+
+fn main() {
+ assert_eq!(S, [0; 1]);
+}
diff --git a/tests/ui/mir/static-by-value-slice.stderr b/tests/ui/mir/static-by-value-slice.stderr
new file mode 100644
index 0000000..2d05929
--- /dev/null
+++ b/tests/ui/mir/static-by-value-slice.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the size for values of type `[i8]` cannot be known at compilation time
+ --> $DIR/static-by-value-slice.rs:5:1
+ |
+LL | static mut S: [i8] = ["Some thing"; 1];
+ | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[i8]`
+ = note: statics and constants must have a statically known size
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/mir/static-by-value-str.rs b/tests/ui/mir/static-by-value-str.rs
new file mode 100644
index 0000000..88b72f9
--- /dev/null
+++ b/tests/ui/mir/static-by-value-str.rs
@@ -0,0 +1,15 @@
+//! Regression test for #139872
+//! KnownPanicsLint used to assert ABI compatibility in the interpreter,
+//! which ICEs with unsized statics.
+
+enum E {
+ V16(u16),
+ V32(u32),
+}
+
+static C: (E, u16, str) = (E::V16(0xDEAD), 0x600D, 0xBAD);
+//~^ ERROR the size for values of type `str` cannot be known
+
+pub fn main() {
+ let (_, n, _) = C;
+}
diff --git a/tests/ui/mir/static-by-value-str.stderr b/tests/ui/mir/static-by-value-str.stderr
new file mode 100644
index 0000000..6e046e0
--- /dev/null
+++ b/tests/ui/mir/static-by-value-str.stderr
@@ -0,0 +1,13 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+ --> $DIR/static-by-value-str.rs:10:1
+ |
+LL | static C: (E, u16, str) = (E::V16(0xDEAD), 0x600D, 0xBAD);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: within `(E, u16, str)`, the trait `Sized` is not implemented for `str`
+ = note: required because it appears within the type `(E, u16, str)`
+ = note: statics and constants must have a statically known size
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/mir/unsized-extern-static.rs b/tests/ui/mir/unsized-extern-static.rs
new file mode 100644
index 0000000..3868425
--- /dev/null
+++ b/tests/ui/mir/unsized-extern-static.rs
@@ -0,0 +1,13 @@
+//! Regression test for #129109
+//! MIR building used to produce erroneous constants when referring to statics of unsized type.
+//@ compile-flags: -Zmir-enable-passes=+GVN -Zvalidate-mir
+
+extern "C" {
+ pub static mut symbol: [i8];
+ //~^ ERROR the size for values of type `[i8]`
+}
+
+fn main() {
+ println!("C", unsafe { &symbol });
+ //~^ ERROR argument never used
+}
diff --git a/tests/ui/mir/unsized-extern-static.stderr b/tests/ui/mir/unsized-extern-static.stderr
new file mode 100644
index 0000000..93aed35
--- /dev/null
+++ b/tests/ui/mir/unsized-extern-static.stderr
@@ -0,0 +1,20 @@
+error: argument never used
+ --> $DIR/unsized-extern-static.rs:11:19
+ |
+LL | println!("C", unsafe { &symbol });
+ | --- ^^^^^^^^^^^^^^^^^^ argument never used
+ | |
+ | formatting specifier missing
+
+error[E0277]: the size for values of type `[i8]` cannot be known at compilation time
+ --> $DIR/unsized-extern-static.rs:6:5
+ |
+LL | pub static mut symbol: [i8];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[i8]`
+ = note: statics and constants must have a statically known size
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/modules/issue-107649.stderr b/tests/ui/modules/issue-107649.stderr
index 802ac66..49d7cb4 100644
--- a/tests/ui/modules/issue-107649.stderr
+++ b/tests/ui/modules/issue-107649.stderr
@@ -9,8 +9,8 @@
help: consider annotating `Dummy` with `#[derive(Debug)]`
--> $DIR/auxiliary/dummy_lib.rs:2:1
|
-2 + #[derive(Debug)]
-3 | pub struct Dummy;
+ 2 + #[derive(Debug)]
+ 3 | pub struct Dummy;
|
error: aborting due to 1 previous error
diff --git a/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
index 523134a..51d0f85 100644
--- a/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
+++ b/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
@@ -2,9 +2,11 @@
--> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:9:28
|
LL | let i = Box::new(3);
- | - captured outer variable
+ | - ----------- move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait
+ | |
+ | captured outer variable
LL | let _f = to_fn(|| test(i));
- | -- ^ move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait
+ | -- ^ `i` is moved here
| |
| captured by this `Fn` closure
|
diff --git a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr
index c626796..6272455 100644
--- a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr
+++ b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr
@@ -8,6 +8,14 @@
|
note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
+note: if `Hash128_1` implemented `Clone`, you could clone the value
+ --> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:8:1
+ |
+LL | pub struct Hash128_1;
+ | ^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let mut copy: Vec<U> = map.clone().into_values().collect();
+ | ----------- you could clone this value
help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied
|
LL - let mut copy: Vec<U> = map.clone().into_values().collect();
diff --git a/tests/ui/never_type/defaulted-never-note.nofallback.stderr b/tests/ui/never_type/defaulted-never-note.nofallback.stderr
index 6de323a..b7df6fb 100644
--- a/tests/ui/never_type/defaulted-never-note.nofallback.stderr
+++ b/tests/ui/never_type/defaulted-never-note.nofallback.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: ImplementedForUnitButNotNever` will fail
--> $DIR/defaulted-never-note.rs:32:9
@@ -28,7 +28,7 @@
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: ImplementedForUnitButNotNever` will fail
--> $DIR/defaulted-never-note.rs:32:9
diff --git a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr
index be80756..6ee57d5 100644
--- a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr
+++ b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/dependency-on-fallback-to-unit.rs:12:19
@@ -26,7 +26,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/dependency-on-fallback-to-unit.rs:22:5
@@ -48,7 +48,7 @@
| ^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/dependency-on-fallback-to-unit.rs:12:19
@@ -70,7 +70,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/dependency-on-fallback-to-unit.rs:22:5
diff --git a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr
index 44ebdb4..64a8ecd 100644
--- a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr
+++ b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: UnitDefault` will fail
--> $DIR/diverging-fallback-control-flow.rs:36:13
@@ -25,7 +25,7 @@
| ^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: UnitDefault` will fail
--> $DIR/diverging-fallback-control-flow.rs:50:13
@@ -47,7 +47,7 @@
| ^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: UnitDefault` will fail
--> $DIR/diverging-fallback-control-flow.rs:36:13
@@ -68,7 +68,7 @@
| ^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: UnitDefault` will fail
--> $DIR/diverging-fallback-control-flow.rs:50:13
diff --git a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr
index 4a8dea4..ec48c38 100644
--- a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr
+++ b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Test` will fail
--> $DIR/diverging-fallback-no-leak.rs:20:23
@@ -28,7 +28,7 @@
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Test` will fail
--> $DIR/diverging-fallback-no-leak.rs:20:23
diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr
index 803af39..48debdd 100644
--- a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr
+++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: UnitReturn` will fail
--> $DIR/diverging-fallback-unconstrained-return.rs:39:23
@@ -28,7 +28,7 @@
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: UnitReturn` will fail
--> $DIR/diverging-fallback-unconstrained-return.rs:39:23
diff --git a/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr b/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr
index 365e886..d2d108e 100644
--- a/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr
+++ b/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/dont-suggest-turbofish-from-expansion.rs:14:23
@@ -32,7 +32,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/dont-suggest-turbofish-from-expansion.rs:14:23
diff --git a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr
index cf19363..5651a26 100644
--- a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr
+++ b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Bar` will fail
--> $DIR/fallback-closure-ret.rs:24:5
@@ -28,7 +28,7 @@
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Bar` will fail
--> $DIR/fallback-closure-ret.rs:24:5
diff --git a/tests/ui/never_type/impl_trait_fallback.stderr b/tests/ui/never_type/impl_trait_fallback.stderr
index 7250db1..36d2eae 100644
--- a/tests/ui/never_type/impl_trait_fallback.stderr
+++ b/tests/ui/never_type/impl_trait_fallback.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: T` will fail
--> $DIR/impl_trait_fallback.rs:8:25
@@ -24,7 +24,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: T` will fail
--> $DIR/impl_trait_fallback.rs:8:25
diff --git a/tests/ui/never_type/lint-breaking-2024-assign-underscore.stderr b/tests/ui/never_type/lint-breaking-2024-assign-underscore.stderr
index 945db40..6a85b99 100644
--- a/tests/ui/never_type/lint-breaking-2024-assign-underscore.stderr
+++ b/tests/ui/never_type/lint-breaking-2024-assign-underscore.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/lint-breaking-2024-assign-underscore.rs:13:9
@@ -32,7 +32,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/lint-breaking-2024-assign-underscore.rs:13:9
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
index c90efd2..48734f3 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -20,7 +20,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
help: use `()` annotations to avoid fallback changes
|
@@ -34,7 +34,7 @@
| ^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
warning: never type fallback affects this raw pointer dereference
@@ -44,7 +44,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
help: use `()` annotations to avoid fallback changes
|
@@ -58,7 +58,7 @@
| ^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
help: use `()` annotations to avoid fallback changes
|
@@ -72,7 +72,7 @@
| ^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
help: use `()` annotations to avoid fallback changes
|
@@ -86,7 +86,7 @@
| ^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
help: use `()` annotations to avoid fallback changes
|
@@ -100,7 +100,7 @@
| ^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
help: use `()` annotations to avoid fallback changes
|
@@ -114,7 +114,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
warning: never type fallback affects this call to an `unsafe` function
@@ -127,7 +127,7 @@
| ----------- in this macro invocation
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: this warning originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -141,7 +141,7 @@
| ^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -157,7 +157,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -173,7 +173,7 @@
| ^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
@@ -185,7 +185,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -201,7 +201,7 @@
| ^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -217,7 +217,7 @@
| ^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -233,7 +233,7 @@
| ^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -249,7 +249,7 @@
| ^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -265,7 +265,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
@@ -280,7 +280,7 @@
| ----------- in this macro invocation
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
= note: this warning originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
index 858d738..8039ef4 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -20,7 +20,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
help: use `()` annotations to avoid fallback changes
|
@@ -34,7 +34,7 @@
| ^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
error: never type fallback affects this raw pointer dereference
@@ -44,7 +44,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
help: use `()` annotations to avoid fallback changes
|
@@ -58,7 +58,7 @@
| ^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
help: use `()` annotations to avoid fallback changes
|
@@ -72,7 +72,7 @@
| ^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
help: use `()` annotations to avoid fallback changes
|
@@ -86,7 +86,7 @@
| ^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
help: use `()` annotations to avoid fallback changes
|
@@ -100,7 +100,7 @@
| ^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
help: use `()` annotations to avoid fallback changes
|
@@ -114,7 +114,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
error: never type fallback affects this call to an `unsafe` function
@@ -127,7 +127,7 @@
| ----------- in this macro invocation
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -150,7 +150,7 @@
| ^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -166,7 +166,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -182,7 +182,7 @@
| ^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
@@ -194,7 +194,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -210,7 +210,7 @@
| ^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -226,7 +226,7 @@
| ^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -242,7 +242,7 @@
| ^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -258,7 +258,7 @@
| ^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
help: use `()` annotations to avoid fallback changes
@@ -274,7 +274,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
@@ -289,7 +289,7 @@
| ----------- in this macro invocation
|
= warning: this changes meaning in Rust 2024 and in a future release in all editions!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
= help: specify the type explicitly
= note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
= note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr
index 8268f5d..331c651 100644
--- a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr
+++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr
@@ -4,7 +4,7 @@
LL | S1 { a: unsafe { &mut X1 } }
| ^^^^^^^ mutable reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
= note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
= note: `#[warn(static_mut_refs)]` on by default
help: use `&raw mut` instead to create a raw pointer
diff --git a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
index a445534..2742162c 100644
--- a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
+++ b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
@@ -9,6 +9,9 @@
for<Region(BrAnon), Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 mut &'^1 i32, &'^2 i32)),
(),
]
+ = note: late-bound region is '?1
+ = note: late-bound region is '?2
+ = note: late-bound region is '?3
error: lifetime may not live long enough
--> $DIR/escape-argument-callee.rs:26:45
diff --git a/tests/ui/nll/closure-requirements/escape-argument.stderr b/tests/ui/nll/closure-requirements/escape-argument.stderr
index 7fd1cd8..22cb036 100644
--- a/tests/ui/nll/closure-requirements/escape-argument.stderr
+++ b/tests/ui/nll/closure-requirements/escape-argument.stderr
@@ -9,6 +9,8 @@
for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 mut &'^1 i32, &'^1 i32)),
(),
]
+ = note: late-bound region is '?1
+ = note: late-bound region is '?2
note: no external requirements
--> $DIR/escape-argument.rs:20:1
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
index 60087ec..134ce99 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
@@ -9,6 +9,8 @@
for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((std::cell::Cell<&'?1 &'^0 u32>, std::cell::Cell<&'?2 &'^0 u32>, std::cell::Cell<&'^1 &'?3 u32>, std::cell::Cell<&'^0 u32>, std::cell::Cell<&'^1 u32>)),
(),
]
+ = note: late-bound region is '?7
+ = note: late-bound region is '?8
= note: late-bound region is '?4
= note: late-bound region is '?5
= note: late-bound region is '?6
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
index 7325a9d..f5527ee 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
@@ -9,6 +9,12 @@
for<Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 std::cell::Cell<&'?1 &'^1 u32>, &'^2 std::cell::Cell<&'^3 &'?2 u32>, &'^4 std::cell::Cell<&'^1 u32>, &'^5 std::cell::Cell<&'^3 u32>)),
(),
]
+ = note: late-bound region is '?5
+ = note: late-bound region is '?6
+ = note: late-bound region is '?7
+ = note: late-bound region is '?8
+ = note: late-bound region is '?9
+ = note: late-bound region is '?10
= note: late-bound region is '?3
= note: late-bound region is '?4
= note: number of external vids: 5
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index 621c1ea..e13653f 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -9,6 +9,7 @@
for<Region(BrAnon)> extern "rust-call" fn((std::cell::Cell<&'?1 u32>, std::cell::Cell<&'^0 u32>)),
(),
]
+ = note: late-bound region is '?2
error[E0521]: borrowed data escapes outside of closure
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:22:9
@@ -43,6 +44,7 @@
for<Region(BrAnon)> extern "rust-call" fn((std::cell::Cell<&'?1 u32>, std::cell::Cell<&'^0 u32>)),
(),
]
+ = note: late-bound region is '?2
= note: number of external vids: 2
= note: where '?1: '?0
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index b9365c9..9e9eae9 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -9,6 +9,11 @@
for<Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 std::cell::Cell<&'?1 &'^1 u32>, &'^2 std::cell::Cell<&'^1 u32>, &'^3 std::cell::Cell<&'^4 u32>)),
(),
]
+ = note: late-bound region is '?4
+ = note: late-bound region is '?5
+ = note: late-bound region is '?6
+ = note: late-bound region is '?7
+ = note: late-bound region is '?8
= note: late-bound region is '?2
= note: late-bound region is '?3
= note: number of external vids: 4
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index e5d2867..303fcd4 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -9,6 +9,12 @@
for<Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 std::cell::Cell<&'?1 &'^1 u32>, &'^2 std::cell::Cell<&'?2 &'^3 u32>, &'^4 std::cell::Cell<&'^1 u32>, &'^5 std::cell::Cell<&'^3 u32>)),
(),
]
+ = note: late-bound region is '?5
+ = note: late-bound region is '?6
+ = note: late-bound region is '?7
+ = note: late-bound region is '?8
+ = note: late-bound region is '?9
+ = note: late-bound region is '?10
= note: late-bound region is '?3
= note: late-bound region is '?4
= note: number of external vids: 5
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
index a14bfb0..aa75b4c 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
@@ -9,6 +9,8 @@
for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((std::cell::Cell<&'?1 &'^0 u32>, std::cell::Cell<&'^1 &'?2 u32>, std::cell::Cell<&'^0 u32>, std::cell::Cell<&'^1 u32>)),
(),
]
+ = note: late-bound region is '?5
+ = note: late-bound region is '?6
= note: late-bound region is '?3
= note: late-bound region is '?4
= note: number of external vids: 5
diff --git a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
index 49c65d7..30ee259 100644
--- a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
@@ -9,6 +9,8 @@
for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((std::cell::Cell<&'?1 &'^0 u32>, std::cell::Cell<&'^1 &'?2 u32>, std::cell::Cell<&'^0 u32>, std::cell::Cell<&'^1 u32>)),
(),
]
+ = note: late-bound region is '?4
+ = note: late-bound region is '?5
= note: late-bound region is '?3
= note: number of external vids: 4
= note: where '?1: '?2
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
index f48ed28..6b04e34 100644
--- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
@@ -9,6 +9,11 @@
for<Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 std::cell::Cell<&'^1 &'?1 u32>, &'^2 std::cell::Cell<&'^3 u32>, &'^4 std::cell::Cell<&'^1 u32>)),
(),
]
+ = note: late-bound region is '?4
+ = note: late-bound region is '?5
+ = note: late-bound region is '?6
+ = note: late-bound region is '?7
+ = note: late-bound region is '?8
= note: late-bound region is '?2
= note: late-bound region is '?3
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
index a090e94..ae2129c 100644
--- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
@@ -9,6 +9,12 @@
for<Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 std::cell::Cell<&'^1 &'?1 u32>, &'^2 std::cell::Cell<&'^3 &'?2 u32>, &'^4 std::cell::Cell<&'^1 u32>, &'^5 std::cell::Cell<&'^3 u32>)),
(),
]
+ = note: late-bound region is '?5
+ = note: late-bound region is '?6
+ = note: late-bound region is '?7
+ = note: late-bound region is '?8
+ = note: late-bound region is '?9
+ = note: late-bound region is '?10
= note: late-bound region is '?3
= note: late-bound region is '?4
diff --git a/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr
index bc5c04a..1f1cce1 100644
--- a/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr
+++ b/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr
@@ -9,6 +9,8 @@
for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 i32, &'^1 i32)) -> &'^0 i32,
(),
]
+ = note: late-bound region is '?1
+ = note: late-bound region is '?2
error: lifetime may not live long enough
--> $DIR/return-wrong-bound-region.rs:11:23
diff --git a/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr b/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
index 63f230b..3363c4e 100644
--- a/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
+++ b/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
@@ -27,6 +27,15 @@
| - value moved here
LL | d.x = 10;
| ^^^^^^^^ value assigned here after move
+ |
+note: if `D` implemented `Clone`, you could clone the value
+ --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:11:1
+ |
+LL | struct D {
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | drop(d);
+ | - you could clone this value
error[E0381]: partially assigned binding `d` isn't fully initialized
--> $DIR/issue-21232-partial-init-and-erroneous-use.rs:45:5
@@ -57,6 +66,15 @@
| - value moved here
LL | d.s.y = 20;
| ^^^^^^^^^^ value partially assigned here after move
+ |
+note: if `D` implemented `Clone`, you could clone the value
+ --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:11:1
+ |
+LL | struct D {
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | drop(d);
+ | - you could clone this value
error: aborting due to 6 previous errors
diff --git a/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr b/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr
index fbaec8a..5754603 100644
--- a/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr
+++ b/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr
@@ -2,9 +2,11 @@
--> $DIR/issue-52663-span-decl-captured-variable.rs:8:26
|
LL | let x = (vec![22], vec![44]);
- | - captured outer variable
+ | - -------------------- move occurs because `x.0` has type `Vec<i32>`, which does not implement the `Copy` trait
+ | |
+ | captured outer variable
LL | expect_fn(|| drop(x.0));
- | -- ^^^ move occurs because `x.0` has type `Vec<i32>`, which does not implement the `Copy` trait
+ | -- ^^^ `x.0` is moved here
| |
| captured by this `Fn` closure
|
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
index e587643..396e149 100644
--- a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
@@ -9,6 +9,8 @@
for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'?1 &'^0 ()>>, &'^1 T)),
(),
]
+ = note: late-bound region is '?2
+ = note: late-bound region is '?3
= note: number of external vids: 2
= note: where T: '?1
@@ -31,6 +33,8 @@
for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'?1 &'^0 ()>>, &'^1 T)),
(),
]
+ = note: late-bound region is '?3
+ = note: late-bound region is '?4
= note: late-bound region is '?2
= note: number of external vids: 3
= note: where T: '?1
diff --git a/tests/ui/numbers-arithmetic/u128-as-f32.rs b/tests/ui/numbers-arithmetic/u128-as-f32.rs
index 88579f5..57c82d5 100644
--- a/tests/ui/numbers-arithmetic/u128-as-f32.rs
+++ b/tests/ui/numbers-arithmetic/u128-as-f32.rs
@@ -1,4 +1,5 @@
//@ run-pass
+//@ ignore-backends: gcc
#![feature(test)]
#![deny(overflowing_literals)]
diff --git a/tests/ui/offset-of/offset-of-tuple-field.rs b/tests/ui/offset-of/offset-of-tuple-field.rs
new file mode 100644
index 0000000..02d41f9
--- /dev/null
+++ b/tests/ui/offset-of/offset-of-tuple-field.rs
@@ -0,0 +1,22 @@
+#![feature(builtin_syntax)]
+
+use std::mem::offset_of;
+
+fn main() {
+ offset_of!((u8, u8), _0); //~ ERROR no field `_0`
+ offset_of!((u8, u8), 01); //~ ERROR no field `01`
+ offset_of!((u8, u8), 1e2); //~ ERROR no field `1e2`
+ offset_of!((u8, u8), 1_u8); //~ ERROR no field `1_`
+ //~| ERROR suffixes on a tuple index
+
+ builtin # offset_of((u8, u8), 1e2); //~ ERROR no field `1e2`
+ builtin # offset_of((u8, u8), _0); //~ ERROR no field `_0`
+ builtin # offset_of((u8, u8), 01); //~ ERROR no field `01`
+ builtin # offset_of((u8, u8), 1_u8); //~ ERROR no field `1_`
+ //~| ERROR suffixes on a tuple index
+
+ offset_of!(((u8, u16), (u32, u16, u8)), 0.2); //~ ERROR no field `2`
+ offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); //~ ERROR no field `1e2`
+ offset_of!(((u8, u16), (u32, u16, u8)), 1.2);
+ offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0); //~ ERROR no field `0`
+}
diff --git a/tests/ui/offset-of/offset-of-tuple-field.stderr b/tests/ui/offset-of/offset-of-tuple-field.stderr
new file mode 100644
index 0000000..4da0d85
--- /dev/null
+++ b/tests/ui/offset-of/offset-of-tuple-field.stderr
@@ -0,0 +1,81 @@
+error: suffixes on a tuple index are invalid
+ --> $DIR/offset-of-tuple-field.rs:15:35
+ |
+LL | builtin # offset_of((u8, u8), 1_u8);
+ | ^^^^ invalid suffix `u8`
+
+error: suffixes on a tuple index are invalid
+ --> $DIR/offset-of-tuple-field.rs:9:26
+ |
+LL | offset_of!((u8, u8), 1_u8);
+ | ^^^^ invalid suffix `u8`
+
+error[E0609]: no field `_0` on type `(u8, u8)`
+ --> $DIR/offset-of-tuple-field.rs:6:26
+ |
+LL | offset_of!((u8, u8), _0);
+ | ^^
+
+error[E0609]: no field `01` on type `(u8, u8)`
+ --> $DIR/offset-of-tuple-field.rs:7:26
+ |
+LL | offset_of!((u8, u8), 01);
+ | ^^
+
+error[E0609]: no field `1e2` on type `(u8, u8)`
+ --> $DIR/offset-of-tuple-field.rs:8:26
+ |
+LL | offset_of!((u8, u8), 1e2);
+ | ^^^
+
+error[E0609]: no field `1_` on type `(u8, u8)`
+ --> $DIR/offset-of-tuple-field.rs:9:26
+ |
+LL | offset_of!((u8, u8), 1_u8);
+ | ^^^^
+
+error[E0609]: no field `1e2` on type `(u8, u8)`
+ --> $DIR/offset-of-tuple-field.rs:12:35
+ |
+LL | builtin # offset_of((u8, u8), 1e2);
+ | ^^^
+
+error[E0609]: no field `_0` on type `(u8, u8)`
+ --> $DIR/offset-of-tuple-field.rs:13:35
+ |
+LL | builtin # offset_of((u8, u8), _0);
+ | ^^
+
+error[E0609]: no field `01` on type `(u8, u8)`
+ --> $DIR/offset-of-tuple-field.rs:14:35
+ |
+LL | builtin # offset_of((u8, u8), 01);
+ | ^^
+
+error[E0609]: no field `1_` on type `(u8, u8)`
+ --> $DIR/offset-of-tuple-field.rs:15:35
+ |
+LL | builtin # offset_of((u8, u8), 1_u8);
+ | ^^^^
+
+error[E0609]: no field `2` on type `(u8, u16)`
+ --> $DIR/offset-of-tuple-field.rs:18:47
+ |
+LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.2);
+ | ^
+
+error[E0609]: no field `1e2` on type `(u8, u16)`
+ --> $DIR/offset-of-tuple-field.rs:19:47
+ |
+LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2);
+ | ^^^
+
+error[E0609]: no field `0` on type `u8`
+ --> $DIR/offset-of-tuple-field.rs:21:49
+ |
+LL | offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0);
+ | ^
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0609`.
diff --git a/tests/ui/offset-of/offset-of-tuple.rs b/tests/ui/offset-of/offset-of-tuple.rs
index e844724..ddbaee9 100644
--- a/tests/ui/offset-of/offset-of-tuple.rs
+++ b/tests/ui/offset-of/offset-of-tuple.rs
@@ -3,20 +3,10 @@
use std::mem::offset_of;
fn main() {
- offset_of!((u8, u8), _0); //~ ERROR no field `_0`
- offset_of!((u8, u8), 01); //~ ERROR no field `01`
- offset_of!((u8, u8), 1e2); //~ ERROR no field `1e2`
- offset_of!((u8, u8), 1_u8); //~ ERROR no field `1_`
- //~| ERROR suffixes on a tuple index
offset_of!((u8, u8), +1); //~ ERROR no rules expected
offset_of!((u8, u8), -1); //~ ERROR offset_of expects dot-separated field and variant names
offset_of!((u8, u8), 1.); //~ ERROR offset_of expects dot-separated field and variant names
offset_of!((u8, u8), 1 .); //~ ERROR unexpected token: `)`
- builtin # offset_of((u8, u8), 1e2); //~ ERROR no field `1e2`
- builtin # offset_of((u8, u8), _0); //~ ERROR no field `_0`
- builtin # offset_of((u8, u8), 01); //~ ERROR no field `01`
- builtin # offset_of((u8, u8), 1_u8); //~ ERROR no field `1_`
- //~| ERROR suffixes on a tuple index
// We need to put these into curly braces, otherwise only one of the
// errors will be emitted and the others suppressed.
{ builtin # offset_of((u8, u8), +1) }; //~ ERROR leading `+` is not supported
@@ -27,11 +17,6 @@ fn main() {
type ComplexTup = (((u8, u8), u8), u8);
fn nested() {
- offset_of!(((u8, u16), (u32, u16, u8)), 0.2); //~ ERROR no field `2`
- offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); //~ ERROR no field `1e2`
- offset_of!(((u8, u16), (u32, u16, u8)), 1.2);
- offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0); //~ ERROR no field `0`
-
// All combinations of spaces (this sends different tokens to the parser)
offset_of!(ComplexTup, 0.0.1.); //~ ERROR unexpected token: `)`
offset_of!(ComplexTup, 0 .0.1.); //~ ERROR unexpected token: `)`
diff --git a/tests/ui/offset-of/offset-of-tuple.stderr b/tests/ui/offset-of/offset-of-tuple.stderr
index 38ce49c..33dea99 100644
--- a/tests/ui/offset-of/offset-of-tuple.stderr
+++ b/tests/ui/offset-of/offset-of-tuple.stderr
@@ -1,11 +1,5 @@
-error: suffixes on a tuple index are invalid
- --> $DIR/offset-of-tuple.rs:18:35
- |
-LL | builtin # offset_of((u8, u8), 1_u8);
- | ^^^^ invalid suffix `u8`
-
error: leading `+` is not supported
- --> $DIR/offset-of-tuple.rs:22:37
+ --> $DIR/offset-of-tuple.rs:12:37
|
LL | { builtin # offset_of((u8, u8), +1) };
| ^ unexpected `+`
@@ -17,67 +11,61 @@
|
error: offset_of expects dot-separated field and variant names
- --> $DIR/offset-of-tuple.rs:23:38
+ --> $DIR/offset-of-tuple.rs:13:38
|
LL | { builtin # offset_of((u8, u8), 1.) };
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:24:40
+ --> $DIR/offset-of-tuple.rs:14:40
|
LL | { builtin # offset_of((u8, u8), 1 .) };
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:47:45
+ --> $DIR/offset-of-tuple.rs:32:45
|
LL | { builtin # offset_of(ComplexTup, 0.0.1.) };
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:48:46
+ --> $DIR/offset-of-tuple.rs:33:46
|
LL | { builtin # offset_of(ComplexTup, 0 .0.1.) };
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:49:47
+ --> $DIR/offset-of-tuple.rs:34:47
|
LL | { builtin # offset_of(ComplexTup, 0 . 0.1.) };
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:50:46
+ --> $DIR/offset-of-tuple.rs:35:46
|
LL | { builtin # offset_of(ComplexTup, 0. 0.1.) };
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:51:46
+ --> $DIR/offset-of-tuple.rs:36:46
|
LL | { builtin # offset_of(ComplexTup, 0.0 .1.) };
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:52:47
+ --> $DIR/offset-of-tuple.rs:37:47
|
LL | { builtin # offset_of(ComplexTup, 0.0 . 1.) };
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:53:46
+ --> $DIR/offset-of-tuple.rs:38:46
|
LL | { builtin # offset_of(ComplexTup, 0.0. 1.) };
| ^
-error: suffixes on a tuple index are invalid
- --> $DIR/offset-of-tuple.rs:9:26
- |
-LL | offset_of!((u8, u8), 1_u8);
- | ^^^^ invalid suffix `u8`
-
error: no rules expected `+`
- --> $DIR/offset-of-tuple.rs:11:26
+ --> $DIR/offset-of-tuple.rs:6:26
|
LL | offset_of!((u8, u8), +1);
| ^ no rules expected this token in macro call
@@ -86,131 +74,64 @@
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
error: offset_of expects dot-separated field and variant names
- --> $DIR/offset-of-tuple.rs:12:26
+ --> $DIR/offset-of-tuple.rs:7:26
|
LL | offset_of!((u8, u8), -1);
| ^^
error: offset_of expects dot-separated field and variant names
- --> $DIR/offset-of-tuple.rs:13:27
+ --> $DIR/offset-of-tuple.rs:8:27
|
LL | offset_of!((u8, u8), 1.);
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:14:29
+ --> $DIR/offset-of-tuple.rs:9:29
|
LL | offset_of!((u8, u8), 1 .);
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:36:34
+ --> $DIR/offset-of-tuple.rs:21:34
|
LL | offset_of!(ComplexTup, 0.0.1.);
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:37:35
+ --> $DIR/offset-of-tuple.rs:22:35
|
LL | offset_of!(ComplexTup, 0 .0.1.);
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:38:36
+ --> $DIR/offset-of-tuple.rs:23:36
|
LL | offset_of!(ComplexTup, 0 . 0.1.);
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:39:35
+ --> $DIR/offset-of-tuple.rs:24:35
|
LL | offset_of!(ComplexTup, 0. 0.1.);
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:40:35
+ --> $DIR/offset-of-tuple.rs:25:35
|
LL | offset_of!(ComplexTup, 0.0 .1.);
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:41:36
+ --> $DIR/offset-of-tuple.rs:26:36
|
LL | offset_of!(ComplexTup, 0.0 . 1.);
| ^
error: unexpected token: `)`
- --> $DIR/offset-of-tuple.rs:42:35
+ --> $DIR/offset-of-tuple.rs:27:35
|
LL | offset_of!(ComplexTup, 0.0. 1.);
| ^
-error[E0609]: no field `_0` on type `(u8, u8)`
- --> $DIR/offset-of-tuple.rs:6:26
- |
-LL | offset_of!((u8, u8), _0);
- | ^^
+error: aborting due to 21 previous errors
-error[E0609]: no field `01` on type `(u8, u8)`
- --> $DIR/offset-of-tuple.rs:7:26
- |
-LL | offset_of!((u8, u8), 01);
- | ^^
-
-error[E0609]: no field `1e2` on type `(u8, u8)`
- --> $DIR/offset-of-tuple.rs:8:26
- |
-LL | offset_of!((u8, u8), 1e2);
- | ^^^
-
-error[E0609]: no field `1_` on type `(u8, u8)`
- --> $DIR/offset-of-tuple.rs:9:26
- |
-LL | offset_of!((u8, u8), 1_u8);
- | ^^^^
-
-error[E0609]: no field `1e2` on type `(u8, u8)`
- --> $DIR/offset-of-tuple.rs:15:35
- |
-LL | builtin # offset_of((u8, u8), 1e2);
- | ^^^
-
-error[E0609]: no field `_0` on type `(u8, u8)`
- --> $DIR/offset-of-tuple.rs:16:35
- |
-LL | builtin # offset_of((u8, u8), _0);
- | ^^
-
-error[E0609]: no field `01` on type `(u8, u8)`
- --> $DIR/offset-of-tuple.rs:17:35
- |
-LL | builtin # offset_of((u8, u8), 01);
- | ^^
-
-error[E0609]: no field `1_` on type `(u8, u8)`
- --> $DIR/offset-of-tuple.rs:18:35
- |
-LL | builtin # offset_of((u8, u8), 1_u8);
- | ^^^^
-
-error[E0609]: no field `2` on type `(u8, u16)`
- --> $DIR/offset-of-tuple.rs:30:47
- |
-LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.2);
- | ^
-
-error[E0609]: no field `1e2` on type `(u8, u16)`
- --> $DIR/offset-of-tuple.rs:31:47
- |
-LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2);
- | ^^^
-
-error[E0609]: no field `0` on type `u8`
- --> $DIR/offset-of-tuple.rs:33:49
- |
-LL | offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0);
- | ^
-
-error: aborting due to 34 previous errors
-
-For more information about this error, try `rustc --explain E0609`.
diff --git a/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs b/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs
index 0566d23..bef2d8b 100644
--- a/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs
+++ b/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs
@@ -3,6 +3,7 @@
//@ aux-build:exit-success-if-unwind.rs
//@ no-prefer-dynamic
//@ needs-subprocess
+//@ ignore-backends: gcc
extern crate exit_success_if_unwind;
diff --git a/tests/ui/panic-runtime/abort.rs b/tests/ui/panic-runtime/abort.rs
index 8cdfd01..2a52228 100644
--- a/tests/ui/panic-runtime/abort.rs
+++ b/tests/ui/panic-runtime/abort.rs
@@ -2,6 +2,7 @@
//@ compile-flags:-C panic=abort
//@ no-prefer-dynamic
//@ needs-subprocess
+//@ ignore-backends: gcc
use std::env;
use std::process::Command;
diff --git a/tests/ui/panic-runtime/link-to-abort.rs b/tests/ui/panic-runtime/link-to-abort.rs
index a4013f2..98718ab 100644
--- a/tests/ui/panic-runtime/link-to-abort.rs
+++ b/tests/ui/panic-runtime/link-to-abort.rs
@@ -2,6 +2,7 @@
//@ compile-flags:-C panic=abort
//@ no-prefer-dynamic
+//@ ignore-backends: gcc
#![feature(panic_abort)]
diff --git a/tests/ui/panic-runtime/lto-abort.rs b/tests/ui/panic-runtime/lto-abort.rs
index cf15ae6..cf36cd8 100644
--- a/tests/ui/panic-runtime/lto-abort.rs
+++ b/tests/ui/panic-runtime/lto-abort.rs
@@ -1,3 +1,4 @@
+//@ ignore-backends: gcc
//@ run-pass
//@ compile-flags:-C lto -C panic=abort
//@ no-prefer-dynamic
diff --git a/tests/ui/issues/issue-10638.rs b/tests/ui/parser/doc-comment-parsing.rs
similarity index 74%
rename from tests/ui/issues/issue-10638.rs
rename to tests/ui/parser/doc-comment-parsing.rs
index c6c6939..00f6b0e 100644
--- a/tests/ui/issues/issue-10638.rs
+++ b/tests/ui/parser/doc-comment-parsing.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10638
+
//@ run-pass
pub fn main() {
diff --git a/tests/ui/parser/recover/recover-pat-ranges.stderr b/tests/ui/parser/recover/recover-pat-ranges.stderr
index 6c17182..246c704 100644
--- a/tests/ui/parser/recover/recover-pat-ranges.stderr
+++ b/tests/ui/parser/recover/recover-pat-ranges.stderr
@@ -191,7 +191,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(ellipsis_inclusive_range_patterns)]` on by default
error: aborting due to 13 previous errors; 1 warning emitted
diff --git a/tests/ui/parser/recover/recover-range-pats.stderr b/tests/ui/parser/recover/recover-range-pats.stderr
index a2f3ba4..1570475 100644
--- a/tests/ui/parser/recover/recover-range-pats.stderr
+++ b/tests/ui/parser/recover/recover-range-pats.stderr
@@ -339,7 +339,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
note: the lint level is defined here
--> $DIR/recover-range-pats.rs:6:9
|
@@ -353,7 +353,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:46:13
@@ -362,7 +362,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:49:13
@@ -371,7 +371,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:52:16
@@ -380,7 +380,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:55:13
@@ -389,7 +389,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:58:14
@@ -398,7 +398,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:62:13
@@ -407,7 +407,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:137:20
@@ -419,7 +419,7 @@
| ----------- in this macro invocation
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0029]: only `char` and numeric types are allowed in range patterns
diff --git a/tests/ui/parser/trait-object-trait-parens.stderr b/tests/ui/parser/trait-object-trait-parens.stderr
index 26d388f..b206754 100644
--- a/tests/ui/parser/trait-object-trait-parens.stderr
+++ b/tests/ui/parser/trait-object-trait-parens.stderr
@@ -23,7 +23,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
@@ -48,7 +48,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | let _: Box<dyn ?Sized + (for<'a> Trait<'a>) + (Obj)>;
@@ -72,7 +72,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | let _: Box<dyn for<'a> Trait<'a> + (Obj) + (?Sized)>;
diff --git a/tests/ui/parser/unclosed-delimiter-in-dep.rs b/tests/ui/parser/unclosed-delimiter-in-dep.rs
index 40f517f..4f0423a 100644
--- a/tests/ui/parser/unclosed-delimiter-in-dep.rs
+++ b/tests/ui/parser/unclosed-delimiter-in-dep.rs
@@ -1,3 +1,5 @@
+//@ ignore-backends: gcc
+
mod unclosed_delim_mod;
fn main() {
diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr
index f19fed0..deb14d1 100644
--- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr
+++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr
@@ -146,6 +146,15 @@
...
LL | drop(&tup0);
| ^^^^^ value borrowed here after move
+ |
+note: if `S` implemented `Clone`, you could clone the value
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5
+ |
+LL | struct S; // Not `Copy`.
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | m!((ref mut borrow, mov) = tup0);
+ | ---- you could clone this value
error[E0382]: borrow of moved value: `tup1`
--> $DIR/move-ref-patterns-closure-captures-inside.rs:76:10
@@ -161,6 +170,15 @@
...
LL | drop(&tup1);
| ^^^^^ value borrowed here after move
+ |
+note: if `S` implemented `Clone`, you could clone the value
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5
+ |
+LL | struct S; // Not `Copy`.
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | m!((mov, _, ref mut borrow) = tup1);
+ | ---- you could clone this value
error[E0382]: borrow of moved value: `tup2`
--> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10
@@ -176,6 +194,15 @@
...
LL | drop(&tup2);
| ^^^^^ value borrowed here after move
+ |
+note: if `S` implemented `Clone`, you could clone the value
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5
+ |
+LL | struct S; // Not `Copy`.
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | m!((ref borrow, mov) = tup2);
+ | ---- you could clone this value
error[E0382]: borrow of moved value: `tup3`
--> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10
@@ -191,6 +218,15 @@
...
LL | drop(&tup3);
| ^^^^^ value borrowed here after move
+ |
+note: if `S` implemented `Clone`, you could clone the value
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5
+ |
+LL | struct S; // Not `Copy`.
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | m!((mov, _, ref borrow) = tup3);
+ | ---- you could clone this value
error[E0382]: borrow of moved value: `tup4`
--> $DIR/move-ref-patterns-closure-captures-inside.rs:79:21
@@ -206,6 +242,15 @@
...
LL | m!((ref x, _) = &tup4);
| ^^^^^ value borrowed here after move
+ |
+note: if `S` implemented `Clone`, you could clone the value
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5
+ |
+LL | struct S; // Not `Copy`.
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | m!((ref borrow, mov) = tup4);
+ | ---- you could clone this value
error[E0382]: borrow of moved value: `arr0`
--> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10
@@ -221,6 +266,15 @@
...
LL | drop(&arr0);
| ^^^^^ value borrowed here after move
+ |
+note: if `S` implemented `Clone`, you could clone the value
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5
+ |
+LL | struct S; // Not `Copy`.
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | m!([mov @ .., ref borrow] = arr0);
+ | ---- you could clone this value
error[E0382]: borrow of moved value: `arr1`
--> $DIR/move-ref-patterns-closure-captures-inside.rs:81:35
@@ -236,6 +290,15 @@
...
LL | m!([_, mov1, mov2, mov3, _] = &arr1);
| ^^^^^ value borrowed here after move
+ |
+note: if `S` implemented `Clone`, you could clone the value
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5
+ |
+LL | struct S; // Not `Copy`.
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | m!([_, ref mut borrow @ .., _, mov] = arr1);
+ | ---- you could clone this value
error[E0382]: borrow of moved value: `arr2`
--> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10
@@ -251,6 +314,15 @@
...
LL | drop(&arr2);
| ^^^^^ value borrowed here after move
+ |
+note: if `S` implemented `Clone`, you could clone the value
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5
+ |
+LL | struct S; // Not `Copy`.
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | m!([mov @ .., ref borrow] = arr2);
+ | ---- you could clone this value
error[E0382]: borrow of moved value: `arr3`
--> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35
@@ -265,6 +337,15 @@
...
LL | m!([_, mov1, mov2, mov3, _] = &arr3);
| ^^^^^ value borrowed here after move
+ |
+note: if `S` implemented `Clone`, you could clone the value
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5
+ |
+LL | struct S; // Not `Copy`.
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | m!([_, ref borrow @ .., _, mov] = arr3);
+ | ---- you could clone this value
error[E0382]: borrow of moved value: `tup0`
--> $DIR/move-ref-patterns-closure-captures-inside.rs:111:10
diff --git a/tests/ui/issues/issue-10683.rs b/tests/ui/pattern/premature-match-scrutinee-temporary-drop-10683.rs
similarity index 67%
rename from tests/ui/issues/issue-10683.rs
rename to tests/ui/pattern/premature-match-scrutinee-temporary-drop-10683.rs
index 5657ec18..a4dfa56 100644
--- a/tests/ui/issues/issue-10683.rs
+++ b/tests/ui/pattern/premature-match-scrutinee-temporary-drop-10683.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10683
+
//@ run-pass
static NAME: &'static str = "hello world";
diff --git a/tests/ui/privacy/associated-item-privacy-trait.stderr b/tests/ui/privacy/associated-item-privacy-trait.stderr
index f79c4cf..4e9dfa4a 100644
--- a/tests/ui/privacy/associated-item-privacy-trait.stderr
+++ b/tests/ui/privacy/associated-item-privacy-trait.stderr
@@ -75,6 +75,17 @@
|
= note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+error: trait `PrivTr` is private
+ --> $DIR/associated-item-privacy-trait.rs:29:14
+ |
+LL | impl PrivTr for u8 {}
+ | ^^^^^^ private trait
+...
+LL | priv_trait::mac!();
+ | ------------------ in this macro invocation
+ |
+ = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+
error: type `priv_signature::Priv` is private
--> $DIR/associated-item-privacy-trait.rs:46:21
|
@@ -317,16 +328,5 @@
|
= note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: trait `PrivTr` is private
- --> $DIR/associated-item-privacy-trait.rs:29:14
- |
-LL | impl PrivTr for u8 {}
- | ^^^^^^ private trait
-...
-LL | priv_trait::mac!();
- | ------------------ in this macro invocation
- |
- = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-
error: aborting due to 30 previous errors
diff --git a/tests/ui/privacy/private-field-access-in-mutex-54062.rs b/tests/ui/privacy/private-field-access-in-mutex-54062.rs
new file mode 100644
index 0000000..c957e0b
--- /dev/null
+++ b/tests/ui/privacy/private-field-access-in-mutex-54062.rs
@@ -0,0 +1,14 @@
+use std::sync::Mutex;
+
+struct Test {
+ comps: Mutex<String>,
+}
+
+fn main() {}
+
+fn testing(test: Test) {
+ let _ = test.comps.inner.try_lock();
+ //~^ ERROR: field `inner` of struct `std::sync::Mutex` is private
+}
+
+// https://github.com/rust-lang/rust/issues/54062
diff --git a/tests/ui/issues/issue-54062.stderr b/tests/ui/privacy/private-field-access-in-mutex-54062.stderr
similarity index 62%
rename from tests/ui/issues/issue-54062.stderr
rename to tests/ui/privacy/private-field-access-in-mutex-54062.stderr
index 75eef54..f7f84640 100644
--- a/tests/ui/issues/issue-54062.stderr
+++ b/tests/ui/privacy/private-field-access-in-mutex-54062.stderr
@@ -1,5 +1,5 @@
-error[E0616]: field `inner` of struct `Mutex` is private
- --> $DIR/issue-54062.rs:10:24
+error[E0616]: field `inner` of struct `std::sync::Mutex` is private
+ --> $DIR/private-field-access-in-mutex-54062.rs:10:24
|
LL | let _ = test.comps.inner.try_lock();
| ^^^^^ private field
diff --git a/tests/ui/privacy/private-in-public-warn.stderr b/tests/ui/privacy/private-in-public-warn.stderr
index c2a57e3..86f6be8 100644
--- a/tests/ui/privacy/private-in-public-warn.stderr
+++ b/tests/ui/privacy/private-in-public-warn.stderr
@@ -84,42 +84,6 @@
LL | struct Priv;
| ^^^^^^^^^^^
-error: type `types::Priv` is more private than the item `types::ES`
- --> $DIR/private-in-public-warn.rs:27:9
- |
-LL | pub static ES: Priv;
- | ^^^^^^^^^^^^^^^^^^^ static `types::ES` is reachable at visibility `pub(crate)`
- |
-note: but type `types::Priv` is only usable at visibility `pub(self)`
- --> $DIR/private-in-public-warn.rs:9:5
- |
-LL | struct Priv;
- | ^^^^^^^^^^^
-
-error: type `types::Priv` is more private than the item `types::ef1`
- --> $DIR/private-in-public-warn.rs:28:9
- |
-LL | pub fn ef1(arg: Priv);
- | ^^^^^^^^^^^^^^^^^^^^^^ function `types::ef1` is reachable at visibility `pub(crate)`
- |
-note: but type `types::Priv` is only usable at visibility `pub(self)`
- --> $DIR/private-in-public-warn.rs:9:5
- |
-LL | struct Priv;
- | ^^^^^^^^^^^
-
-error: type `types::Priv` is more private than the item `types::ef2`
- --> $DIR/private-in-public-warn.rs:29:9
- |
-LL | pub fn ef2() -> Priv;
- | ^^^^^^^^^^^^^^^^^^^^^ function `types::ef2` is reachable at visibility `pub(crate)`
- |
-note: but type `types::Priv` is only usable at visibility `pub(self)`
- --> $DIR/private-in-public-warn.rs:9:5
- |
-LL | struct Priv;
- | ^^^^^^^^^^^
-
error[E0446]: private type `types::Priv` in public interface
--> $DIR/private-in-public-warn.rs:32:9
|
@@ -395,6 +359,42 @@
LL | struct Priv2;
| ^^^^^^^^^^^^
+error: type `types::Priv` is more private than the item `types::ES`
+ --> $DIR/private-in-public-warn.rs:27:9
+ |
+LL | pub static ES: Priv;
+ | ^^^^^^^^^^^^^^^^^^^ static `types::ES` is reachable at visibility `pub(crate)`
+ |
+note: but type `types::Priv` is only usable at visibility `pub(self)`
+ --> $DIR/private-in-public-warn.rs:9:5
+ |
+LL | struct Priv;
+ | ^^^^^^^^^^^
+
+error: type `types::Priv` is more private than the item `types::ef1`
+ --> $DIR/private-in-public-warn.rs:28:9
+ |
+LL | pub fn ef1(arg: Priv);
+ | ^^^^^^^^^^^^^^^^^^^^^^ function `types::ef1` is reachable at visibility `pub(crate)`
+ |
+note: but type `types::Priv` is only usable at visibility `pub(self)`
+ --> $DIR/private-in-public-warn.rs:9:5
+ |
+LL | struct Priv;
+ | ^^^^^^^^^^^
+
+error: type `types::Priv` is more private than the item `types::ef2`
+ --> $DIR/private-in-public-warn.rs:29:9
+ |
+LL | pub fn ef2() -> Priv;
+ | ^^^^^^^^^^^^^^^^^^^^^ function `types::ef2` is reachable at visibility `pub(crate)`
+ |
+note: but type `types::Priv` is only usable at visibility `pub(self)`
+ --> $DIR/private-in-public-warn.rs:9:5
+ |
+LL | struct Priv;
+ | ^^^^^^^^^^^
+
warning: bounds on generic parameters in type aliases are not enforced
--> $DIR/private-in-public-warn.rs:42:23
|
diff --git a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs
index 13f3065..d5065a6 100644
--- a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs
+++ b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs
@@ -1,5 +1,6 @@
-// We should not emit sealed traits note, see issue #143392
+// We should not emit sealed traits note, see issue #143392 and #143121
+/// Reported in #143392
mod inner {
pub trait TraitA {}
@@ -10,4 +11,13 @@ pub trait TraitB: TraitA {}
impl inner::TraitB for Struct {} //~ ERROR the trait bound `Struct: TraitA` is not satisfied [E0277]
+/// Reported in #143121
+mod x {
+ pub trait A {}
+ pub trait B: A {}
+
+ pub struct C;
+ impl B for C {} //~ ERROR the trait bound `C: A` is not satisfied [E0277]
+}
+
fn main(){}
diff --git a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr
index f80d985..df80165 100644
--- a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr
+++ b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr
@@ -1,20 +1,37 @@
error[E0277]: the trait bound `Struct: TraitA` is not satisfied
- --> $DIR/false-sealed-traits-note.rs:11:24
+ --> $DIR/false-sealed-traits-note.rs:12:24
|
LL | impl inner::TraitB for Struct {}
| ^^^^^^ the trait `TraitA` is not implemented for `Struct`
|
help: this trait has no implementations, consider adding one
- --> $DIR/false-sealed-traits-note.rs:4:5
+ --> $DIR/false-sealed-traits-note.rs:5:5
|
LL | pub trait TraitA {}
| ^^^^^^^^^^^^^^^^
note: required by a bound in `TraitB`
- --> $DIR/false-sealed-traits-note.rs:6:23
+ --> $DIR/false-sealed-traits-note.rs:7:23
|
LL | pub trait TraitB: TraitA {}
| ^^^^^^ required by this bound in `TraitB`
-error: aborting due to 1 previous error
+error[E0277]: the trait bound `C: A` is not satisfied
+ --> $DIR/false-sealed-traits-note.rs:20:16
+ |
+LL | impl B for C {}
+ | ^ the trait `A` is not implemented for `C`
+ |
+help: this trait has no implementations, consider adding one
+ --> $DIR/false-sealed-traits-note.rs:16:5
+ |
+LL | pub trait A {}
+ | ^^^^^^^^^^^
+note: required by a bound in `B`
+ --> $DIR/false-sealed-traits-note.rs:17:18
+ |
+LL | pub trait B: A {}
+ | ^ required by this bound in `B`
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/privacy/struct-field-and-impl-expose-10545.rs b/tests/ui/privacy/struct-field-and-impl-expose-10545.rs
new file mode 100644
index 0000000..8a8c824
--- /dev/null
+++ b/tests/ui/privacy/struct-field-and-impl-expose-10545.rs
@@ -0,0 +1,11 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10545
+
+mod a {
+ struct S;
+ impl S { }
+}
+
+fn foo(_: a::S) { //~ ERROR: struct `S` is private
+}
+
+fn main() {}
diff --git a/tests/ui/issues/issue-10545.stderr b/tests/ui/privacy/struct-field-and-impl-expose-10545.stderr
similarity index 72%
rename from tests/ui/issues/issue-10545.stderr
rename to tests/ui/privacy/struct-field-and-impl-expose-10545.stderr
index 9aa0421..ddf87d1 100644
--- a/tests/ui/issues/issue-10545.stderr
+++ b/tests/ui/privacy/struct-field-and-impl-expose-10545.stderr
@@ -1,11 +1,11 @@
error[E0603]: struct `S` is private
- --> $DIR/issue-10545.rs:6:14
+ --> $DIR/struct-field-and-impl-expose-10545.rs:8:14
|
LL | fn foo(_: a::S) {
| ^ private struct
|
note: the struct `S` is defined here
- --> $DIR/issue-10545.rs:2:5
+ --> $DIR/struct-field-and-impl-expose-10545.rs:4:5
|
LL | struct S;
| ^^^^^^^^^
diff --git a/tests/ui/proc-macro/attribute.rs b/tests/ui/proc-macro/attribute.rs
index 30ed8ff..988cdcd 100644
--- a/tests/ui/proc-macro/attribute.rs
+++ b/tests/ui/proc-macro/attribute.rs
@@ -6,68 +6,85 @@
extern crate proc_macro;
use proc_macro::*;
-#[proc_macro_derive] //~ ERROR malformed `proc_macro_derive` attribute
+#[proc_macro_derive]
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected this to be a list
pub fn foo1(input: TokenStream) -> TokenStream { input }
-#[proc_macro_derive = ""] //~ ERROR malformed `proc_macro_derive` attribute
+#[proc_macro_derive = ""]
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected this to be a list
pub fn foo2(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(d3, a, b)]
-//~^ ERROR attribute must have either one or two arguments
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE the only valid argument here is `attributes`
pub fn foo3(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(d4, attributes(a), b)]
-//~^ ERROR attribute must have either one or two arguments
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE didn't expect any arguments here
pub fn foo4(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive("a")]
-//~^ ERROR: not a meta item
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE didn't expect a literal here
pub fn foo5(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(d6 = "")]
-//~^ ERROR: must only be one word
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE didn't expect any arguments here
pub fn foo6(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(m::d7)]
-//~^ ERROR: must only be one word
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected a valid identifier here
pub fn foo7(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(d8(a))]
-//~^ ERROR: must only be one word
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE didn't expect any arguments here
pub fn foo8(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(self)]
-//~^ ERROR: `self` cannot be a name of derive macro
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected a valid identifier here
pub fn foo9(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(PartialEq)] // OK
pub fn foo10(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(d11, a)]
-//~^ ERROR: second argument must be `attributes`
-//~| ERROR: attribute must be of form: `attributes(foo, bar)`
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE the only valid argument here is `attributes`
pub fn foo11(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(d12, attributes)]
-//~^ ERROR: attribute must be of form: `attributes(foo, bar)`
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected this to be a list
pub fn foo12(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(d13, attributes("a"))]
-//~^ ERROR: attribute must be a meta item, not a literal
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected a valid identifier here
pub fn foo13(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(d14, attributes(a = ""))]
-//~^ ERROR: attribute must only be a single word
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE didn't expect any arguments here
pub fn foo14(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(d15, attributes(m::a))]
-//~^ ERROR: attribute must only be a single word
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected a valid identifier here
pub fn foo15(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(d16, attributes(a(b)))]
-//~^ ERROR: attribute must only be a single word
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE didn't expect any arguments here
pub fn foo16(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(d17, attributes(self))]
-//~^ ERROR: `self` cannot be a name of derive helper attribute
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected a valid identifier here
pub fn foo17(input: TokenStream) -> TokenStream { input }
diff --git a/tests/ui/proc-macro/attribute.stderr b/tests/ui/proc-macro/attribute.stderr
index 3269aaf..db59a1f 100644
--- a/tests/ui/proc-macro/attribute.stderr
+++ b/tests/ui/proc-macro/attribute.stderr
@@ -1,104 +1,148 @@
-error: malformed `proc_macro_derive` attribute input
+error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:9:1
|
LL | #[proc_macro_derive]
- | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+ | ^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected this to be a list
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: malformed `proc_macro_derive` attribute input
- --> $DIR/attribute.rs:12:1
+error[E0539]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:14:1
|
LL | #[proc_macro_derive = ""]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected this to be a list
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: attribute must have either one or two arguments
- --> $DIR/attribute.rs:15:1
- |
-LL | #[proc_macro_derive(d3, a, b)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: attribute must have either one or two arguments
+error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:19:1
|
-LL | #[proc_macro_derive(d4, attributes(a), b)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[proc_macro_derive(d3, a, b)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^
+ | | |
+ | | the only valid argument here is `attributes`
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: not a meta item
- --> $DIR/attribute.rs:23:21
+error[E0565]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:24:1
+ |
+LL | #[proc_macro_derive(d4, attributes(a), b)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+
+error[E0565]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:29:1
|
LL | #[proc_macro_derive("a")]
- | ^^^
+ | ^^^^^^^^^^^^^^^^^^^^---^^
+ | | |
+ | | didn't expect a literal here
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: must only be one word
- --> $DIR/attribute.rs:27:21
+error[E0565]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:34:1
|
LL | #[proc_macro_derive(d6 = "")]
- | ^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^----^^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: must only be one word
- --> $DIR/attribute.rs:31:21
+error[E0539]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:39:1
|
LL | #[proc_macro_derive(m::d7)]
- | ^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^-----^^
+ | | |
+ | | expected a valid identifier here
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: must only be one word
- --> $DIR/attribute.rs:35:21
+error[E0565]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:44:1
|
LL | #[proc_macro_derive(d8(a))]
- | ^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^---^^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: `self` cannot be a name of derive macro
- --> $DIR/attribute.rs:39:21
+error[E0539]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:49:1
|
LL | #[proc_macro_derive(self)]
- | ^^^^
+ | ^^^^^^^^^^^^^^^^^^^^----^^
+ | | |
+ | | expected a valid identifier here
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: second argument must be `attributes`
- --> $DIR/attribute.rs:46:26
+error[E0539]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:57:1
|
LL | #[proc_macro_derive(d11, a)]
- | ^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^-^^
+ | | |
+ | | the only valid argument here is `attributes`
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: attribute must be of form: `attributes(foo, bar)`
- --> $DIR/attribute.rs:46:26
- |
-LL | #[proc_macro_derive(d11, a)]
- | ^
-
-error: attribute must be of form: `attributes(foo, bar)`
- --> $DIR/attribute.rs:51:26
+error[E0539]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:62:1
|
LL | #[proc_macro_derive(d12, attributes)]
- | ^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^----------^^
+ | | |
+ | | expected this to be a list
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: attribute must be a meta item, not a literal
- --> $DIR/attribute.rs:55:37
+error[E0539]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:67:1
|
LL | #[proc_macro_derive(d13, attributes("a"))]
- | ^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^
+ | | |
+ | | expected a valid identifier here
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: attribute must only be a single word
- --> $DIR/attribute.rs:59:37
+error[E0565]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:72:1
|
LL | #[proc_macro_derive(d14, attributes(a = ""))]
- | ^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: attribute must only be a single word
- --> $DIR/attribute.rs:63:37
+error[E0539]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:77:1
|
LL | #[proc_macro_derive(d15, attributes(m::a))]
- | ^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^
+ | | |
+ | | expected a valid identifier here
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: attribute must only be a single word
- --> $DIR/attribute.rs:67:37
+error[E0565]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:82:1
|
LL | #[proc_macro_derive(d16, attributes(a(b)))]
- | ^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: `self` cannot be a name of derive helper attribute
- --> $DIR/attribute.rs:71:37
+error[E0539]: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:87:1
|
LL | #[proc_macro_derive(d17, attributes(self))]
- | ^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^
+ | | |
+ | | expected a valid identifier here
+ | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
+Some errors have detailed explanations: E0539, E0565.
+For more information about an error, try `rustc --explain E0539`.
diff --git a/tests/ui/proc-macro/invalid-attributes.rs b/tests/ui/proc-macro/invalid-attributes.rs
index a70c73e..703defa 100644
--- a/tests/ui/proc-macro/invalid-attributes.rs
+++ b/tests/ui/proc-macro/invalid-attributes.rs
@@ -7,20 +7,32 @@
use proc_macro::TokenStream;
-#[proc_macro = "test"] //~ ERROR malformed `proc_macro` attribute
+#[proc_macro = "test"]
+//~^ ERROR malformed `proc_macro` attribute
+//~| NOTE didn't expect any arguments here
pub fn a(a: TokenStream) -> TokenStream { a }
-#[proc_macro()] //~ ERROR malformed `proc_macro` attribute
+#[proc_macro()]
+//~^ ERROR malformed `proc_macro` attribute
+//~| NOTE didn't expect any arguments here
pub fn c(a: TokenStream) -> TokenStream { a }
-#[proc_macro(x)] //~ ERROR malformed `proc_macro` attribute
+#[proc_macro(x)]
+//~^ ERROR malformed `proc_macro` attribute
+//~| NOTE didn't expect any arguments here
pub fn d(a: TokenStream) -> TokenStream { a }
-#[proc_macro_attribute = "test"] //~ ERROR malformed `proc_macro_attribute` attribute
+#[proc_macro_attribute = "test"]
+//~^ ERROR malformed `proc_macro_attribute` attribute
+//~| NOTE didn't expect any arguments here
pub fn e(_: TokenStream, a: TokenStream) -> TokenStream { a }
-#[proc_macro_attribute()] //~ ERROR malformed `proc_macro_attribute` attribute
+#[proc_macro_attribute()]
+//~^ ERROR malformed `proc_macro_attribute` attribute
+//~| NOTE didn't expect any arguments here
pub fn g(_: TokenStream, a: TokenStream) -> TokenStream { a }
-#[proc_macro_attribute(x)] //~ ERROR malformed `proc_macro_attribute` attribute
+#[proc_macro_attribute(x)]
+//~^ ERROR malformed `proc_macro_attribute` attribute
+//~| NOTE didn't expect any arguments here
pub fn h(_: TokenStream, a: TokenStream) -> TokenStream { a }
diff --git a/tests/ui/proc-macro/invalid-attributes.stderr b/tests/ui/proc-macro/invalid-attributes.stderr
index fe411fa..11c182e 100644
--- a/tests/ui/proc-macro/invalid-attributes.stderr
+++ b/tests/ui/proc-macro/invalid-attributes.stderr
@@ -1,38 +1,57 @@
-error: malformed `proc_macro` attribute input
+error[E0565]: malformed `proc_macro` attribute input
--> $DIR/invalid-attributes.rs:10:1
|
LL | #[proc_macro = "test"]
- | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]`
+ | ^^^^^^^^^^^^^--------^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro]`
-error: malformed `proc_macro` attribute input
- --> $DIR/invalid-attributes.rs:13:1
+error[E0565]: malformed `proc_macro` attribute input
+ --> $DIR/invalid-attributes.rs:15:1
|
LL | #[proc_macro()]
- | ^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]`
+ | ^^^^^^^^^^^^--^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro]`
-error: malformed `proc_macro` attribute input
- --> $DIR/invalid-attributes.rs:16:1
+error[E0565]: malformed `proc_macro` attribute input
+ --> $DIR/invalid-attributes.rs:20:1
|
LL | #[proc_macro(x)]
- | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]`
+ | ^^^^^^^^^^^^---^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro]`
-error: malformed `proc_macro_attribute` attribute input
- --> $DIR/invalid-attributes.rs:19:1
- |
-LL | #[proc_macro_attribute = "test"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]`
-
-error: malformed `proc_macro_attribute` attribute input
- --> $DIR/invalid-attributes.rs:22:1
- |
-LL | #[proc_macro_attribute()]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]`
-
-error: malformed `proc_macro_attribute` attribute input
+error[E0565]: malformed `proc_macro_attribute` attribute input
--> $DIR/invalid-attributes.rs:25:1
|
+LL | #[proc_macro_attribute = "test"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^--------^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro_attribute]`
+
+error[E0565]: malformed `proc_macro_attribute` attribute input
+ --> $DIR/invalid-attributes.rs:30:1
+ |
+LL | #[proc_macro_attribute()]
+ | ^^^^^^^^^^^^^^^^^^^^^^--^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro_attribute]`
+
+error[E0565]: malformed `proc_macro_attribute` attribute input
+ --> $DIR/invalid-attributes.rs:35:1
+ |
LL | #[proc_macro_attribute(x)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]`
+ | ^^^^^^^^^^^^^^^^^^^^^^---^
+ | | |
+ | | didn't expect any arguments here
+ | help: must be of the form: `#[proc_macro_attribute]`
error: aborting due to 6 previous errors
+For more information about this error, try `rustc --explain E0565`.
diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout
index 91d16ec..452598c 100644
--- a/tests/ui/proc-macro/meta-macro-hygiene.stdout
+++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout
@@ -16,10 +16,10 @@
// in the stdout
#![no_std /* 0#0 */]
-#[prelude_import /* 0#1 */]
-use core /* 0#1 */::prelude /* 0#1 */::rust_2018 /* 0#1 */::*;
#[macro_use /* 0#1 */]
extern crate core /* 0#1 */;
+#[prelude_import /* 0#1 */]
+use core /* 0#1 */::prelude /* 0#1 */::rust_2018 /* 0#1 */::*;
// Don't load unnecessary hygiene information from std
extern crate std /* 0#0 */;
diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
index 6374132..e10a519 100644
--- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
+++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
@@ -36,10 +36,10 @@
#![feature /* 0#0 */(decl_macro)]
#![no_std /* 0#0 */]
-#[prelude_import /* 0#1 */]
-use ::core /* 0#1 */::prelude /* 0#1 */::rust_2015 /* 0#1 */::*;
#[macro_use /* 0#1 */]
extern crate core /* 0#2 */;
+#[prelude_import /* 0#1 */]
+use ::core /* 0#1 */::prelude /* 0#1 */::rust_2015 /* 0#1 */::*;
// Don't load unnecessary hygiene information from std
extern crate std /* 0#0 */;
diff --git a/tests/ui/proc-macro/quote/debug.stdout b/tests/ui/proc-macro/quote/debug.stdout
index 3acb472..77c52f0 100644
--- a/tests/ui/proc-macro/quote/debug.stdout
+++ b/tests/ui/proc-macro/quote/debug.stdout
@@ -12,10 +12,10 @@
#![feature(proc_macro_quote)]
#![crate_type = "proc-macro"]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
extern crate proc_macro;
diff --git a/tests/ui/process/nofile-limit.rs b/tests/ui/process/nofile-limit.rs
index dafc982..64777b5 100644
--- a/tests/ui/process/nofile-limit.rs
+++ b/tests/ui/process/nofile-limit.rs
@@ -7,6 +7,8 @@
//@ only-linux
//@ no-prefer-dynamic
//@ compile-flags: -Ctarget-feature=+crt-static -Crpath=no -Crelocation-model=static
+//@ ignore-backends: gcc
+
#![feature(exit_status_error)]
#![feature(rustc_private)]
extern crate libc;
diff --git a/tests/ui/process/println-with-broken-pipe.rs b/tests/ui/process/println-with-broken-pipe.rs
index fbac9b6..58b83a2 100644
--- a/tests/ui/process/println-with-broken-pipe.rs
+++ b/tests/ui/process/println-with-broken-pipe.rs
@@ -5,6 +5,7 @@
//@ ignore-fuchsia
//@ ignore-horizon
//@ ignore-android
+//@ ignore-backends: gcc
//@ normalize-stderr: ".rs:\d+:\d+" -> ".rs:LL:CC"
//@ compile-flags: -Zon-broken-pipe=error
diff --git a/tests/ui/range/range-inclusive-pattern-precedence.stderr b/tests/ui/range/range-inclusive-pattern-precedence.stderr
index 9df20fc..15237b0 100644
--- a/tests/ui/range/range-inclusive-pattern-precedence.stderr
+++ b/tests/ui/range/range-inclusive-pattern-precedence.stderr
@@ -16,7 +16,7 @@
| ^^^^^^ help: use `..=` for an inclusive range: `&(0..=9)`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
note: the lint level is defined here
--> $DIR/range-inclusive-pattern-precedence.rs:7:9
|
diff --git a/tests/ui/range/range-inclusive-pattern-precedence2.stderr b/tests/ui/range/range-inclusive-pattern-precedence2.stderr
index fd2fa78..4c5016b 100644
--- a/tests/ui/range/range-inclusive-pattern-precedence2.stderr
+++ b/tests/ui/range/range-inclusive-pattern-precedence2.stderr
@@ -16,7 +16,7 @@
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
note: the lint level is defined here
--> $DIR/range-inclusive-pattern-precedence2.rs:5:9
|
diff --git a/tests/ui/issues/issue-67552.rs b/tests/ui/recursion/recursive-impl-trait-iterator-by-ref-67552.rs
similarity index 89%
rename from tests/ui/issues/issue-67552.rs
rename to tests/ui/recursion/recursive-impl-trait-iterator-by-ref-67552.rs
index 53f0e93..0875d38 100644
--- a/tests/ui/issues/issue-67552.rs
+++ b/tests/ui/recursion/recursive-impl-trait-iterator-by-ref-67552.rs
@@ -29,3 +29,5 @@ fn rec<T>(mut it: T)
//~^ ERROR reached the recursion limit while instantiating
}
}
+
+// https://github.com/rust-lang/rust/issues/67552
diff --git a/tests/ui/issues/issue-67552.stderr b/tests/ui/recursion/recursive-impl-trait-iterator-by-ref-67552.stderr
similarity index 67%
rename from tests/ui/issues/issue-67552.stderr
rename to tests/ui/recursion/recursive-impl-trait-iterator-by-ref-67552.stderr
index def0a29..fe00598 100644
--- a/tests/ui/issues/issue-67552.stderr
+++ b/tests/ui/recursion/recursive-impl-trait-iterator-by-ref-67552.stderr
@@ -1,17 +1,17 @@
error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut ...>`
- --> $DIR/issue-67552.rs:28:9
+ --> $DIR/recursive-impl-trait-iterator-by-ref-67552.rs:28:9
|
LL | rec(identity(&mut it))
| ^^^^^^^^^^^^^^^^^^^^^^
|
note: `rec` defined here
- --> $DIR/issue-67552.rs:21:1
+ --> $DIR/recursive-impl-trait-iterator-by-ref-67552.rs:21:1
|
LL | / fn rec<T>(mut it: T)
LL | | where
LL | | T: Iterator,
| |________________^
- = note: the full type name has been written to '$TEST_BUILD_DIR/issue-67552.long-type.txt'
+ = note: the full type name has been written to '$TEST_BUILD_DIR/recursive-impl-trait-iterator-by-ref-67552.long-type.txt'
error: aborting due to 1 previous error
diff --git a/tests/ui/issues/issue-24353.rs b/tests/ui/return/early-return-with-unreachable-code-24353.rs
similarity index 64%
rename from tests/ui/issues/issue-24353.rs
rename to tests/ui/return/early-return-with-unreachable-code-24353.rs
index 369fc23..13add46 100644
--- a/tests/ui/issues/issue-24353.rs
+++ b/tests/ui/return/early-return-with-unreachable-code-24353.rs
@@ -6,3 +6,5 @@ fn main() {
let x = ();
x
}
+
+// https://github.com/rust-lang/rust/issues/24353
diff --git a/tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs b/tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs
index bd62a64..b1df1b1 100644
--- a/tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs
+++ b/tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs
@@ -1,5 +1,6 @@
//@ run-pass
//@ needs-unwind
+//@ ignore-backends: gcc
//@ revisions: default mir-opt
//@[mir-opt] compile-flags: -Zmir-opt-level=4
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate-macro.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate-macro.rs
new file mode 100644
index 0000000..9d86ebc
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate-macro.rs
@@ -0,0 +1,14 @@
+// gate-test-if_let_guard
+
+fn main() {
+ macro_rules! use_expr {
+ ($e:expr) => {
+ match () {
+ () if $e => {}
+ _ => {}
+ }
+ }
+ }
+ use_expr!(let 0 = 1);
+ //~^ ERROR no rules expected keyword `let`
+}
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate-macro.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate-macro.stderr
new file mode 100644
index 0000000..411fde8
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate-macro.stderr
@@ -0,0 +1,17 @@
+error: no rules expected keyword `let`
+ --> $DIR/feature-gate-macro.rs:12:15
+ |
+LL | macro_rules! use_expr {
+ | --------------------- when calling this macro
+...
+LL | use_expr!(let 0 = 1);
+ | ^^^ no rules expected this token in macro call
+ |
+note: while trying to match meta-variable `$e:expr`
+ --> $DIR/feature-gate-macro.rs:5:10
+ |
+LL | ($e:expr) => {
+ | ^^^^^^^
+
+error: aborting due to 1 previous error
+
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 b1e3058..eb9e5df 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
@@ -64,8 +64,6 @@ macro_rules! use_expr {
//~^ ERROR `if let` guards are experimental
_ => {}
}
- use_expr!(let 0 = 1);
- //~^ ERROR no rules expected keyword `let`
}
fn main() {}
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 19d1f4b0..759f147 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
@@ -149,21 +149,6 @@
= note: only supported directly in conditions of `if` and `while` expressions
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: no rules expected keyword `let`
- --> $DIR/feature-gate.rs:67:15
- |
-LL | macro_rules! use_expr {
- | --------------------- when calling this macro
-...
-LL | use_expr!(let 0 = 1);
- | ^^^ no rules expected this token in macro call
- |
-note: while trying to match meta-variable `$e:expr`
- --> $DIR/feature-gate.rs:48:10
- |
-LL | ($e:expr) => {
- | ^^^^^^^
-
error[E0658]: `if let` guards are experimental
--> $DIR/feature-gate.rs:7:12
|
@@ -230,6 +215,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: aborting due to 20 previous errors
+error: aborting due to 19 previous errors
For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
index ea46260..e16841b 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
@@ -79,7 +79,7 @@
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
note: an unsafe function restricts its caller, but its body is safe by default
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 e2e45ae..66ba726 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
@@ -1,9 +1,9 @@
#![feature(prelude_import)]
#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ check-pass
//@ compile-flags: -Z unpretty=expanded
//@ edition: 2015
diff --git a/tests/ui/runtime/backtrace-debuginfo.rs b/tests/ui/runtime/backtrace-debuginfo.rs
index 37fce27..5fb9943 100644
--- a/tests/ui/runtime/backtrace-debuginfo.rs
+++ b/tests/ui/runtime/backtrace-debuginfo.rs
@@ -43,12 +43,13 @@ macro_rules! dump_and_die {
// rust-lang/rust to test it as well, but sometimes we just gotta keep
// landing PRs.
//
- // aarch64-msvc is broken as its backtraces are truncated.
+ // aarch64-msvc/arm64ec-msvc is broken as its backtraces are truncated.
// See https://github.com/rust-lang/rust/issues/140489
if cfg!(any(target_os = "android",
all(target_os = "linux", target_arch = "arm"),
all(target_env = "msvc", target_arch = "x86"),
all(target_env = "msvc", target_arch = "aarch64"),
+ all(target_env = "msvc", target_arch = "arm64ec"),
target_os = "freebsd",
target_os = "dragonfly",
target_os = "openbsd")) {
diff --git a/tests/ui/runtime/on-broken-pipe/child-processes.rs b/tests/ui/runtime/on-broken-pipe/child-processes.rs
index 0da2347..c0c8ad4 100644
--- a/tests/ui/runtime/on-broken-pipe/child-processes.rs
+++ b/tests/ui/runtime/on-broken-pipe/child-processes.rs
@@ -1,6 +1,7 @@
//@ revisions: default error kill inherit
//@ ignore-cross-compile because aux-bin does not yet support it
//@ only-unix because SIGPIPE is a unix thing
+//@ ignore-backends: gcc
//@ run-pass
//@ aux-bin:assert-sigpipe-disposition.rs
//@ aux-crate:sigpipe_utils=sigpipe-utils.rs
diff --git a/tests/ui/runtime/out-of-stack.rs b/tests/ui/runtime/out-of-stack.rs
index 6be34af..913d363 100644
--- a/tests/ui/runtime/out-of-stack.rs
+++ b/tests/ui/runtime/out-of-stack.rs
@@ -19,7 +19,7 @@
use std::env;
use std::hint::black_box;
use std::process::Command;
-use std::thread;
+use std::thread::Builder;
fn silent_recurse() {
let buf = [0u8; 1000];
@@ -56,9 +56,9 @@ fn main() {
} else if args.len() > 1 && args[1] == "loud" {
loud_recurse();
} else if args.len() > 1 && args[1] == "silent-thread" {
- thread::spawn(silent_recurse).join();
+ Builder::new().name("ferris".to_string()).spawn(silent_recurse).unwrap().join();
} else if args.len() > 1 && args[1] == "loud-thread" {
- thread::spawn(loud_recurse).join();
+ Builder::new().name("ferris".to_string()).spawn(loud_recurse).unwrap().join();
} else {
let mut modes = vec![
"silent-thread",
@@ -82,6 +82,12 @@ fn main() {
let error = String::from_utf8_lossy(&silent.stderr);
assert!(error.contains("has overflowed its stack"),
"missing overflow message: {}", error);
+
+ if mode.contains("thread") {
+ assert!(error.contains("ferris"), "missing thread name: {}", error);
+ } else {
+ assert!(error.contains("main"), "missing thread name: {}", error);
+ }
}
}
}
diff --git a/tests/ui/runtime/rt-explody-panic-payloads.rs b/tests/ui/runtime/rt-explody-panic-payloads.rs
index d564a26..1d5795f 100644
--- a/tests/ui/runtime/rt-explody-panic-payloads.rs
+++ b/tests/ui/runtime/rt-explody-panic-payloads.rs
@@ -1,6 +1,7 @@
//@ run-pass
//@ needs-unwind
//@ needs-subprocess
+//@ ignore-backends: gcc
use std::env;
use std::process::Command;
diff --git a/tests/ui/rust-2021/array-into-iter-ambiguous.stderr b/tests/ui/rust-2021/array-into-iter-ambiguous.stderr
index 2a724bd..6e510df 100644
--- a/tests/ui/rust-2021/array-into-iter-ambiguous.stderr
+++ b/tests/ui/rust-2021/array-into-iter-ambiguous.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `MyIntoIter::into_iter(points)`
|
= warning: this changes meaning in Rust 2021
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
note: the lint level is defined here
--> $DIR/array-into-iter-ambiguous.rs:5:9
|
diff --git a/tests/ui/rust-2021/future-prelude-collision-generic-trait.stderr b/tests/ui/rust-2021/future-prelude-collision-generic-trait.stderr
index f38da13..bbc85d5 100644
--- a/tests/ui/rust-2021/future-prelude-collision-generic-trait.stderr
+++ b/tests/ui/rust-2021/future-prelude-collision-generic-trait.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^ help: disambiguate the associated function: `<U as PyTryFrom<'_, _>>::try_from`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
note: the lint level is defined here
--> $DIR/future-prelude-collision-generic-trait.rs:5:9
|
diff --git a/tests/ui/rust-2021/future-prelude-collision-generic.stderr b/tests/ui/rust-2021/future-prelude-collision-generic.stderr
index 9893b3e..06ee6b4 100644
--- a/tests/ui/rust-2021/future-prelude-collision-generic.stderr
+++ b/tests/ui/rust-2021/future-prelude-collision-generic.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Generic<'_, _> as MyFromIter>::from_iter`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
note: the lint level is defined here
--> $DIR/future-prelude-collision-generic.rs:5:9
|
@@ -19,7 +19,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Generic::<'static, i32> as MyFromIter>::from_iter`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: trait-associated function `from_iter` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision-generic.rs:34:5
@@ -28,7 +28,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Generic::<'_, _> as MyFromIter>::from_iter`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: 3 warnings emitted
diff --git a/tests/ui/rust-2021/future-prelude-collision-imported.stderr b/tests/ui/rust-2021/future-prelude-collision-imported.stderr
index c1d72d0..8f650e9 100644
--- a/tests/ui/rust-2021/future-prelude-collision-imported.stderr
+++ b/tests/ui/rust-2021/future-prelude-collision-imported.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(3u8)`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
note: the lint level is defined here
--> $DIR/future-prelude-collision-imported.rs:4:9
|
@@ -19,7 +19,7 @@
| ^^^^^^^^^^^^^^ help: disambiguate the associated function: `crate::m::TryIntoU32::try_into(3u8)`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: trait method `try_into` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision-imported.rs:53:22
@@ -28,7 +28,7 @@
| ^^^^^^^^^^^^^^ help: disambiguate the associated function: `super::m::TryIntoU32::try_into(3u8)`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: trait method `try_into` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision-imported.rs:64:22
@@ -37,7 +37,7 @@
| ^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(3u8)`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: 4 warnings emitted
diff --git a/tests/ui/rust-2021/future-prelude-collision-macros.stderr b/tests/ui/rust-2021/future-prelude-collision-macros.stderr
index 4d4a076..c2d8c85 100644
--- a/tests/ui/rust-2021/future-prelude-collision-macros.stderr
+++ b/tests/ui/rust-2021/future-prelude-collision-macros.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `MyTry::try_into(foo!(), todo!())`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
note: the lint level is defined here
--> $DIR/future-prelude-collision-macros.rs:4:9
|
@@ -19,7 +19,7 @@
| ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<bar!() as TryFromU8>::try_from`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: 2 warnings emitted
diff --git a/tests/ui/rust-2021/future-prelude-collision-turbofish.stderr b/tests/ui/rust-2021/future-prelude-collision-turbofish.stderr
index c0ef80f..73ed238 100644
--- a/tests/ui/rust-2021/future-prelude-collision-turbofish.stderr
+++ b/tests/ui/rust-2021/future-prelude-collision-turbofish.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `AnnotatableTryInto::try_into::<usize>(x)`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
note: the lint level is defined here
--> $DIR/future-prelude-collision-turbofish.rs:6:9
|
@@ -19,7 +19,7 @@
| ^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `AnnotatableTryInto::try_into::<usize>(x)`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: 2 warnings emitted
diff --git a/tests/ui/rust-2021/future-prelude-collision.stderr b/tests/ui/rust-2021/future-prelude-collision.stderr
index cae113f..0b25145 100644
--- a/tests/ui/rust-2021/future-prelude-collision.stderr
+++ b/tests/ui/rust-2021/future-prelude-collision.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(3u8)`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
note: the lint level is defined here
--> $DIR/future-prelude-collision.rs:4:9
|
@@ -19,7 +19,7 @@
| ^^^^^^^^^^^^^ help: disambiguate the associated function: `<u32 as TryFromU8>::try_from`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: trait-associated function `from_iter` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision.rs:66:13
@@ -28,7 +28,7 @@
| ^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Vec<u8> as FromByteIterator>::from_iter`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: trait-associated function `try_from` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision.rs:74:18
@@ -37,7 +37,7 @@
| ^^^^^^^^^^^^^ help: disambiguate the associated function: `<_ as TryFromU8>::try_from`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: trait method `try_into` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision.rs:79:18
@@ -46,7 +46,7 @@
| ^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(*(&3u8))`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: trait method `try_into` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision.rs:84:18
@@ -55,7 +55,7 @@
| ^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(&3.0)`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: trait method `try_into` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision.rs:90:18
@@ -64,7 +64,7 @@
| ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(mut_ptr as *const _)`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: trait-associated function `try_from` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision.rs:95:13
@@ -73,7 +73,7 @@
| ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<U32Alias as TryFromU8>::try_from`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
warning: 8 warnings emitted
diff --git a/tests/ui/rust-2021/generic-type-collision.stderr b/tests/ui/rust-2021/generic-type-collision.stderr
index 1ec6104..c2d2968 100644
--- a/tests/ui/rust-2021/generic-type-collision.stderr
+++ b/tests/ui/rust-2021/generic-type-collision.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Vec<i32> as MyTrait<_>>::from_iter`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
note: the lint level is defined here
--> $DIR/generic-type-collision.rs:4:9
|
diff --git a/tests/ui/rust-2021/inherent-dyn-collision.stderr b/tests/ui/rust-2021/inherent-dyn-collision.stderr
index d9e720d..d582e4a 100644
--- a/tests/ui/rust-2021/inherent-dyn-collision.stderr
+++ b/tests/ui/rust-2021/inherent-dyn-collision.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^ help: disambiguate the method call: `(&*get_dyn_trait())`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html>
note: the lint level is defined here
--> $DIR/inherent-dyn-collision.rs:8:9
|
diff --git a/tests/ui/rust-2021/reserved-prefixes-migration.stderr b/tests/ui/rust-2021/reserved-prefixes-migration.stderr
index 20914d1..8092c63 100644
--- a/tests/ui/rust-2021/reserved-prefixes-migration.stderr
+++ b/tests/ui/rust-2021/reserved-prefixes-migration.stderr
@@ -5,7 +5,7 @@
| ^ unknown prefix
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/reserving-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/reserving-syntax.html>
note: the lint level is defined here
--> $DIR/reserved-prefixes-migration.rs:5:9
|
@@ -23,7 +23,7 @@
| ^^^^^^ unknown prefix
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/reserving-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/reserving-syntax.html>
help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021
|
LL | m2!(prefix "hey");
@@ -36,7 +36,7 @@
| ^^^ unknown prefix
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/reserving-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/reserving-syntax.html>
help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021
|
LL | m3!(hey #123);
@@ -49,7 +49,7 @@
| ^^^ unknown prefix
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/reserving-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/reserving-syntax.html>
help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021
|
LL | m3!(hey #hey);
@@ -62,7 +62,7 @@
| ^^^^ unknown prefix
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/reserving-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/reserving-syntax.html>
help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021
|
LL | #name = #kind #value
diff --git a/tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr
index 0735be2..6da2cb97 100644
--- a/tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr
+++ b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `MyIntoIter::into_iter(points)`
|
= warning: this changes meaning in Rust 2024
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/intoiterator-box-slice.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/intoiterator-box-slice.html>
note: the lint level is defined here
--> $DIR/box-slice-into-iter-ambiguous.rs:5:9
|
diff --git a/tests/ui/rust-2024/gen-kw.e2015.stderr b/tests/ui/rust-2024/gen-kw.e2015.stderr
index 3fca7b4..ebb80cf 100644
--- a/tests/ui/rust-2024/gen-kw.e2015.stderr
+++ b/tests/ui/rust-2024/gen-kw.e2015.stderr
@@ -5,7 +5,7 @@
| ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
note: the lint level is defined here
--> $DIR/gen-kw.rs:4:9
|
@@ -20,7 +20,7 @@
| ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:19:27
@@ -29,7 +29,7 @@
| ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:25:9
@@ -38,7 +38,7 @@
| ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:25:19
@@ -47,7 +47,7 @@
| ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:33:13
@@ -56,7 +56,7 @@
| ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:33:28
@@ -65,7 +65,7 @@
| ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:33:37
@@ -74,7 +74,7 @@
| ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: aborting due to 8 previous errors
diff --git a/tests/ui/rust-2024/gen-kw.e2018.stderr b/tests/ui/rust-2024/gen-kw.e2018.stderr
index b7f2c88..e491454 100644
--- a/tests/ui/rust-2024/gen-kw.e2018.stderr
+++ b/tests/ui/rust-2024/gen-kw.e2018.stderr
@@ -5,7 +5,7 @@
| ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
note: the lint level is defined here
--> $DIR/gen-kw.rs:4:9
|
@@ -20,7 +20,7 @@
| ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:19:27
@@ -29,7 +29,7 @@
| ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:25:9
@@ -38,7 +38,7 @@
| ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:25:19
@@ -47,7 +47,7 @@
| ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:33:13
@@ -56,7 +56,7 @@
| ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:33:28
@@ -65,7 +65,7 @@
| ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:33:37
@@ -74,7 +74,7 @@
| ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
error: aborting due to 8 previous errors
diff --git a/tests/ui/rust-2024/prelude-migration/future-poll-async-block.e2021.stderr b/tests/ui/rust-2024/prelude-migration/future-poll-async-block.e2021.stderr
index 15a3fa1..8e5c3f4 100644
--- a/tests/ui/rust-2024/prelude-migration/future-poll-async-block.e2021.stderr
+++ b/tests/ui/rust-2024/prelude-migration/future-poll-async-block.e2021.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `Meow::poll(&core::pin::pin!(async {}), &mut context())`
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/prelude.html>
note: the lint level is defined here
--> $DIR/future-poll-async-block.rs:7:9
|
diff --git a/tests/ui/rust-2024/prelude-migration/future-poll-not-future-pinned.e2021.stderr b/tests/ui/rust-2024/prelude-migration/future-poll-not-future-pinned.e2021.stderr
index 633731c..7076952 100644
--- a/tests/ui/rust-2024/prelude-migration/future-poll-not-future-pinned.e2021.stderr
+++ b/tests/ui/rust-2024/prelude-migration/future-poll-not-future-pinned.e2021.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `Meow::poll(&core::pin::pin!(()))`
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/prelude.html>
note: the lint level is defined here
--> $DIR/future-poll-not-future-pinned.rs:7:9
|
diff --git a/tests/ui/rust-2024/prelude-migration/in_2024_compatibility.stderr b/tests/ui/rust-2024/prelude-migration/in_2024_compatibility.stderr
index 5865029..2e88751 100644
--- a/tests/ui/rust-2024/prelude-migration/in_2024_compatibility.stderr
+++ b/tests/ui/rust-2024/prelude-migration/in_2024_compatibility.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `Meow::poll(&core::pin::pin!(async {}), &mut context())`
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/prelude.html>
note: the lint level is defined here
--> $DIR/in_2024_compatibility.rs:3:9
|
diff --git a/tests/ui/rust-2024/prelude-migration/into-future-adt.e2021.stderr b/tests/ui/rust-2024/prelude-migration/into-future-adt.e2021.stderr
index e67f07b..690c58f 100644
--- a/tests/ui/rust-2024/prelude-migration/into-future-adt.e2021.stderr
+++ b/tests/ui/rust-2024/prelude-migration/into-future-adt.e2021.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `Meow::into_future(&Cat)`
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/prelude.html>
note: the lint level is defined here
--> $DIR/into-future-adt.rs:7:9
|
diff --git a/tests/ui/rust-2024/prelude-migration/into-future-not-into-future.e2021.stderr b/tests/ui/rust-2024/prelude-migration/into-future-not-into-future.e2021.stderr
index 0588f5b..4423e12 100644
--- a/tests/ui/rust-2024/prelude-migration/into-future-not-into-future.e2021.stderr
+++ b/tests/ui/rust-2024/prelude-migration/into-future-not-into-future.e2021.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `Meow::into_future(&Cat)`
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/prelude.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/prelude.html>
note: the lint level is defined here
--> $DIR/into-future-not-into-future.rs:7:9
|
diff --git a/tests/ui/rust-2024/reserved-guarded-strings-lexing.stderr b/tests/ui/rust-2024/reserved-guarded-strings-lexing.stderr
index bf74f6e..488f66b 100644
--- a/tests/ui/rust-2024/reserved-guarded-strings-lexing.stderr
+++ b/tests/ui/rust-2024/reserved-guarded-strings-lexing.stderr
@@ -35,7 +35,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
note: the lint level is defined here
--> $DIR/reserved-guarded-strings-lexing.rs:4:9
|
@@ -53,7 +53,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo4!(# ## "foo");
@@ -66,7 +66,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo4!(## # "foo");
@@ -79,7 +79,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo4!(# # "foo"#);
@@ -92,7 +92,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo7!(# ## "foo"###);
@@ -105,7 +105,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo7!(## # "foo"###);
@@ -118,7 +118,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo7!(### "foo"# ##);
@@ -131,7 +131,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo7!(### "foo"## #);
@@ -144,7 +144,7 @@
| ^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo5!(# ##"foo"#);
@@ -157,7 +157,7 @@
| ^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo5!(## #"foo"#);
@@ -170,7 +170,7 @@
| ^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo5!(### "foo"#);
@@ -183,7 +183,7 @@
| ^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo5!(# "foo"###);
@@ -196,7 +196,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo5!(#"foo"# ##);
@@ -209,7 +209,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo5!(#"foo"## #);
@@ -222,7 +222,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo4!("foo"# ##);
@@ -235,7 +235,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo4!("foo"## #);
@@ -248,7 +248,7 @@
| ^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo4!(Ñ# ""#);
@@ -261,7 +261,7 @@
| ^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo3!(🙃# "");
diff --git a/tests/ui/rust-2024/reserved-guarded-strings-migration.stderr b/tests/ui/rust-2024/reserved-guarded-strings-migration.stderr
index 59f920c..9e6c455 100644
--- a/tests/ui/rust-2024/reserved-guarded-strings-migration.stderr
+++ b/tests/ui/rust-2024/reserved-guarded-strings-migration.stderr
@@ -5,7 +5,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
note: the lint level is defined here
--> $DIR/reserved-guarded-strings-migration.rs:5:9
|
@@ -23,7 +23,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo4!(# ## "foo");
@@ -36,7 +36,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo4!(## # "foo");
@@ -49,7 +49,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo4!(# # "foo"#);
@@ -62,7 +62,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo6!(# ## "foo"##);
@@ -75,7 +75,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo6!(## # "foo"##);
@@ -88,7 +88,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo6!(### "foo"# #);
@@ -101,7 +101,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo4!("foo"# ##);
@@ -114,7 +114,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo4!("foo"## #);
@@ -127,7 +127,7 @@
| ^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo2!(# "");
@@ -140,7 +140,7 @@
| ^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo3!(# ""#);
@@ -153,7 +153,7 @@
| ^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo3!(# #"");
@@ -166,7 +166,7 @@
| ^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo3!(## "");
@@ -179,7 +179,7 @@
| ^^^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo2!(# "foo");
@@ -192,7 +192,7 @@
| ^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo3!(# #"foo");
@@ -205,7 +205,7 @@
| ^^^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo3!(## "foo");
@@ -218,7 +218,7 @@
| ^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo3!(# "foo"#);
@@ -231,7 +231,7 @@
| ^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo4!(# #"foo"#);
@@ -244,7 +244,7 @@
| ^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo4!(## "foo"#);
@@ -257,7 +257,7 @@
| ^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo5!(# #"foo"##);
@@ -270,7 +270,7 @@
| ^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
|
LL | demo5!(## "foo"##);
@@ -283,7 +283,7 @@
| ^^
|
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/reserved-syntax.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/reserved-syntax.html>
help: insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024
|
LL | demo5!(##"foo"# #);
diff --git a/tests/ui/rust-2024/unsafe-attributes/in_2024_compatibility.stderr b/tests/ui/rust-2024/unsafe-attributes/in_2024_compatibility.stderr
index f0a49f5..2b77f6e 100644
--- a/tests/ui/rust-2024/unsafe-attributes/in_2024_compatibility.stderr
+++ b/tests/ui/rust-2024/unsafe-attributes/in_2024_compatibility.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^ usage of unsafe attribute
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-attributes.html>
note: the lint level is defined here
--> $DIR/in_2024_compatibility.rs:1:9
|
diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr
index 15a48fb..b97176f 100644
--- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr
+++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^ usage of unsafe attribute
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-attributes.html>
note: the lint level is defined here
--> $DIR/unsafe-attributes-fix.rs:2:9
|
@@ -26,7 +26,7 @@
| ----------------- in this macro invocation
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-attributes.html>
= note: this error originates in the macro `ident` (in Nightly builds, run with -Z macro-backtrace for more info)
help: wrap the attribute in `unsafe(...)`
|
@@ -40,7 +40,7 @@
| ^^^^^^^^^ usage of unsafe attribute
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-attributes.html>
help: wrap the attribute in `unsafe(...)`
|
LL | meta!(unsafe(no_mangle));
@@ -53,7 +53,7 @@
| ^^^^^^^^^^^ usage of unsafe attribute
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-attributes.html>
help: wrap the attribute in `unsafe(...)`
|
LL | meta2!(unsafe(export_name = "baw"));
@@ -69,7 +69,7 @@
| ---------------------------- in this macro invocation
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-attributes.html>
= note: this error originates in the macro `ident2` (in Nightly builds, run with -Z macro-backtrace for more info)
help: wrap the attribute in `unsafe(...)`
|
@@ -86,7 +86,7 @@
| ---------------- in this macro invocation
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-attributes.html>
= note: this error originates in the macro `with_cfg_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
help: wrap the attribute in `unsafe(...)`
|
@@ -100,7 +100,7 @@
| ^^^^^^^^^ usage of unsafe attribute
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-attributes.html>
help: wrap the attribute in `unsafe(...)`
|
LL | #[unsafe(no_mangle)]
diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.stderr b/tests/ui/rust-2024/unsafe-env-suggestion.stderr
index 6c95d50..3c5ceaa 100644
--- a/tests/ui/rust-2024/unsafe-env-suggestion.stderr
+++ b/tests/ui/rust-2024/unsafe-env-suggestion.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/newly-unsafe-functions.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/newly-unsafe-functions.html>
note: the lint level is defined here
--> $DIR/unsafe-env-suggestion.rs:3:9
|
@@ -24,7 +24,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/newly-unsafe-functions.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/newly-unsafe-functions.html>
help: you can wrap the call in an `unsafe` block if you can guarantee that the environment access only happens in single-threaded code
|
LL + // TODO: Audit that the environment access only happens in single-threaded code.
diff --git a/tests/ui/rust-2024/unsafe-env.e2021.stderr b/tests/ui/rust-2024/unsafe-env.e2021.stderr
index 4a441cf..a73db9f 100644
--- a/tests/ui/rust-2024/unsafe-env.e2021.stderr
+++ b/tests/ui/rust-2024/unsafe-env.e2021.stderr
@@ -4,7 +4,7 @@
LL | unsafe_fn();
| ^^^^^^^^^^^ call to unsafe function
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: consult the function's documentation for information on how to avoid undefined behavior
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/unsafe-env.rs:8:1
diff --git a/tests/ui/rust-2024/unsafe-env.e2024.stderr b/tests/ui/rust-2024/unsafe-env.e2024.stderr
index 0ee7e04..cb48ae2 100644
--- a/tests/ui/rust-2024/unsafe-env.e2024.stderr
+++ b/tests/ui/rust-2024/unsafe-env.e2024.stderr
@@ -4,7 +4,7 @@
LL | env::set_var("FOO", "BAR");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: consult the function's documentation for information on how to avoid undefined behavior
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/unsafe-env.rs:8:1
@@ -23,7 +23,7 @@
LL | env::remove_var("FOO");
| ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe block
@@ -32,7 +32,7 @@
LL | unsafe_fn();
| ^^^^^^^^^^^ call to unsafe function
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: call to unsafe function `set_var` is unsafe and requires unsafe block
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr
index ab12da0..9a535fb 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr
@@ -14,7 +14,7 @@
| |_^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-extern.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-extern.html>
note: the lint level is defined here
--> $DIR/unsafe-extern-suggestion.rs:3:9
|
diff --git a/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs b/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs
index f4f383e..fad5719 100644
--- a/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs
+++ b/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs
@@ -6,6 +6,7 @@
//@ edition: 2021
//@ no-prefer-dynamic
//@ only-x86_64-unknown-linux-gnu
+//@ ignore-backends: gcc
//@ build-pass
trait Iterable {
diff --git a/tests/ui/sanitizer/cfi/async-closures.rs b/tests/ui/sanitizer/cfi/async-closures.rs
index 351853a..9b09926 100644
--- a/tests/ui/sanitizer/cfi/async-closures.rs
+++ b/tests/ui/sanitizer/cfi/async-closures.rs
@@ -4,6 +4,7 @@
//@ revisions: cfi kcfi
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
//@ only-linux
+//@ ignore-backends: gcc
//@ [cfi] needs-sanitizer-cfi
//@ [kcfi] needs-sanitizer-kcfi
//@ compile-flags: -C target-feature=-crt-static
diff --git a/tests/ui/sanitizer/cfi/can-reveal-opaques.rs b/tests/ui/sanitizer/cfi/can-reveal-opaques.rs
index 99c12d7..a881c6b 100644
--- a/tests/ui/sanitizer/cfi/can-reveal-opaques.rs
+++ b/tests/ui/sanitizer/cfi/can-reveal-opaques.rs
@@ -2,6 +2,7 @@
//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
//@ no-prefer-dynamic
//@ only-x86_64-unknown-linux-gnu
+//@ ignore-backends: gcc
//@ build-pass
// See comment below for why this test exists.
diff --git a/tests/ui/sanitizer/cfi/closures.rs b/tests/ui/sanitizer/cfi/closures.rs
index 424e705..fc9718f 100644
--- a/tests/ui/sanitizer/cfi/closures.rs
+++ b/tests/ui/sanitizer/cfi/closures.rs
@@ -3,6 +3,7 @@
//@ revisions: cfi kcfi
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
//@ only-linux
+//@ ignore-backends: gcc
//@ [cfi] needs-sanitizer-cfi
//@ [kcfi] needs-sanitizer-kcfi
//@ compile-flags: -C target-feature=-crt-static
diff --git a/tests/ui/sanitizer/cfi/complex-receiver.rs b/tests/ui/sanitizer/cfi/complex-receiver.rs
index c7b45a7..aac44c3 100644
--- a/tests/ui/sanitizer/cfi/complex-receiver.rs
+++ b/tests/ui/sanitizer/cfi/complex-receiver.rs
@@ -5,6 +5,7 @@
//@ revisions: cfi kcfi
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
//@ only-linux
+//@ ignore-backends: gcc
//@ [cfi] needs-sanitizer-cfi
//@ [kcfi] needs-sanitizer-kcfi
//@ compile-flags: -C target-feature=-crt-static
diff --git a/tests/ui/sanitizer/cfi/coroutine.rs b/tests/ui/sanitizer/cfi/coroutine.rs
index 39a754f..084a521 100644
--- a/tests/ui/sanitizer/cfi/coroutine.rs
+++ b/tests/ui/sanitizer/cfi/coroutine.rs
@@ -3,6 +3,7 @@
//@ revisions: cfi kcfi
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
//@ only-linux
+//@ ignore-backends: gcc
//@ edition: 2024
//@ [cfi] needs-sanitizer-cfi
//@ [kcfi] needs-sanitizer-kcfi
diff --git a/tests/ui/sanitizer/cfi/drop-in-place.rs b/tests/ui/sanitizer/cfi/drop-in-place.rs
index 8ce2c43..160338a 100644
--- a/tests/ui/sanitizer/cfi/drop-in-place.rs
+++ b/tests/ui/sanitizer/cfi/drop-in-place.rs
@@ -2,6 +2,7 @@
//
// FIXME(#122848): Remove only-linux when fixed.
//@ only-linux
+//@ ignore-backends: gcc
//@ needs-sanitizer-cfi
//@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi
//@ run-pass
diff --git a/tests/ui/sanitizer/cfi/drop-no-principal.rs b/tests/ui/sanitizer/cfi/drop-no-principal.rs
index c1c88c8..e3a46fe 100644
--- a/tests/ui/sanitizer/cfi/drop-no-principal.rs
+++ b/tests/ui/sanitizer/cfi/drop-no-principal.rs
@@ -3,6 +3,7 @@
//@ needs-sanitizer-cfi
// FIXME(#122848) Remove only-linux once OSX CFI binaries works
//@ only-linux
+//@ ignore-backends: gcc
//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi
//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0
// FIXME(#118761) Should be run-pass once the labels on drop are compatible.
diff --git a/tests/ui/sanitizer/cfi/fn-ptr.rs b/tests/ui/sanitizer/cfi/fn-ptr.rs
index 505b4b8..d3209c6 100644
--- a/tests/ui/sanitizer/cfi/fn-ptr.rs
+++ b/tests/ui/sanitizer/cfi/fn-ptr.rs
@@ -3,6 +3,7 @@
//@ revisions: cfi kcfi
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
//@ only-linux
+//@ ignore-backends: gcc
//@ [cfi] needs-sanitizer-cfi
//@ [kcfi] needs-sanitizer-kcfi
//@ compile-flags: -C target-feature=-crt-static
diff --git a/tests/ui/sanitizer/cfi/self-ref.rs b/tests/ui/sanitizer/cfi/self-ref.rs
index 3b524ac..b93d492 100644
--- a/tests/ui/sanitizer/cfi/self-ref.rs
+++ b/tests/ui/sanitizer/cfi/self-ref.rs
@@ -3,6 +3,7 @@
//@ revisions: cfi kcfi
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
//@ only-linux
+//@ ignore-backends: gcc
//@ [cfi] needs-sanitizer-cfi
//@ [kcfi] needs-sanitizer-kcfi
//@ compile-flags: -C target-feature=-crt-static
diff --git a/tests/ui/sanitizer/cfi/sized-associated-ty.rs b/tests/ui/sanitizer/cfi/sized-associated-ty.rs
index f5b4e22..eefc3e2 100644
--- a/tests/ui/sanitizer/cfi/sized-associated-ty.rs
+++ b/tests/ui/sanitizer/cfi/sized-associated-ty.rs
@@ -4,6 +4,7 @@
//@ revisions: cfi kcfi
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
//@ only-linux
+//@ ignore-backends: gcc
//@ [cfi] needs-sanitizer-cfi
//@ [kcfi] needs-sanitizer-kcfi
//@ compile-flags: -C target-feature=-crt-static
diff --git a/tests/ui/sanitizer/cfi/supertraits.rs b/tests/ui/sanitizer/cfi/supertraits.rs
index f80b316..f5a984b 100644
--- a/tests/ui/sanitizer/cfi/supertraits.rs
+++ b/tests/ui/sanitizer/cfi/supertraits.rs
@@ -3,6 +3,7 @@
//@ revisions: cfi kcfi
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
//@ only-linux
+//@ ignore-backends: gcc
//@ [cfi] needs-sanitizer-cfi
//@ [kcfi] needs-sanitizer-kcfi
//@ compile-flags: -C target-feature=-crt-static
diff --git a/tests/ui/sanitizer/cfi/virtual-auto.rs b/tests/ui/sanitizer/cfi/virtual-auto.rs
index 6971d51..e6f2ebd 100644
--- a/tests/ui/sanitizer/cfi/virtual-auto.rs
+++ b/tests/ui/sanitizer/cfi/virtual-auto.rs
@@ -3,6 +3,7 @@
//@ revisions: cfi kcfi
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
//@ only-linux
+//@ ignore-backends: gcc
//@ [cfi] needs-sanitizer-cfi
//@ [kcfi] needs-sanitizer-kcfi
//@ compile-flags: -C target-feature=-crt-static
diff --git a/tests/ui/sanitizer/kcfi-mangling.rs b/tests/ui/sanitizer/kcfi-mangling.rs
index fde7b54..ba36dc1 100644
--- a/tests/ui/sanitizer/kcfi-mangling.rs
+++ b/tests/ui/sanitizer/kcfi-mangling.rs
@@ -4,6 +4,7 @@
//@ no-prefer-dynamic
//@ compile-flags: -C panic=abort -Zsanitizer=kcfi -C symbol-mangling-version=v0
//@ build-pass
+//@ ignore-backends: gcc
trait Foo {
fn foo(&self);
diff --git a/tests/ui/self-profile/pretty_print_no_ice.rs b/tests/ui/self-profile/pretty_print_no_ice.rs
new file mode 100644
index 0000000..71b15e8
--- /dev/null
+++ b/tests/ui/self-profile/pretty_print_no_ice.rs
@@ -0,0 +1,14 @@
+// Checks that when we use `-Zself-profile-events=args`, it is possible to pretty print paths
+// using `trimmed_def_paths` even without producing diagnostics.
+//
+// Issue: <https://github.com/rust-lang/rust/issues/144457>.
+
+//@ compile-flags: -Zself-profile={{build-base}} -Zself-profile-events=args
+//@ build-pass
+
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering::Relaxed;
+
+fn main() {
+ AtomicUsize::new(0).load(Relaxed);
+}
diff --git a/tests/ui/self/self_type_keyword.rs b/tests/ui/self/self_type_keyword.rs
index 96d2471..bd05127 100644
--- a/tests/ui/self/self_type_keyword.rs
+++ b/tests/ui/self/self_type_keyword.rs
@@ -18,8 +18,6 @@ pub fn main() {
//~| ERROR cannot find unit struct, unit variant or constant `Self`
ref mut Self => (),
//~^ ERROR expected identifier, found keyword `Self`
- Self!() => (),
- //~^ ERROR cannot find macro `Self` in this scope
Foo { Self } => (),
//~^ ERROR expected identifier, found keyword `Self`
//~| ERROR mismatched types
diff --git a/tests/ui/self/self_type_keyword.stderr b/tests/ui/self/self_type_keyword.stderr
index f9cde81..f22d04b 100644
--- a/tests/ui/self/self_type_keyword.stderr
+++ b/tests/ui/self/self_type_keyword.stderr
@@ -36,35 +36,29 @@
| ^^^^ expected identifier, found keyword
error: expected identifier, found keyword `Self`
- --> $DIR/self_type_keyword.rs:23:15
+ --> $DIR/self_type_keyword.rs:21:15
|
LL | Foo { Self } => (),
| ^^^^ expected identifier, found keyword
error: expected identifier, found keyword `Self`
- --> $DIR/self_type_keyword.rs:31:26
+ --> $DIR/self_type_keyword.rs:29:26
|
LL | extern crate core as Self;
| ^^^^ expected identifier, found keyword
error: expected identifier, found keyword `Self`
- --> $DIR/self_type_keyword.rs:36:32
+ --> $DIR/self_type_keyword.rs:34:32
|
LL | use std::option::Option as Self;
| ^^^^ expected identifier, found keyword
error: expected identifier, found keyword `Self`
- --> $DIR/self_type_keyword.rs:41:11
+ --> $DIR/self_type_keyword.rs:39:11
|
LL | trait Self {}
| ^^^^ expected identifier, found keyword
-error: cannot find macro `Self` in this scope
- --> $DIR/self_type_keyword.rs:21:9
- |
-LL | Self!() => (),
- | ^^^^
-
error[E0531]: cannot find unit struct, unit variant or constant `Self` in this scope
--> $DIR/self_type_keyword.rs:16:13
|
@@ -86,7 +80,7 @@
= help: consider removing `'Self`, referring to it in a field, or using a marker such as `PhantomData`
error[E0308]: mismatched types
- --> $DIR/self_type_keyword.rs:23:9
+ --> $DIR/self_type_keyword.rs:21:9
|
LL | match 15 {
| -- this expression has type `{integer}`
@@ -95,12 +89,12 @@
| ^^^^^^^^^^^^ expected integer, found `Foo`
error[E0026]: struct `Foo` does not have a field named `Self`
- --> $DIR/self_type_keyword.rs:23:15
+ --> $DIR/self_type_keyword.rs:21:15
|
LL | Foo { Self } => (),
| ^^^^ struct `Foo` does not have this field
-error: aborting due to 14 previous errors
+error: aborting due to 13 previous errors
Some errors have detailed explanations: E0026, E0308, E0392, E0531.
For more information about an error, try `rustc --explain E0026`.
diff --git a/tests/ui/self/self_type_macro_name.rs b/tests/ui/self/self_type_macro_name.rs
new file mode 100644
index 0000000..b92b23b
--- /dev/null
+++ b/tests/ui/self/self_type_macro_name.rs
@@ -0,0 +1,6 @@
+pub fn main() {
+ match 15 {
+ Self!() => (),
+ //~^ ERROR cannot find macro `Self` in this scope
+ }
+}
diff --git a/tests/ui/self/self_type_macro_name.stderr b/tests/ui/self/self_type_macro_name.stderr
new file mode 100644
index 0000000..25f766b
--- /dev/null
+++ b/tests/ui/self/self_type_macro_name.stderr
@@ -0,0 +1,8 @@
+error: cannot find macro `Self` in this scope
+ --> $DIR/self_type_macro_name.rs:3:9
+ |
+LL | Self!() => (),
+ | ^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
index bf38a8b..09f5d41 100644
--- a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
+++ b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
@@ -1,4 +1,6 @@
//@ run-pass
+//@ ignore-backends: gcc
+
#![allow(non_camel_case_types)]
#![feature(repr_simd, core_intrinsics)]
diff --git a/tests/ui/simd/intrinsic/generic-as.rs b/tests/ui/simd/intrinsic/generic-as.rs
index f9ed416..bba712e 100644
--- a/tests/ui/simd/intrinsic/generic-as.rs
+++ b/tests/ui/simd/intrinsic/generic-as.rs
@@ -1,4 +1,5 @@
//@ run-pass
+//@ ignore-backends: gcc
#![feature(repr_simd, core_intrinsics)]
diff --git a/tests/ui/simd/issue-17170.rs b/tests/ui/simd/issue-17170.rs
index 2d13962..508f480 100644
--- a/tests/ui/simd/issue-17170.rs
+++ b/tests/ui/simd/issue-17170.rs
@@ -1,4 +1,6 @@
//@ run-pass
+//@ ignore-backends: gcc
+
#![feature(repr_simd)]
#[repr(simd)]
diff --git a/tests/ui/simd/issue-39720.rs b/tests/ui/simd/issue-39720.rs
index 09d6142..41617c7 100644
--- a/tests/ui/simd/issue-39720.rs
+++ b/tests/ui/simd/issue-39720.rs
@@ -1,4 +1,5 @@
//@ run-pass
+//@ ignore-backends: gcc
#![feature(repr_simd, core_intrinsics)]
diff --git a/tests/ui/simd/masked-load-store.rs b/tests/ui/simd/masked-load-store.rs
index da32ba6..bc4307f 100644
--- a/tests/ui/simd/masked-load-store.rs
+++ b/tests/ui/simd/masked-load-store.rs
@@ -1,3 +1,4 @@
+//@ ignore-backends: gcc
//@ run-pass
#![feature(repr_simd, core_intrinsics)]
diff --git a/tests/ui/simd/repr-simd-on-enum.rs b/tests/ui/simd/repr-simd-on-enum.rs
new file mode 100644
index 0000000..49cf9e9
--- /dev/null
+++ b/tests/ui/simd/repr-simd-on-enum.rs
@@ -0,0 +1,15 @@
+// Used to ICE; see <https://github.com/rust-lang/rust/issues/121097>
+
+#![feature(repr_simd)]
+
+#[repr(simd)] //~ ERROR attribute should be applied to a struct
+enum Aligned {
+ Zero = 0,
+ One = 1,
+}
+
+fn tou8(al: Aligned) -> u8 {
+ al as u8
+}
+
+fn main() {}
diff --git a/tests/ui/simd/repr-simd-on-enum.stderr b/tests/ui/simd/repr-simd-on-enum.stderr
new file mode 100644
index 0000000..6a19a16
--- /dev/null
+++ b/tests/ui/simd/repr-simd-on-enum.stderr
@@ -0,0 +1,14 @@
+error[E0517]: attribute should be applied to a struct
+ --> $DIR/repr-simd-on-enum.rs:5:8
+ |
+LL | #[repr(simd)]
+ | ^^^^
+LL | / enum Aligned {
+LL | | Zero = 0,
+LL | | One = 1,
+LL | | }
+ | |_- not a struct
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0517`.
diff --git a/tests/ui/simd/repr_packed.rs b/tests/ui/simd/repr_packed.rs
index f0c6de7..9cf679d 100644
--- a/tests/ui/simd/repr_packed.rs
+++ b/tests/ui/simd/repr_packed.rs
@@ -1,3 +1,4 @@
+//@ ignore-backends: gcc
//@ run-pass
#![feature(repr_simd, core_intrinsics)]
diff --git a/tests/ui/simd/simd-bitmask-notpow2.rs b/tests/ui/simd/simd-bitmask-notpow2.rs
index b9af591..991fe0d 100644
--- a/tests/ui/simd/simd-bitmask-notpow2.rs
+++ b/tests/ui/simd/simd-bitmask-notpow2.rs
@@ -2,6 +2,8 @@
// FIXME: broken codegen on big-endian (https://github.com/rust-lang/rust/issues/127205)
// This should be merged into `simd-bitmask` once that's fixed.
//@ ignore-endian-big
+//@ ignore-backends: gcc
+
#![feature(repr_simd, core_intrinsics)]
#[path = "../../auxiliary/minisimd.rs"]
diff --git a/tests/ui/issues/issue-37534.rs b/tests/ui/sized/relaxing-default-bound-error-37534.rs
similarity index 74%
rename from tests/ui/issues/issue-37534.rs
rename to tests/ui/sized/relaxing-default-bound-error-37534.rs
index 63f6479..d30e9f9 100644
--- a/tests/ui/issues/issue-37534.rs
+++ b/tests/ui/sized/relaxing-default-bound-error-37534.rs
@@ -3,3 +3,5 @@
//~| ERROR bound modifier `?` can only be applied to `Sized`
fn main() {}
+
+// https://github.com/rust-lang/rust/issues/37534
diff --git a/tests/ui/issues/issue-37534.stderr b/tests/ui/sized/relaxing-default-bound-error-37534.stderr
similarity index 79%
rename from tests/ui/issues/issue-37534.stderr
rename to tests/ui/sized/relaxing-default-bound-error-37534.stderr
index 0860735..8b9597f 100644
--- a/tests/ui/issues/issue-37534.stderr
+++ b/tests/ui/sized/relaxing-default-bound-error-37534.stderr
@@ -1,5 +1,5 @@
error[E0404]: expected trait, found derive macro `Hash`
- --> $DIR/issue-37534.rs:1:16
+ --> $DIR/relaxing-default-bound-error-37534.rs:1:16
|
LL | struct Foo<T: ?Hash> {}
| ^^^^ not a trait
@@ -10,7 +10,7 @@
|
error: bound modifier `?` can only be applied to `Sized`
- --> $DIR/issue-37534.rs:1:15
+ --> $DIR/relaxing-default-bound-error-37534.rs:1:15
|
LL | struct Foo<T: ?Hash> {}
| ^^^^^
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-4.stderr b/tests/ui/stability-attribute/stability-attribute-sanity-4.stderr
index 8ead943..f656aea 100644
--- a/tests/ui/stability-attribute/stability-attribute-sanity-4.stderr
+++ b/tests/ui/stability-attribute/stability-attribute-sanity-4.stderr
@@ -1,26 +1,38 @@
-error: malformed `unstable` attribute input
+error[E0539]: malformed `unstable` attribute input
--> $DIR/stability-attribute-sanity-4.rs:8:5
|
LL | #[unstable]
- | ^^^^^^^^^^^ help: must be of the form: `#[unstable(feature = "name", reason = "...", issue = "N")]`
+ | ^^^^^^^^^^^
+ | |
+ | expected this to be a list
+ | help: must be of the form: `#[unstable(feature = "name", reason = "...", issue = "N")]`
-error: malformed `unstable` attribute input
+error[E0539]: malformed `unstable` attribute input
--> $DIR/stability-attribute-sanity-4.rs:11:5
|
LL | #[unstable = "b"]
- | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[unstable(feature = "name", reason = "...", issue = "N")]`
+ | ^^^^^^^^^^^^^^^^^
+ | |
+ | expected this to be a list
+ | help: must be of the form: `#[unstable(feature = "name", reason = "...", issue = "N")]`
-error: malformed `stable` attribute input
+error[E0539]: malformed `stable` attribute input
--> $DIR/stability-attribute-sanity-4.rs:14:5
|
LL | #[stable]
- | ^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]`
+ | ^^^^^^^^^
+ | |
+ | expected this to be a list
+ | help: must be of the form: `#[stable(feature = "name", since = "version")]`
-error: malformed `stable` attribute input
+error[E0539]: malformed `stable` attribute input
--> $DIR/stability-attribute-sanity-4.rs:17:5
|
LL | #[stable = "a"]
- | ^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]`
+ | ^^^^^^^^^^^^^^^
+ | |
+ | expected this to be a list
+ | help: must be of the form: `#[stable(feature = "name", since = "version")]`
error[E0542]: missing 'since'
--> $DIR/stability-attribute-sanity-4.rs:21:5
@@ -42,5 +54,5 @@
error: aborting due to 7 previous errors
-Some errors have detailed explanations: E0542, E0543.
-For more information about an error, try `rustc --explain E0542`.
+Some errors have detailed explanations: E0539, E0542, E0543.
+For more information about an error, try `rustc --explain E0539`.
diff --git a/tests/ui/static/issue-24446.rs b/tests/ui/static/issue-24446.rs
index 830e373..ffd6dfa 100644
--- a/tests/ui/static/issue-24446.rs
+++ b/tests/ui/static/issue-24446.rs
@@ -1,8 +1,6 @@
fn main() {
static foo: dyn Fn() -> u32 = || -> u32 {
//~^ ERROR the size for values of type
- //~| ERROR cannot be shared between threads safely
- //~| ERROR mismatched types
0
};
}
diff --git a/tests/ui/static/issue-24446.stderr b/tests/ui/static/issue-24446.stderr
index ed19563..497ce8c 100644
--- a/tests/ui/static/issue-24446.stderr
+++ b/tests/ui/static/issue-24446.stderr
@@ -1,12 +1,3 @@
-error[E0277]: `(dyn Fn() -> u32 + 'static)` cannot be shared between threads safely
- --> $DIR/issue-24446.rs:2:17
- |
-LL | static foo: dyn Fn() -> u32 = || -> u32 {
- | ^^^^^^^^^^^^^^^ `(dyn Fn() -> u32 + 'static)` cannot be shared between threads safely
- |
- = help: the trait `Sync` is not implemented for `(dyn Fn() -> u32 + 'static)`
- = note: shared static variables must have a type that implements `Sync`
-
error[E0277]: the size for values of type `(dyn Fn() -> u32 + 'static)` cannot be known at compilation time
--> $DIR/issue-24446.rs:2:5
|
@@ -16,19 +7,6 @@
= help: the trait `Sized` is not implemented for `(dyn Fn() -> u32 + 'static)`
= note: statics and constants must have a statically known size
-error[E0308]: mismatched types
- --> $DIR/issue-24446.rs:2:35
- |
-LL | static foo: dyn Fn() -> u32 = || -> u32 {
- | ___________________________________^
-... |
-LL | | };
- | |_____^ expected `dyn Fn`, found closure
- |
- = note: expected trait object `(dyn Fn() -> u32 + 'static)`
- found closure `{closure@$DIR/issue-24446.rs:2:35: 2:44}`
+error: aborting due to 1 previous error
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/static/static-items-cant-move.stderr b/tests/ui/static/static-items-cant-move.stderr
index 1361e70..7c80661 100644
--- a/tests/ui/static/static-items-cant-move.stderr
+++ b/tests/ui/static/static-items-cant-move.stderr
@@ -3,6 +3,15 @@
|
LL | test(BAR);
| ^^^ move occurs because `BAR` has type `Foo`, which does not implement the `Copy` trait
+ |
+note: if `Foo` implemented `Clone`, you could clone the value
+ --> $DIR/static-items-cant-move.rs:5:1
+ |
+LL | struct Foo {
+ | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | test(BAR);
+ | --- you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/statics/const_generics.rs b/tests/ui/statics/const_generics.rs
index 6cc0a65..1921b2c 100644
--- a/tests/ui/statics/const_generics.rs
+++ b/tests/ui/statics/const_generics.rs
@@ -3,6 +3,7 @@
//! This is not an intentional guarantee, it just describes the status quo.
//@ run-pass
+//@ ignore-backends: gcc
// With optimizations, LLVM will deduplicate the constant `X` whose
// value is `&42` to just be a reference to the static. This is correct,
// but obscures the issue we're trying to show.
diff --git a/tests/ui/statics/issue-15261.stderr b/tests/ui/statics/issue-15261.stderr
index d2dd762..60c5fb9 100644
--- a/tests/ui/statics/issue-15261.stderr
+++ b/tests/ui/statics/issue-15261.stderr
@@ -4,7 +4,7 @@
LL | static n: &'static usize = unsafe { &n_mut };
| ^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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: `#[warn(static_mut_refs)]` on by default
help: use `&raw const` instead to create a raw pointer
diff --git a/tests/ui/statics/static-mut-shared-parens.stderr b/tests/ui/statics/static-mut-shared-parens.stderr
index 3825e8e..16daee0 100644
--- a/tests/ui/statics/static-mut-shared-parens.stderr
+++ b/tests/ui/statics/static-mut-shared-parens.stderr
@@ -4,7 +4,7 @@
LL | let _ = unsafe { (&TEST) as *const usize };
| ^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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: `#[warn(static_mut_refs)]` on by default
help: use `&raw const` instead to create a raw pointer
@@ -18,7 +18,7 @@
LL | let _ = unsafe { (&mut TEST) as *const usize };
| ^^^^^^^^^^^ mutable reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
= note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
help: use `&raw mut` instead to create a raw pointer
|
diff --git a/tests/ui/statics/static-mut-xc.stderr b/tests/ui/statics/static-mut-xc.stderr
index 2d7a055..2e5aa1b 100644
--- a/tests/ui/statics/static-mut-xc.stderr
+++ b/tests/ui/statics/static-mut-xc.stderr
@@ -4,7 +4,7 @@
LL | assert_eq!(static_mut_xc::a, 3);
| ^^^^^^^^^^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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: `#[warn(static_mut_refs)]` on by default
@@ -14,7 +14,7 @@
LL | assert_eq!(static_mut_xc::a, 4);
| ^^^^^^^^^^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
warning: creating a shared reference to mutable static
@@ -23,7 +23,7 @@
LL | assert_eq!(static_mut_xc::a, 5);
| ^^^^^^^^^^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
warning: creating a shared reference to mutable static
@@ -32,7 +32,7 @@
LL | assert_eq!(static_mut_xc::a, 15);
| ^^^^^^^^^^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
warning: creating a shared reference to mutable static
@@ -41,7 +41,7 @@
LL | assert_eq!(static_mut_xc::a, -3);
| ^^^^^^^^^^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
warning: creating a shared reference to mutable static
@@ -50,7 +50,7 @@
LL | static_bound(&static_mut_xc::a);
| ^^^^^^^^^^^^^^^^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
help: use `&raw const` instead to create a raw pointer
|
@@ -63,7 +63,7 @@
LL | static_bound_set(&mut static_mut_xc::a);
| ^^^^^^^^^^^^^^^^^^^^^ mutable reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
= note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
help: use `&raw mut` instead to create a raw pointer
|
diff --git a/tests/ui/statics/static-recursive.stderr b/tests/ui/statics/static-recursive.stderr
index 252807e..0c3f961 100644
--- a/tests/ui/statics/static-recursive.stderr
+++ b/tests/ui/statics/static-recursive.stderr
@@ -4,7 +4,7 @@
LL | static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
| ^^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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: `#[warn(static_mut_refs)]` on by default
help: use `&raw const` instead to create a raw pointer
@@ -18,7 +18,7 @@
LL | assert_eq!(S, *(S as *const *const u8));
| ^ shared reference to mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
+ = note: for more information, see <https://doc.rust-lang.org/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
warning: 2 warnings emitted
diff --git a/tests/ui/issues/issue-11267.rs b/tests/ui/structs/mutable-unit-struct-borrow-11267.rs
similarity index 82%
rename from tests/ui/issues/issue-11267.rs
rename to tests/ui/structs/mutable-unit-struct-borrow-11267.rs
index 036ad1d..d96c4a4 100644
--- a/tests/ui/issues/issue-11267.rs
+++ b/tests/ui/structs/mutable-unit-struct-borrow-11267.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/11267
+
//@ run-pass
// Tests that unary structs can be mutably borrowed.
diff --git a/tests/ui/issues/issue-3389.rs b/tests/ui/structs/trie-node-structure-usage-3389.rs
similarity index 91%
rename from tests/ui/issues/issue-3389.rs
rename to tests/ui/structs/trie-node-structure-usage-3389.rs
index 4e73a2cf..1518e10 100644
--- a/tests/ui/issues/issue-3389.rs
+++ b/tests/ui/structs/trie-node-structure-usage-3389.rs
@@ -24,3 +24,5 @@ pub fn main() {
print_str_vector(node.content.clone());
}
+
+// https://github.com/rust-lang/rust/issues/3389
diff --git a/tests/ui/suggestions/enum-method-probe.fixed b/tests/ui/suggestions/enum-method-probe.fixed
index e097fa8..b7fd6f1 100644
--- a/tests/ui/suggestions/enum-method-probe.fixed
+++ b/tests/ui/suggestions/enum-method-probe.fixed
@@ -56,4 +56,11 @@
//~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None`
}
+fn test_option_private_method() {
+ let res: Option<_> = Some(vec![1, 2, 3]);
+ res.expect("REASON").len();
+ //~^ ERROR method `len` is private
+ //~| HELP consider using `Option::expect` to unwrap the `Vec<{integer}>` value, panicking if the value is an `Option::None`
+}
+
fn main() {}
diff --git a/tests/ui/suggestions/enum-method-probe.rs b/tests/ui/suggestions/enum-method-probe.rs
index 665ee7d..cbb819b 100644
--- a/tests/ui/suggestions/enum-method-probe.rs
+++ b/tests/ui/suggestions/enum-method-probe.rs
@@ -56,4 +56,11 @@ fn test_option_in_unit_return() {
//~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None`
}
+fn test_option_private_method() {
+ let res: Option<_> = Some(vec![1, 2, 3]);
+ res.len();
+ //~^ ERROR method `len` is private
+ //~| HELP consider using `Option::expect` to unwrap the `Vec<{integer}>` value, panicking if the value is an `Option::None`
+}
+
fn main() {}
diff --git a/tests/ui/suggestions/enum-method-probe.stderr b/tests/ui/suggestions/enum-method-probe.stderr
index 6ed1498..e66973d 100644
--- a/tests/ui/suggestions/enum-method-probe.stderr
+++ b/tests/ui/suggestions/enum-method-probe.stderr
@@ -94,6 +94,23 @@
LL | res.expect("REASON").get();
| +++++++++++++++++
-error: aborting due to 6 previous errors
+error[E0624]: method `len` is private
+ --> $DIR/enum-method-probe.rs:61:9
+ |
+LL | res.len();
+ | ^^^ private method
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ |
+ = note: private method defined here
+ |
+note: the method `len` exists on the type `Vec<{integer}>`
+ --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+help: consider using `Option::expect` to unwrap the `Vec<{integer}>` value, panicking if the value is an `Option::None`
+ |
+LL | res.expect("REASON").len();
+ | +++++++++++++++++
-For more information about this error, try `rustc --explain E0599`.
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0599, E0624.
+For more information about an error, try `rustc --explain E0599`.
diff --git a/tests/ui/suggestions/inner_type.fixed b/tests/ui/suggestions/inner_type.fixed
index 3dc939d..175a2a02 100644
--- a/tests/ui/suggestions/inner_type.fixed
+++ b/tests/ui/suggestions/inner_type.fixed
@@ -25,7 +25,7 @@
let another_item = std::sync::Mutex::new(Struct { p: 42_u32 });
another_item.lock().unwrap().method();
- //~^ ERROR no method named `method` found for struct `Mutex` in the current scope [E0599]
+ //~^ ERROR no method named `method` found for struct `std::sync::Mutex` in the current scope [E0599]
//~| HELP use `.lock().unwrap()` to borrow the `Struct<u32>`, blocking the current thread until it can be acquired
let another_item = std::sync::RwLock::new(Struct { p: 42_u32 });
diff --git a/tests/ui/suggestions/inner_type.rs b/tests/ui/suggestions/inner_type.rs
index 81a05c2..ab02141 100644
--- a/tests/ui/suggestions/inner_type.rs
+++ b/tests/ui/suggestions/inner_type.rs
@@ -25,7 +25,7 @@ fn main() {
let another_item = std::sync::Mutex::new(Struct { p: 42_u32 });
another_item.method();
- //~^ ERROR no method named `method` found for struct `Mutex` in the current scope [E0599]
+ //~^ ERROR no method named `method` found for struct `std::sync::Mutex` in the current scope [E0599]
//~| HELP use `.lock().unwrap()` to borrow the `Struct<u32>`, blocking the current thread until it can be acquired
let another_item = std::sync::RwLock::new(Struct { p: 42_u32 });
diff --git a/tests/ui/suggestions/inner_type.stderr b/tests/ui/suggestions/inner_type.stderr
index 5ac3d04..67ebb57 100644
--- a/tests/ui/suggestions/inner_type.stderr
+++ b/tests/ui/suggestions/inner_type.stderr
@@ -30,11 +30,11 @@
LL | other_item.borrow_mut().some_mutable_method();
| +++++++++++++
-error[E0599]: no method named `method` found for struct `Mutex` in the current scope
+error[E0599]: no method named `method` found for struct `std::sync::Mutex` in the current scope
--> $DIR/inner_type.rs:27:18
|
LL | another_item.method();
- | ^^^^^^ method not found in `Mutex<Struct<u32>>`
+ | ^^^^^^ method not found in `std::sync::Mutex<Struct<u32>>`
|
note: the method `method` exists on the type `Struct<u32>`
--> $DIR/inner_type.rs:9:5
diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr
index cad5812..e7173d9 100644
--- a/tests/ui/suggestions/issue-116434-2015.stderr
+++ b/tests/ui/suggestions/issue-116434-2015.stderr
@@ -5,7 +5,7 @@
| ^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
@@ -19,7 +19,7 @@
| ^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: if this is a dyn-compatible trait, use `dyn`
|
@@ -52,7 +52,7 @@
| ^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | fn handle() -> dyn DbHandle;
@@ -65,7 +65,7 @@
| ^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/suggestions/issue-61963.stderr b/tests/ui/suggestions/issue-61963.stderr
index ef11efe..ffdeef1 100644
--- a/tests/ui/suggestions/issue-61963.stderr
+++ b/tests/ui/suggestions/issue-61963.stderr
@@ -5,7 +5,7 @@
| ^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
note: the lint level is defined here
--> $DIR/issue-61963.rs:4:9
|
@@ -23,7 +23,7 @@
| ^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | dyn pub struct Foo {
diff --git a/tests/ui/suggestions/option-content-move2.stderr b/tests/ui/suggestions/option-content-move2.stderr
index be97cba..c73e874 100644
--- a/tests/ui/suggestions/option-content-move2.stderr
+++ b/tests/ui/suggestions/option-content-move2.stderr
@@ -2,7 +2,9 @@
--> $DIR/option-content-move2.rs:11:9
|
LL | let mut var = None;
- | ------- captured outer variable
+ | ------- ---- move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait
+ | |
+ | captured outer variable
LL | func(|| {
| -- captured by this `FnMut` closure
LL | // Shouldn't suggest `move ||.as_ref()` here
@@ -10,16 +12,24 @@
| ^^^^^^^ `var` is moved here
LL |
LL | var = Some(NotCopyable);
- | ---
- | |
- | variable moved due to use in closure
- | move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait
+ | --- variable moved due to use in closure
+ |
+note: if `NotCopyable` implemented `Clone`, you could clone the value
+ --> $DIR/option-content-move2.rs:1:1
+ |
+LL | struct NotCopyable;
+ | ^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | var = Some(NotCopyable);
+ | --- you could clone this value
error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
--> $DIR/option-content-move2.rs:21:9
|
LL | let mut var = None;
- | ------- captured outer variable
+ | ------- ---- move occurs because `var` has type `Option<NotCopyableButCloneable>`, which does not implement the `Copy` trait
+ | |
+ | captured outer variable
LL | func(|| {
| -- captured by this `FnMut` closure
LL | // Shouldn't suggest `move ||.as_ref()` nor to `clone()` here
@@ -27,10 +37,7 @@
| ^^^^^^^ `var` is moved here
LL |
LL | var = Some(NotCopyableButCloneable);
- | ---
- | |
- | variable moved due to use in closure
- | move occurs because `var` has type `Option<NotCopyableButCloneable>`, which does not implement the `Copy` trait
+ | --- variable moved due to use in closure
error: aborting due to 2 previous errors
diff --git a/tests/ui/suggestions/option-content-move3.stderr b/tests/ui/suggestions/option-content-move3.stderr
index faaf8a9..68c5235 100644
--- a/tests/ui/suggestions/option-content-move3.stderr
+++ b/tests/ui/suggestions/option-content-move3.stderr
@@ -26,17 +26,16 @@
--> $DIR/option-content-move3.rs:12:9
|
LL | let var = NotCopyable;
- | --- captured outer variable
+ | --- ----------- move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait
+ | |
+ | captured outer variable
LL | func(|| {
| -- captured by this `FnMut` closure
LL | // Shouldn't suggest `move ||.as_ref()` here
LL | move || {
| ^^^^^^^ `var` is moved here
LL | let x = var;
- | ---
- | |
- | variable moved due to use in closure
- | move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait
+ | --- variable moved due to use in closure
|
note: if `NotCopyable` implemented `Clone`, you could clone the value
--> $DIR/option-content-move3.rs:2:1
@@ -67,17 +66,16 @@
--> $DIR/option-content-move3.rs:23:9
|
LL | let var = NotCopyableButCloneable;
- | --- captured outer variable
+ | --- ----------------------- move occurs because `var` has type `NotCopyableButCloneable`, which does not implement the `Copy` trait
+ | |
+ | captured outer variable
LL | func(|| {
| -- captured by this `FnMut` closure
LL | // Shouldn't suggest `move ||.as_ref()` here
LL | move || {
| ^^^^^^^ `var` is moved here
LL | let x = var;
- | ---
- | |
- | variable moved due to use in closure
- | move occurs because `var` has type `NotCopyableButCloneable`, which does not implement the `Copy` trait
+ | --- variable moved due to use in closure
|
help: consider cloning the value before moving it into the closure
|
diff --git a/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr b/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr
index 929f893..d90dd20 100644
--- a/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr
+++ b/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr
@@ -68,7 +68,7 @@
| ^^^^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
@@ -82,7 +82,7 @@
| ^^^^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | impl<'a, T> Enum<T> for dyn Trait<'a, T> {}
@@ -95,7 +95,7 @@
| ^^^^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | impl<'a, T> Union<T> for dyn Trait<'a, T> {}
diff --git a/tests/ui/sync/mutexguard-sync.stderr b/tests/ui/sync/mutexguard-sync.stderr
index 1501a79..ab9983c 100644
--- a/tests/ui/sync/mutexguard-sync.stderr
+++ b/tests/ui/sync/mutexguard-sync.stderr
@@ -8,7 +8,7 @@
|
= help: the trait `Sync` is not implemented for `Cell<i32>`
= note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead
- = note: required for `MutexGuard<'_, Cell<i32>>` to implement `Sync`
+ = note: required for `std::sync::MutexGuard<'_, Cell<i32>>` to implement `Sync`
note: required by a bound in `test_sync`
--> $DIR/mutexguard-sync.rs:5:17
|
diff --git a/tests/ui/target_modifiers/defaults_check.rs b/tests/ui/target_modifiers/defaults_check.rs
index de72acd..ce1d534 100644
--- a/tests/ui/target_modifiers/defaults_check.rs
+++ b/tests/ui/target_modifiers/defaults_check.rs
@@ -6,7 +6,7 @@
//@ needs-llvm-components: x86
//@ revisions: ok ok_explicit error
-//@[ok] compile-flags:
+// [ok] no extra compile-flags
//@[ok_explicit] compile-flags: -Zreg-struct-return=false
//@[error] compile-flags: -Zreg-struct-return=true
//@[ok] check-pass
diff --git a/tests/ui/target_modifiers/incompatible_fixedx18.rs b/tests/ui/target_modifiers/incompatible_fixedx18.rs
index 6c13984..5ba6764 100644
--- a/tests/ui/target_modifiers/incompatible_fixedx18.rs
+++ b/tests/ui/target_modifiers/incompatible_fixedx18.rs
@@ -5,7 +5,7 @@
//@ revisions:allow_match allow_mismatch error_generated
//@[allow_match] compile-flags: -Zfixed-x18
//@[allow_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch=fixed-x18
-//@[error_generated] compile-flags:
+// [error_generated] no extra compile-flags
//@[allow_mismatch] check-pass
//@[allow_match] check-pass
diff --git a/tests/ui/target_modifiers/incompatible_regparm.rs b/tests/ui/target_modifiers/incompatible_regparm.rs
index 395c26f..e76bfc9 100644
--- a/tests/ui/target_modifiers/incompatible_regparm.rs
+++ b/tests/ui/target_modifiers/incompatible_regparm.rs
@@ -5,7 +5,7 @@
//@ revisions:allow_regparm_mismatch allow_no_value error_generated
//@[allow_regparm_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch=regparm
//@[allow_no_value] compile-flags: -Cunsafe-allow-abi-mismatch
-//@[error_generated] compile-flags:
+// [error_generated] no extra compile-flags
//@[allow_regparm_mismatch] check-pass
#![feature(no_core)]
diff --git a/tests/ui/target_modifiers/no_value_bool.rs b/tests/ui/target_modifiers/no_value_bool.rs
index ceba40a..72130f8 100644
--- a/tests/ui/target_modifiers/no_value_bool.rs
+++ b/tests/ui/target_modifiers/no_value_bool.rs
@@ -8,7 +8,7 @@
//@ revisions: ok ok_explicit error error_explicit
//@[ok] compile-flags: -Zreg-struct-return
//@[ok_explicit] compile-flags: -Zreg-struct-return=true
-//@[error] compile-flags:
+// [error] no extra compile-flags
//@[error_explicit] compile-flags: -Zreg-struct-return=false
//@[ok] check-pass
//@[ok_explicit] check-pass
diff --git a/tests/ui/issues/issue-39089.rs b/tests/ui/trait-bounds/for-binder-placement-error-39089.rs
similarity index 69%
rename from tests/ui/issues/issue-39089.rs
rename to tests/ui/trait-bounds/for-binder-placement-error-39089.rs
index 822c475..47976bd 100644
--- a/tests/ui/issues/issue-39089.rs
+++ b/tests/ui/trait-bounds/for-binder-placement-error-39089.rs
@@ -2,3 +2,5 @@
//~^ ERROR `for<...>` binder should be placed before trait bound modifiers
fn main() {}
+
+// https://github.com/rust-lang/rust/issues/39089
diff --git a/tests/ui/issues/issue-39089.stderr b/tests/ui/trait-bounds/for-binder-placement-error-39089.stderr
similarity index 82%
rename from tests/ui/issues/issue-39089.stderr
rename to tests/ui/trait-bounds/for-binder-placement-error-39089.stderr
index a81010a..12fcbc57 100644
--- a/tests/ui/issues/issue-39089.stderr
+++ b/tests/ui/trait-bounds/for-binder-placement-error-39089.stderr
@@ -1,5 +1,5 @@
error: `for<...>` binder should be placed before trait bound modifiers
- --> $DIR/issue-39089.rs:1:13
+ --> $DIR/for-binder-placement-error-39089.rs:1:13
|
LL | fn f<T: ?for<'a> Sized>() {}
| - ^^^^
diff --git a/tests/ui/issues/issue-10456.rs b/tests/ui/traits/blanket-impl-trait-object-10456.rs
similarity index 80%
rename from tests/ui/issues/issue-10456.rs
rename to tests/ui/traits/blanket-impl-trait-object-10456.rs
index 51c740f..f842143 100644
--- a/tests/ui/issues/issue-10456.rs
+++ b/tests/ui/traits/blanket-impl-trait-object-10456.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10456
+
//@ check-pass
pub struct Foo;
diff --git a/tests/ui/traits/bound/not-on-bare-trait.stderr b/tests/ui/traits/bound/not-on-bare-trait.stderr
index 9028e66..69413ca 100644
--- a/tests/ui/traits/bound/not-on-bare-trait.stderr
+++ b/tests/ui/traits/bound/not-on-bare-trait.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/traits/bound/on-structs-and-enums-static.rs b/tests/ui/traits/bound/on-structs-and-enums-static.rs
index d734893..61e8e2a 100644
--- a/tests/ui/traits/bound/on-structs-and-enums-static.rs
+++ b/tests/ui/traits/bound/on-structs-and-enums-static.rs
@@ -6,9 +6,7 @@ struct Foo<T:Trait> {
x: T,
}
-static X: Foo<usize> = Foo {
-//~^ ERROR E0277
-//~| ERROR E0277
+static X: Foo<usize> = Foo { //~ ERROR E0277
x: 1, //~ ERROR: E0277
};
diff --git a/tests/ui/traits/bound/on-structs-and-enums-static.stderr b/tests/ui/traits/bound/on-structs-and-enums-static.stderr
index 42ebcc0..1413422 100644
--- a/tests/ui/traits/bound/on-structs-and-enums-static.stderr
+++ b/tests/ui/traits/bound/on-structs-and-enums-static.stderr
@@ -15,29 +15,11 @@
LL | struct Foo<T:Trait> {
| ^^^^^ required by this bound in `Foo`
-error[E0277]: the trait bound `usize: Trait` is not satisfied
- --> $DIR/on-structs-and-enums-static.rs:9:11
- |
-LL | static X: Foo<usize> = Foo {
- | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize`
- |
-help: this trait has no implementations, consider adding one
- --> $DIR/on-structs-and-enums-static.rs:1:1
- |
-LL | trait Trait {
- | ^^^^^^^^^^^
-note: required by a bound in `Foo`
- --> $DIR/on-structs-and-enums-static.rs:5:14
- |
-LL | struct Foo<T:Trait> {
- | ^^^^^ required by this bound in `Foo`
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0277]: the trait bound `usize: Trait` is not satisfied
- --> $DIR/on-structs-and-enums-static.rs:12:8
+error[E0277]: the trait bound `{integer}: Trait` is not satisfied
+ --> $DIR/on-structs-and-enums-static.rs:10:8
|
LL | x: 1,
- | ^ the trait `Trait` is not implemented for `usize`
+ | ^ the trait `Trait` is not implemented for `{integer}`
|
help: this trait has no implementations, consider adding one
--> $DIR/on-structs-and-enums-static.rs:1:1
@@ -50,6 +32,6 @@
LL | struct Foo<T:Trait> {
| ^^^^^ required by this bound in `Foo`
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr
index 9c49ee5..ff803ff 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr
@@ -1,5 +1,5 @@
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
- --> $DIR/const-drop-fail.rs:33:5
+ --> $DIR/const-drop-fail.rs:34:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -8,13 +8,13 @@
| ^^^^^^^^^^^^^^
|
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:24:19
+ --> $DIR/const-drop-fail.rs:25:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
- --> $DIR/const-drop-fail.rs:35:5
+ --> $DIR/const-drop-fail.rs:36:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -23,7 +23,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:24:19
+ --> $DIR/const-drop-fail.rs:25:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
diff --git a/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr
index 9c49ee5..ff803ff 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr
@@ -1,5 +1,5 @@
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
- --> $DIR/const-drop-fail.rs:33:5
+ --> $DIR/const-drop-fail.rs:34:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -8,13 +8,13 @@
| ^^^^^^^^^^^^^^
|
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:24:19
+ --> $DIR/const-drop-fail.rs:25:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
- --> $DIR/const-drop-fail.rs:35:5
+ --> $DIR/const-drop-fail.rs:36:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -23,7 +23,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:24:19
+ --> $DIR/const-drop-fail.rs:25:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
diff --git a/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr
index 9c49ee5..ff803ff 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr
@@ -1,5 +1,5 @@
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
- --> $DIR/const-drop-fail.rs:33:5
+ --> $DIR/const-drop-fail.rs:34:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -8,13 +8,13 @@
| ^^^^^^^^^^^^^^
|
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:24:19
+ --> $DIR/const-drop-fail.rs:25:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
- --> $DIR/const-drop-fail.rs:35:5
+ --> $DIR/const-drop-fail.rs:36:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -23,7 +23,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:24:19
+ --> $DIR/const-drop-fail.rs:25:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
diff --git a/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr
index 9c49ee5..ff803ff 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr
@@ -1,5 +1,5 @@
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
- --> $DIR/const-drop-fail.rs:33:5
+ --> $DIR/const-drop-fail.rs:34:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -8,13 +8,13 @@
| ^^^^^^^^^^^^^^
|
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:24:19
+ --> $DIR/const-drop-fail.rs:25:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
- --> $DIR/const-drop-fail.rs:35:5
+ --> $DIR/const-drop-fail.rs:36:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -23,7 +23,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:24:19
+ --> $DIR/const-drop-fail.rs:25:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
diff --git a/tests/ui/traits/const-traits/const-drop-fail.rs b/tests/ui/traits/const-traits/const-drop-fail.rs
index 4513d71..b74716f 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.rs
+++ b/tests/ui/traits/const-traits/const-drop-fail.rs
@@ -1,6 +1,7 @@
//@[new_precise] compile-flags: -Znext-solver
//@[new_stock] compile-flags: -Znext-solver
//@ revisions: new_stock old_stock new_precise old_precise
+//@ ignore-backends: gcc
#![feature(const_trait_impl, const_destruct)]
#![cfg_attr(any(new_precise, old_precise), feature(const_precise_live_drops))]
diff --git a/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs b/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs
index a5f6ae1..ee04f74 100644
--- a/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs
+++ b/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs
@@ -13,7 +13,7 @@ macro_rules! check {
compile_error!("ty");
};
(const $Trait:path) => {};
- ([const] $Trait:path) => {};
+ ([const] $Trait:path) => { [const] Trait };
}
check! { const Trait }
diff --git a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs
index 3dcdb0c..35e964e 100644
--- a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs
+++ b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs
@@ -4,18 +4,19 @@
// Setting the edition to 2018 since we don't regress `demo! { dyn const }` in Rust <2018.
//@ edition:2018
+trait Trait {}
+
macro_rules! demo {
- ($ty:ty) => { compile_error!("ty"); };
- //~^ ERROR ty
- //~| ERROR ty
- (impl $c:ident Trait) => {};
- (dyn $c:ident Trait) => {};
+ (impl $c:ident Trait) => { impl $c Trait {} };
+ //~^ ERROR inherent
+ //~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
+ (dyn $c:ident Trait) => { dyn $c Trait {} }; //~ ERROR macro expansion
}
demo! { impl const Trait }
//~^ ERROR const trait impls are experimental
demo! { dyn const Trait }
-//~^ ERROR const trait impls are experimental
fn main() {}
diff --git a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr
index b500e48..af160a4 100644
--- a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr
+++ b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr
@@ -1,27 +1,31 @@
-error: ty
- --> $DIR/macro-const-trait-bound-theoretical-regression.rs:8:19
+error: macro expansion ignores keyword `dyn` and any tokens following
+ --> $DIR/macro-const-trait-bound-theoretical-regression.rs:14:31
|
-LL | ($ty:ty) => { compile_error!("ty"); };
- | ^^^^^^^^^^^^^^^^^^^^
-...
-LL | demo! { impl const Trait }
- | -------------------------- in this macro invocation
- |
- = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: ty
- --> $DIR/macro-const-trait-bound-theoretical-regression.rs:8:19
- |
-LL | ($ty:ty) => { compile_error!("ty"); };
- | ^^^^^^^^^^^^^^^^^^^^
+LL | (dyn $c:ident Trait) => { dyn $c Trait {} };
+ | ^^^
...
LL | demo! { dyn const Trait }
- | ------------------------- in this macro invocation
+ | ------------------------- caused by the macro expansion here
|
+ = note: the usage of `demo!` is likely invalid in item context
+
+error: inherent impls cannot be `const`
+ --> $DIR/macro-const-trait-bound-theoretical-regression.rs:10:40
+ |
+LL | (impl $c:ident Trait) => { impl $c Trait {} };
+ | ^^^^^ inherent impl for this type
+...
+LL | demo! { impl const Trait }
+ | --------------------------
+ | | |
+ | | `const` because of this
+ | in this macro invocation
+ |
+ = note: only trait implementations may be annotated with `const`
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0658]: const trait impls are experimental
- --> $DIR/macro-const-trait-bound-theoretical-regression.rs:15:14
+ --> $DIR/macro-const-trait-bound-theoretical-regression.rs:17:14
|
LL | demo! { impl const Trait }
| ^^^^^
@@ -30,16 +34,24 @@
= help: add `#![feature(const_trait_impl)]` 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]: const trait impls are experimental
- --> $DIR/macro-const-trait-bound-theoretical-regression.rs:18:13
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/macro-const-trait-bound-theoretical-regression.rs:10:40
|
-LL | demo! { dyn const Trait }
- | ^^^^^
+LL | (impl $c:ident Trait) => { impl $c Trait {} };
+ | ^^^^^
+...
+LL | demo! { impl const Trait }
+ | -------------------------- in this macro invocation
|
- = note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
- = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+ = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: `#[warn(bare_trait_objects)]` on by default
+ = note: this warning originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might have intended to implement this trait for a given type
+ |
+LL | (impl $c:ident Trait) => { impl $c Trait for /* Type */ {} };
+ | ++++++++++++++
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/const-traits/span-bug-issue-121418.stderr b/tests/ui/traits/const-traits/span-bug-issue-121418.stderr
index 92cfecd..f31129d 100644
--- a/tests/ui/traits/const-traits/span-bug-issue-121418.stderr
+++ b/tests/ui/traits/const-traits/span-bug-issue-121418.stderr
@@ -14,8 +14,8 @@
LL | pub const fn new() -> std::sync::Mutex<dyn T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
- = help: within `Mutex<(dyn T + 'static)>`, the trait `Sized` is not implemented for `(dyn T + 'static)`
-note: required because it appears within the type `Mutex<(dyn T + 'static)>`
+ = help: within `std::sync::Mutex<(dyn T + 'static)>`, the trait `Sized` is not implemented for `(dyn T + 'static)`
+note: required because it appears within the type `std::sync::Mutex<(dyn T + 'static)>`
--> $SRC_DIR/std/src/sync/poison/mutex.rs:LL:COL
= note: the return type of a function must have a statically known size
@@ -27,7 +27,7 @@
| |
| implicitly returns `()` as its body has no tail or `return` expression
|
- = note: expected struct `Mutex<(dyn T + 'static)>`
+ = note: expected struct `std::sync::Mutex<(dyn T + 'static)>`
found unit type `()`
error: aborting due to 3 previous errors
diff --git a/tests/ui/issues/issue-23281.rs b/tests/ui/traits/dyn-trait-size-error-23281.rs
similarity index 76%
rename from tests/ui/issues/issue-23281.rs
rename to tests/ui/traits/dyn-trait-size-error-23281.rs
index 7271689..8e44b8c 100644
--- a/tests/ui/issues/issue-23281.rs
+++ b/tests/ui/traits/dyn-trait-size-error-23281.rs
@@ -10,3 +10,5 @@ struct Vec<T> {
}
fn main() {}
+
+// https://github.com/rust-lang/rust/issues/23281
diff --git a/tests/ui/issues/issue-23281.stderr b/tests/ui/traits/dyn-trait-size-error-23281.stderr
similarity index 86%
rename from tests/ui/issues/issue-23281.stderr
rename to tests/ui/traits/dyn-trait-size-error-23281.stderr
index ee079f2..d7b791a 100644
--- a/tests/ui/issues/issue-23281.stderr
+++ b/tests/ui/traits/dyn-trait-size-error-23281.stderr
@@ -1,17 +1,17 @@
error[E0277]: the size for values of type `(dyn Fn() + 'static)` cannot be known at compilation time
- --> $DIR/issue-23281.rs:4:27
+ --> $DIR/dyn-trait-size-error-23281.rs:4:27
|
LL | pub fn function(funs: Vec<dyn Fn() -> ()>) {}
| ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn Fn() + 'static)`
note: required by an implicit `Sized` bound in `Vec`
- --> $DIR/issue-23281.rs:8:12
+ --> $DIR/dyn-trait-size-error-23281.rs:8:12
|
LL | struct Vec<T> {
| ^ required by the implicit `Sized` requirement on this type parameter in `Vec`
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
- --> $DIR/issue-23281.rs:8:12
+ --> $DIR/dyn-trait-size-error-23281.rs:8:12
|
LL | struct Vec<T> {
| ^ this could be changed to `T: ?Sized`...
diff --git a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
index c8a1329..a0bfc52 100644
--- a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
+++ b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
@@ -23,7 +23,7 @@
| ^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: if this is a dyn-compatible trait, use `dyn`
|
diff --git a/tests/ui/issues/issue-10465.rs b/tests/ui/traits/nested-mod-trait-method-lookup-leak-10465.rs
similarity index 80%
rename from tests/ui/issues/issue-10465.rs
rename to tests/ui/traits/nested-mod-trait-method-lookup-leak-10465.rs
index d899c3f..d5a5009 100644
--- a/tests/ui/issues/issue-10465.rs
+++ b/tests/ui/traits/nested-mod-trait-method-lookup-leak-10465.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/10465
+
pub mod a {
pub trait A {
fn foo(&self);
diff --git a/tests/ui/issues/issue-10465.stderr b/tests/ui/traits/nested-mod-trait-method-lookup-leak-10465.stderr
similarity index 87%
rename from tests/ui/issues/issue-10465.stderr
rename to tests/ui/traits/nested-mod-trait-method-lookup-leak-10465.stderr
index 0f46ebe..ffd8fd3 100644
--- a/tests/ui/issues/issue-10465.stderr
+++ b/tests/ui/traits/nested-mod-trait-method-lookup-leak-10465.stderr
@@ -1,5 +1,5 @@
error[E0599]: no method named `foo` found for reference `&B` in the current scope
- --> $DIR/issue-10465.rs:17:15
+ --> $DIR/nested-mod-trait-method-lookup-leak-10465.rs:19:15
|
LL | b.foo();
| ^^^ method not found in `&B`
diff --git a/tests/ui/issues/issue-36839.rs b/tests/ui/traits/trait-associated-type-bounds-36839.rs
similarity index 85%
rename from tests/ui/issues/issue-36839.rs
rename to tests/ui/traits/trait-associated-type-bounds-36839.rs
index 654c0f6..156c063 100644
--- a/tests/ui/issues/issue-36839.rs
+++ b/tests/ui/traits/trait-associated-type-bounds-36839.rs
@@ -19,3 +19,5 @@ fn broken(&self) where Self::Assoc: Foo {
fn main() {
let _m: &dyn Broken<Assoc=()> = &();
}
+
+// https://github.com/rust-lang/rust/issues/36839
diff --git a/tests/ui/issues/issue-5280.rs b/tests/ui/traits/trait-implementation-for-primitive-type-5280.rs
similarity index 83%
rename from tests/ui/issues/issue-5280.rs
rename to tests/ui/traits/trait-implementation-for-primitive-type-5280.rs
index 66452c3..72a4283 100644
--- a/tests/ui/issues/issue-5280.rs
+++ b/tests/ui/traits/trait-implementation-for-primitive-type-5280.rs
@@ -16,3 +16,5 @@ fn tag_to_string(self) {
pub fn main() {
5.tag_to_string();
}
+
+// https://github.com/rust-lang/rust/issues/5280
diff --git a/tests/ui/issues/issue-5321-immediates-with-bare-self.rs b/tests/ui/traits/trait-implementation-for-usize-5321.rs
similarity index 77%
rename from tests/ui/issues/issue-5321-immediates-with-bare-self.rs
rename to tests/ui/traits/trait-implementation-for-usize-5321.rs
index cb35a64..ab997b6 100644
--- a/tests/ui/issues/issue-5321-immediates-with-bare-self.rs
+++ b/tests/ui/traits/trait-implementation-for-usize-5321.rs
@@ -13,3 +13,5 @@ fn yes(self) {
pub fn main() {
2.yes();
}
+
+// https://github.com/rust-lang/rust/issues/5321
diff --git a/tests/ui/traits/unspecified-self-in-trait-ref.stderr b/tests/ui/traits/unspecified-self-in-trait-ref.stderr
index 6f5ae78..2e87245 100644
--- a/tests/ui/traits/unspecified-self-in-trait-ref.stderr
+++ b/tests/ui/traits/unspecified-self-in-trait-ref.stderr
@@ -5,7 +5,7 @@
| ^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
@@ -25,7 +25,7 @@
| ^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | let b = <dyn Foo::<_>>::lol();
@@ -44,7 +44,7 @@
| ^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | let c = <dyn Bar>::lol();
@@ -63,7 +63,7 @@
| ^^^^^^^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | let d = <dyn Bar::<usize, _>>::lol();
@@ -82,7 +82,7 @@
| ^^^^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | let e = <dyn Bar::<usize>>::lol();
diff --git a/tests/ui/transmutability/enums/niche_optimization.rs b/tests/ui/transmutability/enums/niche_optimization.rs
index 2436be5..316a857 100644
--- a/tests/ui/transmutability/enums/niche_optimization.rs
+++ b/tests/ui/transmutability/enums/niche_optimization.rs
@@ -75,8 +75,8 @@ enum OptionLike {
assert::is_transmutable::<OptionLike, u8>();
assert::is_transmutable::<V0, OptionLike>();
+ assert::is_transmutable::<V1, OptionLike>();
assert::is_transmutable::<V254, OptionLike>();
- assert::is_transmutable::<V255, OptionLike>();
}
fn one_niche_alt() {
@@ -97,9 +97,9 @@ enum OptionLike {
};
assert::is_transmutable::<OptionLike, u8>();
- assert::is_transmutable::<V0, OptionLike>();
+ assert::is_transmutable::<V1, OptionLike>();
+ assert::is_transmutable::<V2, OptionLike>();
assert::is_transmutable::<V254, OptionLike>();
- assert::is_transmutable::<V255, OptionLike>();
}
fn two_niche() {
@@ -121,9 +121,9 @@ enum OptionLike {
assert::is_transmutable::<OptionLike, u8>();
assert::is_transmutable::<V0, OptionLike>();
+ assert::is_transmutable::<V1, OptionLike>();
+ assert::is_transmutable::<V2, OptionLike>();
assert::is_transmutable::<V253, OptionLike>();
- assert::is_transmutable::<V254, OptionLike>();
- assert::is_transmutable::<V255, OptionLike>();
}
fn no_niche() {
@@ -142,7 +142,7 @@ enum OptionLike {
}
const _: () = {
- assert!(std::mem::size_of::<OptionLike>() == 2);
+ assert!(std::mem::size_of::<OptionLike>() == 1);
};
#[repr(C)]
diff --git a/tests/ui/issues/issue-21174.rs b/tests/ui/transmutability/transmute-between-associated-types-with-lifetimers-21174.rs
similarity index 82%
rename from tests/ui/issues/issue-21174.rs
rename to tests/ui/transmutability/transmute-between-associated-types-with-lifetimers-21174.rs
index 0782742..22cb379 100644
--- a/tests/ui/issues/issue-21174.rs
+++ b/tests/ui/transmutability/transmute-between-associated-types-with-lifetimers-21174.rs
@@ -9,3 +9,5 @@ fn foo<'a, T: Trait<'a>>(value: T::A) {
}
fn main() { }
+
+// https://github.com/rust-lang/rust/issues/21174
diff --git a/tests/ui/issues/issue-21174.stderr b/tests/ui/transmutability/transmute-between-associated-types-with-lifetimers-21174.stderr
similarity index 86%
rename from tests/ui/issues/issue-21174.stderr
rename to tests/ui/transmutability/transmute-between-associated-types-with-lifetimers-21174.stderr
index a6b75c9..5c0cd91 100644
--- a/tests/ui/issues/issue-21174.stderr
+++ b/tests/ui/transmutability/transmute-between-associated-types-with-lifetimers-21174.stderr
@@ -1,5 +1,5 @@
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
- --> $DIR/issue-21174.rs:7:30
+ --> $DIR/transmute-between-associated-types-with-lifetimers-21174.rs:7:30
|
LL | let new: T::B = unsafe { std::mem::transmute(value) };
| ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/type-alias-enum-variants/self-in-enum-definition.stderr b/tests/ui/type-alias-enum-variants/self-in-enum-definition.stderr
index 084008d..13ae6df 100644
--- a/tests/ui/type-alias-enum-variants/self-in-enum-definition.stderr
+++ b/tests/ui/type-alias-enum-variants/self-in-enum-definition.stderr
@@ -9,36 +9,6 @@
|
LL | V3 = Self::V1 {} as u8 + 2,
| ^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires caching mir of `Alpha::V3::{constant#0}` for CTFE...
- --> $DIR/self-in-enum-definition.rs:5:10
- |
-LL | V3 = Self::V1 {} as u8 + 2,
- | ^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires elaborating drops for `Alpha::V3::{constant#0}`...
- --> $DIR/self-in-enum-definition.rs:5:10
- |
-LL | V3 = Self::V1 {} as u8 + 2,
- | ^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires borrow-checking `Alpha::V3::{constant#0}`...
- --> $DIR/self-in-enum-definition.rs:5:10
- |
-LL | V3 = Self::V1 {} as u8 + 2,
- | ^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires promoting constants in MIR for `Alpha::V3::{constant#0}`...
- --> $DIR/self-in-enum-definition.rs:5:10
- |
-LL | V3 = Self::V1 {} as u8 + 2,
- | ^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const checking `Alpha::V3::{constant#0}`...
- --> $DIR/self-in-enum-definition.rs:5:10
- |
-LL | V3 = Self::V1 {} as u8 + 2,
- | ^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires building MIR for `Alpha::V3::{constant#0}`...
- --> $DIR/self-in-enum-definition.rs:5:10
- |
-LL | V3 = Self::V1 {} as u8 + 2,
- | ^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing layout of `Alpha`...
= note: ...which again requires simplifying constant for the type system `Alpha::V3::{constant#0}`, completing the cycle
note: cycle used when checking that `Alpha` is well-formed
diff --git a/tests/ui/type-alias-impl-trait/issue-60662.stdout b/tests/ui/type-alias-impl-trait/issue-60662.stdout
index 52152a7..7ad29c8 100644
--- a/tests/ui/type-alias-impl-trait/issue-60662.stdout
+++ b/tests/ui/type-alias-impl-trait/issue-60662.stdout
@@ -3,10 +3,10 @@
//@ edition: 2015
#![feature(type_alias_impl_trait)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
trait Animal { }
diff --git a/tests/ui/issues/issue-102964.rs b/tests/ui/type-alias/dummy-binder-102964.rs
similarity index 74%
rename from tests/ui/issues/issue-102964.rs
rename to tests/ui/type-alias/dummy-binder-102964.rs
index 43ff236..6b6fa3e 100644
--- a/tests/ui/issues/issue-102964.rs
+++ b/tests/ui/type-alias/dummy-binder-102964.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/102964
+
use std::rc::Rc;
type Foo<'a, T> = &'a dyn Fn(&T);
type RcFoo<'a, T> = Rc<Foo<'a, T>>;
diff --git a/tests/ui/issues/issue-102964.stderr b/tests/ui/type-alias/dummy-binder-102964.stderr
similarity index 93%
rename from tests/ui/issues/issue-102964.stderr
rename to tests/ui/type-alias/dummy-binder-102964.stderr
index 0e2761f..fc32cab 100644
--- a/tests/ui/issues/issue-102964.stderr
+++ b/tests/ui/type-alias/dummy-binder-102964.stderr
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
- --> $DIR/issue-102964.rs:5:41
+ --> $DIR/dummy-binder-102964.rs:7:41
|
LL | fn bar_function<T>(function: Foo<T>) -> RcFoo<T> {
| ------------ ^^^^^^^^ expected `Rc<&dyn Fn(&T)>`, found `()`
diff --git a/tests/ui/issues/issue-11047.rs b/tests/ui/type-alias/static-method-type-alias-11047.rs
similarity index 87%
rename from tests/ui/issues/issue-11047.rs
rename to tests/ui/type-alias/static-method-type-alias-11047.rs
index 6e1b285..efb336f 100644
--- a/tests/ui/issues/issue-11047.rs
+++ b/tests/ui/type-alias/static-method-type-alias-11047.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/11047
+
//@ run-pass
// Test that static methods can be invoked on `type` aliases
diff --git a/tests/ui/issues/issue-14382.rs b/tests/ui/type-inference/float-type-inference-unification-14382.rs
similarity index 84%
rename from tests/ui/issues/issue-14382.rs
rename to tests/ui/type-inference/float-type-inference-unification-14382.rs
index 74d9387..5bf497d 100644
--- a/tests/ui/issues/issue-14382.rs
+++ b/tests/ui/type-inference/float-type-inference-unification-14382.rs
@@ -13,3 +13,5 @@ fn main() {
let m : Matrix4<f32> = translate(x);
println!("m: {:?}", m);
}
+
+// https://github.com/rust-lang/rust/issues/14382
diff --git a/tests/ui/typeck/assign-non-lval-derefmut.fixed b/tests/ui/typeck/assign-non-lval-derefmut.fixed
index 6ecec57..e6f97a9 100644
--- a/tests/ui/typeck/assign-non-lval-derefmut.fixed
+++ b/tests/ui/typeck/assign-non-lval-derefmut.fixed
@@ -5,11 +5,11 @@
*x.lock().unwrap() = 2;
//~^ ERROR invalid left-hand side of assignment
*x.lock().unwrap() += 1;
- //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+ //~^ ERROR binary assignment operation `+=` cannot be applied to type `std::sync::MutexGuard<'_, usize>`
let mut y = x.lock().unwrap();
*y = 2;
//~^ ERROR mismatched types
*y += 1;
- //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+ //~^ ERROR binary assignment operation `+=` cannot be applied to type `std::sync::MutexGuard<'_, usize>`
}
diff --git a/tests/ui/typeck/assign-non-lval-derefmut.rs b/tests/ui/typeck/assign-non-lval-derefmut.rs
index ac1be91..a53a52c 100644
--- a/tests/ui/typeck/assign-non-lval-derefmut.rs
+++ b/tests/ui/typeck/assign-non-lval-derefmut.rs
@@ -5,11 +5,11 @@ fn main() {
x.lock().unwrap() = 2;
//~^ ERROR invalid left-hand side of assignment
x.lock().unwrap() += 1;
- //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+ //~^ ERROR binary assignment operation `+=` cannot be applied to type `std::sync::MutexGuard<'_, usize>`
let mut y = x.lock().unwrap();
y = 2;
//~^ ERROR mismatched types
y += 1;
- //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+ //~^ ERROR binary assignment operation `+=` cannot be applied to type `std::sync::MutexGuard<'_, usize>`
}
diff --git a/tests/ui/typeck/assign-non-lval-derefmut.stderr b/tests/ui/typeck/assign-non-lval-derefmut.stderr
index 16fb1e9c..f57b5ab 100644
--- a/tests/ui/typeck/assign-non-lval-derefmut.stderr
+++ b/tests/ui/typeck/assign-non-lval-derefmut.stderr
@@ -11,15 +11,15 @@
LL | *x.lock().unwrap() = 2;
| +
-error[E0368]: binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+error[E0368]: binary assignment operation `+=` cannot be applied to type `std::sync::MutexGuard<'_, usize>`
--> $DIR/assign-non-lval-derefmut.rs:7:5
|
LL | x.lock().unwrap() += 1;
| -----------------^^^^^
| |
- | cannot use `+=` on type `MutexGuard<'_, usize>`
+ | cannot use `+=` on type `std::sync::MutexGuard<'_, usize>`
|
-note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
+note: the foreign item type `std::sync::MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
--> $SRC_DIR/std/src/sync/poison/mutex.rs:LL:COL
|
= note: not implement `AddAssign<{integer}>`
@@ -36,22 +36,22 @@
LL | y = 2;
| ^ expected `MutexGuard<'_, usize>`, found integer
|
- = note: expected struct `MutexGuard<'_, usize>`
+ = note: expected struct `std::sync::MutexGuard<'_, usize>`
found type `{integer}`
help: consider dereferencing here to assign to the mutably borrowed value
|
LL | *y = 2;
| +
-error[E0368]: binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+error[E0368]: binary assignment operation `+=` cannot be applied to type `std::sync::MutexGuard<'_, usize>`
--> $DIR/assign-non-lval-derefmut.rs:13:5
|
LL | y += 1;
| -^^^^^
| |
- | cannot use `+=` on type `MutexGuard<'_, usize>`
+ | cannot use `+=` on type `std::sync::MutexGuard<'_, usize>`
|
-note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
+note: the foreign item type `std::sync::MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
--> $SRC_DIR/std/src/sync/poison/mutex.rs:LL:COL
|
= note: not implement `AddAssign<{integer}>`
diff --git a/tests/ui/typeck/deref-multi.stderr b/tests/ui/typeck/deref-multi.stderr
index 0251385..c4fa49e 100644
--- a/tests/ui/typeck/deref-multi.stderr
+++ b/tests/ui/typeck/deref-multi.stderr
@@ -63,7 +63,7 @@
| ^^^^^^^^^^^^^^^^^ expected `i32`, found `MutexGuard<'_, &i32>`
|
= note: expected type `i32`
- found struct `MutexGuard<'_, &i32>`
+ found struct `std::sync::MutexGuard<'_, &i32>`
help: consider dereferencing the type
|
LL | **x.lock().unwrap()
diff --git a/tests/ui/typeck/suggestions/suggest-clone-in-macro-issue-139253.rs b/tests/ui/typeck/suggestions/suggest-clone-in-macro-issue-139253.rs
new file mode 100644
index 0000000..3b3ea05
--- /dev/null
+++ b/tests/ui/typeck/suggestions/suggest-clone-in-macro-issue-139253.rs
@@ -0,0 +1,19 @@
+#[derive(Debug, Clone)]
+struct Struct { field: S }
+
+#[derive(Debug, Clone)]
+struct S;
+
+macro_rules! expand {
+ ($ident:ident) => { Struct { $ident } }
+}
+
+fn test1() {
+ let field = &S;
+ let a: Struct = dbg!(expand!(field)); //~ ERROR mismatched types [E0308]
+ let b: Struct = dbg!(Struct { field }); //~ ERROR mismatched types [E0308]
+ let c: S = dbg!(field); //~ ERROR mismatched types [E0308]
+ let c: S = dbg!(dbg!(field)); //~ ERROR mismatched types [E0308]
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/suggestions/suggest-clone-in-macro-issue-139253.stderr b/tests/ui/typeck/suggestions/suggest-clone-in-macro-issue-139253.stderr
new file mode 100644
index 0000000..59e56f6
--- /dev/null
+++ b/tests/ui/typeck/suggestions/suggest-clone-in-macro-issue-139253.stderr
@@ -0,0 +1,49 @@
+error[E0308]: mismatched types
+ --> $DIR/suggest-clone-in-macro-issue-139253.rs:13:34
+ |
+LL | let a: Struct = dbg!(expand!(field));
+ | ^^^^^ expected `S`, found `&S`
+ |
+help: consider using clone here
+ |
+LL | let a: Struct = dbg!(expand!(field: field.clone()));
+ | +++++++++++++++
+
+error[E0308]: mismatched types
+ --> $DIR/suggest-clone-in-macro-issue-139253.rs:14:35
+ |
+LL | let b: Struct = dbg!(Struct { field });
+ | ^^^^^ expected `S`, found `&S`
+ |
+help: consider using clone here
+ |
+LL | let b: Struct = dbg!(Struct { field: field.clone() });
+ | +++++++++++++++
+
+error[E0308]: mismatched types
+ --> $DIR/suggest-clone-in-macro-issue-139253.rs:15:16
+ |
+LL | let c: S = dbg!(field);
+ | ^^^^^^^^^^^ expected `S`, found `&S`
+ |
+ = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider using clone here
+ |
+LL | let c: S = dbg!(field).clone();
+ | ++++++++
+
+error[E0308]: mismatched types
+ --> $DIR/suggest-clone-in-macro-issue-139253.rs:16:16
+ |
+LL | let c: S = dbg!(dbg!(field));
+ | ^^^^^^^^^^^^^^^^^ expected `S`, found `&S`
+ |
+ = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider using clone here
+ |
+LL | let c: S = dbg!(dbg!(field)).clone();
+ | ++++++++
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/issues/issue-18952.rs b/tests/ui/unboxed-closures/fn-traits-overloading-arity-18952.rs
similarity index 96%
rename from tests/ui/issues/issue-18952.rs
rename to tests/ui/unboxed-closures/fn-traits-overloading-arity-18952.rs
index 9fdafb1..4e3bc9b 100644
--- a/tests/ui/issues/issue-18952.rs
+++ b/tests/ui/unboxed-closures/fn-traits-overloading-arity-18952.rs
@@ -54,3 +54,5 @@ fn main() {
assert_eq!(foo(1, 1), (2, 2));
assert_eq!(foo(1, 1, 1), (4, 4, 4));
}
+
+// https://github.com/rust-lang/rust/issues/18952
diff --git a/tests/ui/issues/issue-22789.rs b/tests/ui/unboxed-closures/unboxed-closure-call-22789.rs
similarity index 71%
rename from tests/ui/issues/issue-22789.rs
rename to tests/ui/unboxed-closures/unboxed-closure-call-22789.rs
index 95ebe6b..0bc8bed 100644
--- a/tests/ui/issues/issue-22789.rs
+++ b/tests/ui/unboxed-closures/unboxed-closure-call-22789.rs
@@ -6,3 +6,5 @@ fn main() {
let k = |x: i32| { x + 1 };
Fn::call(&k, (0,));
}
+
+// https://github.com/rust-lang/rust/issues/22789
diff --git a/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
index cf43913..8d9a61c 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
@@ -2,9 +2,11 @@
--> $DIR/unboxed-closure-illegal-move.rs:15:31
|
LL | let x = Box::new(0);
- | - captured outer variable
+ | - ----------- move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+ | |
+ | captured outer variable
LL | let f = to_fn(|| drop(x));
- | -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+ | -- ^ `x` is moved here
| |
| captured by this `Fn` closure
|
@@ -17,9 +19,11 @@
--> $DIR/unboxed-closure-illegal-move.rs:19:35
|
LL | let x = Box::new(0);
- | - captured outer variable
+ | - ----------- move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+ | |
+ | captured outer variable
LL | let f = to_fn_mut(|| drop(x));
- | -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+ | -- ^ `x` is moved here
| |
| captured by this `FnMut` closure
|
@@ -32,9 +36,11 @@
--> $DIR/unboxed-closure-illegal-move.rs:28:36
|
LL | let x = Box::new(0);
- | - captured outer variable
+ | - ----------- move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+ | |
+ | captured outer variable
LL | let f = to_fn(move || drop(x));
- | ------- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+ | ------- ^ `x` is moved here
| |
| captured by this `Fn` closure
@@ -42,9 +48,11 @@
--> $DIR/unboxed-closure-illegal-move.rs:32:40
|
LL | let x = Box::new(0);
- | - captured outer variable
+ | - ----------- move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+ | |
+ | captured outer variable
LL | let f = to_fn_mut(move || drop(x));
- | ------- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+ | ------- ^ `x` is moved here
| |
| captured by this `FnMut` closure
diff --git a/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs b/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs
index 2c2788a..e439a82 100644
--- a/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs
+++ b/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs
@@ -1,5 +1,6 @@
//@ run-pass
//@ needs-unwind
+//@ ignore-backends: gcc
// See https://github.com/rust-lang/rust/issues/135802
enum Void {}
diff --git a/tests/ui/union/union-borrow-move-parent-sibling.stderr b/tests/ui/union/union-borrow-move-parent-sibling.stderr
index f8e9609..461ee40 100644
--- a/tests/ui/union/union-borrow-move-parent-sibling.stderr
+++ b/tests/ui/union/union-borrow-move-parent-sibling.stderr
@@ -31,6 +31,15 @@
| --- value moved here
LL | let b = u.y;
| ^^^ value used here after move
+ |
+note: if `U` implemented `Clone`, you could clone the value
+ --> $DIR/union-borrow-move-parent-sibling.rs:43:1
+ |
+LL | union U {
+ | ^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let a = u.x;
+ | --- you could clone this value
error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`)
--> $DIR/union-borrow-move-parent-sibling.rs:67:13
@@ -73,6 +82,15 @@
| --- value moved here
LL | let b = u.y;
| ^^^ value used here after move
+ |
+note: if `U` implemented `Clone`, you could clone the value
+ --> $DIR/union-borrow-move-parent-sibling.rs:43:1
+ |
+LL | union U {
+ | ^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let a = u.x;
+ | --- you could clone this value
error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`)
--> $DIR/union-borrow-move-parent-sibling.rs:81:13
diff --git a/tests/ui/unpretty/bad-literal.stdout b/tests/ui/unpretty/bad-literal.stdout
index ba84673..1f697af 100644
--- a/tests/ui/unpretty/bad-literal.stdout
+++ b/tests/ui/unpretty/bad-literal.stdout
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ compile-flags: -Zunpretty=hir
//@ check-fail
//@ edition: 2015
diff --git a/tests/ui/unpretty/debug-fmt-hir.stdout b/tests/ui/unpretty/debug-fmt-hir.stdout
index 1d224c9..9c79421 100644
--- a/tests/ui/unpretty/debug-fmt-hir.stdout
+++ b/tests/ui/unpretty/debug-fmt-hir.stdout
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ compile-flags: -Zunpretty=hir
//@ check-pass
//@ edition: 2015
diff --git a/tests/ui/unpretty/deprecated-attr.stdout b/tests/ui/unpretty/deprecated-attr.stdout
index 0abeef6..26cc74c 100644
--- a/tests/ui/unpretty/deprecated-attr.stdout
+++ b/tests/ui/unpretty/deprecated-attr.stdout
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ compile-flags: -Zunpretty=hir
//@ check-pass
//@ edition: 2015
diff --git a/tests/ui/unpretty/diagnostic-attr.stdout b/tests/ui/unpretty/diagnostic-attr.stdout
index a1325c6..4822cf4 100644
--- a/tests/ui/unpretty/diagnostic-attr.stdout
+++ b/tests/ui/unpretty/diagnostic-attr.stdout
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ compile-flags: -Zunpretty=hir
//@ check-pass
//@ edition: 2015
diff --git a/tests/ui/unpretty/exhaustive-asm.expanded.stdout b/tests/ui/unpretty/exhaustive-asm.expanded.stdout
index 92829b0..9a58e4c 100644
--- a/tests/ui/unpretty/exhaustive-asm.expanded.stdout
+++ b/tests/ui/unpretty/exhaustive-asm.expanded.stdout
@@ -1,8 +1,8 @@
#![feature(prelude_import)]
-#[prelude_import]
-use std::prelude::rust_2024::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use std::prelude::rust_2024::*;
//@ revisions: expanded hir
//@[expanded]compile-flags: -Zunpretty=expanded
//@[expanded]check-pass
diff --git a/tests/ui/unpretty/exhaustive-asm.hir.stdout b/tests/ui/unpretty/exhaustive-asm.hir.stdout
index bbd846a..b33b38c 100644
--- a/tests/ui/unpretty/exhaustive-asm.hir.stdout
+++ b/tests/ui/unpretty/exhaustive-asm.hir.stdout
@@ -1,7 +1,7 @@
-#[prelude_import]
-use std::prelude::rust_2024::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use std::prelude::rust_2024::*;
//@ revisions: expanded hir
//@[expanded]compile-flags: -Zunpretty=expanded
//@[expanded]check-pass
diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout
index 53ca3c8..6b08f3e 100644
--- a/tests/ui/unpretty/exhaustive.expanded.stdout
+++ b/tests/ui/unpretty/exhaustive.expanded.stdout
@@ -29,10 +29,10 @@
#![feature(try_blocks)]
#![feature(yeet_expr)]
#![allow(incomplete_features)]
-#[prelude_import]
-use std::prelude::rust_2024::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use std::prelude::rust_2024::*;
#[prelude_import]
use self::prelude::*;
diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout
index 7780772..9cfa65f 100644
--- a/tests/ui/unpretty/exhaustive.hir.stdout
+++ b/tests/ui/unpretty/exhaustive.hir.stdout
@@ -28,10 +28,10 @@
#![feature(try_blocks)]
#![feature(yeet_expr)]
#![allow(incomplete_features)]
-#[prelude_import]
-use std::prelude::rust_2024::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use std::prelude::rust_2024::*;
#[prelude_import]
use self::prelude::*;
diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout
index 3cd0273..0792dc1 100644
--- a/tests/ui/unpretty/flattened-format-args.stdout
+++ b/tests/ui/unpretty/flattened-format-args.stdout
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ compile-flags: -Zunpretty=hir -Zflatten-format-args=yes
//@ check-pass
//@ edition: 2015
diff --git a/tests/ui/unpretty/interpolation-expanded.stdout b/tests/ui/unpretty/interpolation-expanded.stdout
index d46b46b..7284a89 100644
--- a/tests/ui/unpretty/interpolation-expanded.stdout
+++ b/tests/ui/unpretty/interpolation-expanded.stdout
@@ -10,10 +10,10 @@
// synthesizing parentheses indiscriminately; only where necessary.
#![feature(if_let_guard)]
-#[prelude_import]
-use std::prelude::rust_2024::*;
#[macro_use]
extern crate std;
+#[prelude_import]
+use std::prelude::rust_2024::*;
macro_rules! expr { ($expr:expr) => { $expr }; }
diff --git a/tests/ui/unpretty/let-else-hir.stdout b/tests/ui/unpretty/let-else-hir.stdout
index a83790d..14270a5 100644
--- a/tests/ui/unpretty/let-else-hir.stdout
+++ b/tests/ui/unpretty/let-else-hir.stdout
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ compile-flags: -Zunpretty=hir
//@ check-pass
//@ edition: 2015
diff --git a/tests/ui/unpretty/self-hir.stdout b/tests/ui/unpretty/self-hir.stdout
index 1eafc3c..b190565 100644
--- a/tests/ui/unpretty/self-hir.stdout
+++ b/tests/ui/unpretty/self-hir.stdout
@@ -1,7 +1,7 @@
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
//@ compile-flags: -Zunpretty=hir
//@ check-pass
//@ edition: 2015
diff --git a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout
index e9fd222..c04909a 100644
--- a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout
+++ b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout
@@ -8,10 +8,10 @@
//@ compile-flags: -Zunpretty=hir,typed
//@ edition: 2015
#![allow(dead_code)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
fn main() ({ } as ())
diff --git a/tests/ui/issues/issue-7246.rs b/tests/ui/unreachable-code/unreachable-bool-read-7246.rs
similarity index 79%
rename from tests/ui/issues/issue-7246.rs
rename to tests/ui/unreachable-code/unreachable-bool-read-7246.rs
index 7b16fa0..8bbaa10 100644
--- a/tests/ui/issues/issue-7246.rs
+++ b/tests/ui/unreachable-code/unreachable-bool-read-7246.rs
@@ -9,3 +9,5 @@ pub unsafe fn g() {
}
pub fn main() {}
+
+// https://github.com/rust-lang/rust/issues/7246
diff --git a/tests/ui/issues/issue-7246.stderr b/tests/ui/unreachable-code/unreachable-bool-read-7246.stderr
similarity index 80%
rename from tests/ui/issues/issue-7246.stderr
rename to tests/ui/unreachable-code/unreachable-bool-read-7246.stderr
index 1fb6ab1..6072160 100644
--- a/tests/ui/issues/issue-7246.stderr
+++ b/tests/ui/unreachable-code/unreachable-bool-read-7246.stderr
@@ -1,5 +1,5 @@
error: unreachable statement
- --> $DIR/issue-7246.rs:7:5
+ --> $DIR/unreachable-bool-read-7246.rs:7:5
|
LL | return;
| ------ any code following this expression is unreachable
@@ -7,13 +7,13 @@
| ^^^^^^^^^^^^^^^^^^^ unreachable statement
|
note: the lint level is defined here
- --> $DIR/issue-7246.rs:1:9
+ --> $DIR/unreachable-bool-read-7246.rs:1:9
|
LL | #![deny(unreachable_code)]
| ^^^^^^^^^^^^^^^^
warning: dereferencing a null pointer
- --> $DIR/issue-7246.rs:7:8
+ --> $DIR/unreachable-bool-read-7246.rs:7:8
|
LL | if *ptr::null() {};
| ^^^^^^^^^^^^ this code causes undefined behavior when executed
diff --git a/tests/ui/unsafe-binders/moves.stderr b/tests/ui/unsafe-binders/moves.stderr
index 0f976d9..bd48015 100644
--- a/tests/ui/unsafe-binders/moves.stderr
+++ b/tests/ui/unsafe-binders/moves.stderr
@@ -16,6 +16,15 @@
| ---- value moved here
LL | drop(base);
| ^^^^ value used here after move
+ |
+note: if `NotCopyInner` implemented `Clone`, you could clone the value
+ --> $DIR/moves.rs:8:1
+ |
+LL | struct NotCopyInner;
+ | ^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let binder: unsafe<> NotCopy = wrap_binder!(base);
+ | ---- you could clone this value
error[E0382]: use of moved value: `binder`
--> $DIR/moves.rs:24:14
diff --git a/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr b/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr
index a02c604..8a26b45 100644
--- a/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr
+++ b/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr
@@ -4,7 +4,7 @@
LL | unsf();
| ^^^^^^ call to unsafe function
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: consult the function's documentation for information on how to avoid undefined behavior
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/edition-2024-unsafe_op_in_unsafe_fn.rs:8:1
diff --git a/tests/ui/issues/issue-11004.rs b/tests/ui/unsafe/raw-pointer-field-access-error.rs
similarity index 88%
rename from tests/ui/issues/issue-11004.rs
rename to tests/ui/unsafe/raw-pointer-field-access-error.rs
index 0c34554..04b45b2 100644
--- a/tests/ui/issues/issue-11004.rs
+++ b/tests/ui/unsafe/raw-pointer-field-access-error.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/11004
+
use std::mem;
struct A { x: i32, y: f64 }
diff --git a/tests/ui/issues/issue-11004.stderr b/tests/ui/unsafe/raw-pointer-field-access-error.stderr
similarity index 84%
rename from tests/ui/issues/issue-11004.stderr
rename to tests/ui/unsafe/raw-pointer-field-access-error.stderr
index 6d157c9..e9a205a 100644
--- a/tests/ui/issues/issue-11004.stderr
+++ b/tests/ui/unsafe/raw-pointer-field-access-error.stderr
@@ -1,5 +1,5 @@
error[E0609]: no field `x` on type `*mut A`
- --> $DIR/issue-11004.rs:7:21
+ --> $DIR/raw-pointer-field-access-error.rs:9:21
|
LL | let x : i32 = n.x;
| ^ unknown field
@@ -10,7 +10,7 @@
| ++ +
error[E0609]: no field `y` on type `*mut A`
- --> $DIR/issue-11004.rs:8:21
+ --> $DIR/raw-pointer-field-access-error.rs:10:21
|
LL | let y : f64 = n.y;
| ^ unknown field
diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr
index 2ad1de5..458a218 100644
--- a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr
+++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr
@@ -4,7 +4,7 @@
LL | unsf();
| ^^^^^^ call to unsafe function
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: consult the function's documentation for information on how to avoid undefined behavior
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/edition_2024_default.rs:11:1
diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.stderr
index 54447fb..0c40700 100644
--- a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.stderr
+++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.stderr
@@ -4,7 +4,7 @@
LL | unsf();
| ^^^^^^ call to unsafe function
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: consult the function's documentation for information on how to avoid undefined behavior
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/in_2024_compatibility.rs:6:1
diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/rfc-2585-unsafe_op_in_unsafe_fn.stderr
index 5465c22..3e43840 100644
--- a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/rfc-2585-unsafe_op_in_unsafe_fn.stderr
+++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/rfc-2585-unsafe_op_in_unsafe_fn.stderr
@@ -4,7 +4,7 @@
LL | unsf();
| ^^^^^^ call to unsafe function
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: consult the function's documentation for information on how to avoid undefined behavior
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:8:1
@@ -23,7 +23,7 @@
LL | *PTR;
| ^^^^ dereference of raw pointer
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error[E0133]: use of mutable static is unsafe and requires unsafe block
@@ -32,7 +32,7 @@
LL | VOID = ();
| ^^^^ use of mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
error: unnecessary `unsafe` block
@@ -53,7 +53,7 @@
LL | unsf();
| ^^^^^^ call to unsafe function
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: consult the function's documentation for information on how to avoid undefined behavior
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:23:1
@@ -73,7 +73,7 @@
LL | *PTR;
| ^^^^ dereference of raw pointer
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error[E0133]: use of mutable static is unsafe and requires unsafe block
@@ -82,7 +82,7 @@
LL | VOID = ();
| ^^^^ use of mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
error: unnecessary `unsafe` block
diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.stderr
index b48e607..f7dbf39 100644
--- a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.stderr
+++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.stderr
@@ -4,7 +4,7 @@
LL | unsf();
| ^^^^^^ call to unsafe function
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: consult the function's documentation for information on how to avoid undefined behavior
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/wrapping-unsafe-block-sugg.rs:11:1
@@ -23,7 +23,7 @@
LL | unsf();
| ^^^^^^ call to unsafe function
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: dereference of raw pointer is unsafe and requires unsafe block
@@ -32,7 +32,7 @@
LL | let y = *x;
| ^^ dereference of raw pointer
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/wrapping-unsafe-block-sugg.rs:23:1
@@ -46,7 +46,7 @@
LL | y + *x
| ^^ dereference of raw pointer
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error[E0133]: use of mutable static is unsafe and requires unsafe block
@@ -55,7 +55,7 @@
LL | let y = BAZ;
| ^^^ use of mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/wrapping-unsafe-block-sugg.rs:36:1
@@ -69,7 +69,7 @@
LL | y + BAZ
| ^^^ use of mutable static
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block
@@ -81,7 +81,7 @@
LL | unsafe_macro!();
| --------------- in this macro invocation
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: consult the function's documentation for information on how to avoid undefined behavior
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/wrapping-unsafe-block-sugg.rs:58:1
@@ -99,7 +99,7 @@
LL | unsafe_macro!();
| --------------- in this macro invocation
|
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
= note: consult the function's documentation for information on how to avoid undefined behavior
= note: this error originates in the macro `unsafe_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/issues/issue-41229-ref-str.rs b/tests/ui/unsized/unsized-function-argument-41229.rs
similarity index 61%
rename from tests/ui/issues/issue-41229-ref-str.rs
rename to tests/ui/unsized/unsized-function-argument-41229.rs
index fe5e6cd..9210431 100644
--- a/tests/ui/issues/issue-41229-ref-str.rs
+++ b/tests/ui/unsized/unsized-function-argument-41229.rs
@@ -2,3 +2,5 @@
//~^ ERROR the size for values of type
fn main() {}
+
+// https://github.com/rust-lang/rust/issues/41229
diff --git a/tests/ui/issues/issue-41229-ref-str.stderr b/tests/ui/unsized/unsized-function-argument-41229.stderr
similarity index 91%
rename from tests/ui/issues/issue-41229-ref-str.stderr
rename to tests/ui/unsized/unsized-function-argument-41229.stderr
index d4ef2a7..326e568 100644
--- a/tests/ui/issues/issue-41229-ref-str.stderr
+++ b/tests/ui/unsized/unsized-function-argument-41229.stderr
@@ -1,5 +1,5 @@
error[E0277]: the size for values of type `str` cannot be known at compilation time
- --> $DIR/issue-41229-ref-str.rs:1:23
+ --> $DIR/unsized-function-argument-41229.rs:1:23
|
LL | pub fn example(ref s: str) {}
| ^^^ doesn't have a size known at compile-time
diff --git a/tests/ui/use/use-after-move-implicity-coerced-object.stderr b/tests/ui/use/use-after-move-implicity-coerced-object.stderr
index 35ede21..defaeef 100644
--- a/tests/ui/use/use-after-move-implicity-coerced-object.stderr
+++ b/tests/ui/use/use-after-move-implicity-coerced-object.stderr
@@ -17,6 +17,14 @@
| ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this parameter takes ownership of the value
| |
| in this method
+note: if `Number` implemented `Clone`, you could clone the value
+ --> $DIR/use-after-move-implicity-coerced-object.rs:3:1
+ |
+LL | struct Number {
+ | ^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | l.push(n);
+ | - you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/hello_world/main.rs b/tests/ui/warnings/hello-world.rs
similarity index 100%
rename from tests/ui/hello_world/main.rs
rename to tests/ui/warnings/hello-world.rs
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
index a99728f..26872f6 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
@@ -5,7 +5,7 @@
| ^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
|
@@ -19,7 +19,7 @@
| ^^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | trait Bar<const M: dyn Foo<2>> {}
diff --git a/tests/ui/wf/wf-static-type.rs b/tests/ui/wf/wf-static-type.rs
index 1980c5d..1c35e1d 100644
--- a/tests/ui/wf/wf-static-type.rs
+++ b/tests/ui/wf/wf-static-type.rs
@@ -9,8 +9,6 @@ struct IsCopy<T:Copy> { t: T }
static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None };
//~^ ERROR E0277
-//~| ERROR E0277
-//~| ERROR E0277
fn main() { }
diff --git a/tests/ui/wf/wf-static-type.stderr b/tests/ui/wf/wf-static-type.stderr
index 53b90c6..2fa8ae0 100644
--- a/tests/ui/wf/wf-static-type.stderr
+++ b/tests/ui/wf/wf-static-type.stderr
@@ -16,43 +16,6 @@
LL | struct NotCopy;
|
-error[E0277]: the trait bound `NotCopy: Copy` is not satisfied
- --> $DIR/wf-static-type.rs:10:13
- |
-LL | static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None };
- | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`
- |
- = note: required for `Option<NotCopy>` to implement `Copy`
-note: required by a bound in `IsCopy`
- --> $DIR/wf-static-type.rs:7:17
- |
-LL | struct IsCopy<T:Copy> { t: T }
- | ^^^^ required by this bound in `IsCopy`
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: consider annotating `NotCopy` with `#[derive(Copy)]`
- |
-LL + #[derive(Copy)]
-LL | struct NotCopy;
- |
-
-error[E0277]: the trait bound `NotCopy: Copy` is not satisfied
- --> $DIR/wf-static-type.rs:10:51
- |
-LL | static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None };
- | ^^^^ the trait `Copy` is not implemented for `NotCopy`
- |
- = note: required for `Option<NotCopy>` to implement `Copy`
-note: required by a bound in `IsCopy`
- --> $DIR/wf-static-type.rs:7:17
- |
-LL | struct IsCopy<T:Copy> { t: T }
- | ^^^^ required by this bound in `IsCopy`
-help: consider annotating `NotCopy` with `#[derive(Copy)]`
- |
-LL + #[derive(Copy)]
-LL | struct NotCopy;
- |
-
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.
diff --git a/triagebot.toml b/triagebot.toml
index 5b522a6..e1b4983 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -28,6 +28,7 @@
"llvm-*",
"needs-fcp",
"relnotes",
+ "release-blog-post",
"requires-*",
"regression-*",
"rla-*",
@@ -49,6 +50,21 @@
# Those labels are added when PR author requests a review from an assignee
add_labels = ["S-waiting-on-review"]
+# [backport.*] sections autonominate pull requests for a backport
+# see: https://forge.rust-lang.org/triagebot/backport.html
+
+[backport.t-compiler-beta-backport]
+# The pull request MUST have one of these labels
+required-pr-labels = ["T-compiler"]
+# The regression MUST have this label
+required-issue-label = "regression-from-stable-to-beta"
+# if the above conditions matches, the PR will receive these labels
+add-labels = ["beta-nominated"]
+
+[backport.t-compiler-stable-backport]
+required-pr-labels = ["T-compiler"]
+required-issue-label = "regression-from-stable-to-stable"
+add-labels = ["stable-nominated"]
# ------------------------------------------------------------------------------
# Ping groups
@@ -1096,7 +1112,7 @@
message = "The list of allowed third-party dependencies may have been modified! You must ensure that any new dependencies have compatible licenses before merging."
cc = ["@davidtwco", "@wesleywiser"]
-[mentions."src/tools/tidy/src/ext_tool_checks.rs"]
+[mentions."src/tools/tidy/src/extra_checks"]
message = "`tidy` extra checks were modified."
cc = ["@lolbinarycat"]