From cdeca5cbd323841285d41af33825864b5764642e Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 30 Apr 2025 20:51:22 +0200 Subject: [PATCH 001/363] fix Zip unsoundness (again) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some history: The Zip TrustedRandomAccess specialization has tried to emulate the side-effects of the naive implementation for a long time, including backwards iteration. 82292¹ tried to fix unsoundness (82291¹) in that side-effect-preservation code, but this introduced some panic-safety unsoundness (86443¹), but the fix 86452¹ didn't fix it for nested Zip iterators (137255¹). Rather than piling yet another fix ontop of this heap of fixes this PR reduces the number of cases in which side-effects will be preserved; the necessary API guarantee change was approved in 83791¹ but we haven't made use of that so far. ¹ see merge commit for linkfied issues. --- library/core/src/iter/adapters/zip.rs | 74 +++++++------- .../coretests/tests/iter/adapters/cloned.rs | 3 +- library/coretests/tests/iter/adapters/zip.rs | 97 ++++++++++++------- 3 files changed, 99 insertions(+), 75 deletions(-) diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 8090c98e7edb..c5e199c30821 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -18,7 +18,6 @@ pub struct Zip { // index, len and a_len are only used by the specialized version of zip index: usize, len: usize, - a_len: usize, } impl Zip { pub(in crate::iter) fn new(a: A, b: B) -> Zip { @@ -158,7 +157,6 @@ macro_rules! zip_impl_general_defaults { b, index: 0, // unused len: 0, // unused - a_len: 0, // unused } } @@ -299,9 +297,8 @@ where B: TrustedRandomAccess + Iterator, { fn new(a: A, b: B) -> Self { - let a_len = a.size(); - let len = cmp::min(a_len, b.size()); - Zip { a, b, index: 0, len, a_len } + let len = cmp::min(a.size(), b.size()); + Zip { a, b, index: 0, len } } #[inline] @@ -315,17 +312,6 @@ where unsafe { Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i))) } - } else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a_len { - let i = self.index; - // as above, increment before executing code that may panic - self.index += 1; - self.len += 1; - // match the base implementation's potential side effects - // SAFETY: we just checked that `i` < `self.a.len()` - unsafe { - self.a.__iterator_get_unchecked(i); - } - None } else { None } @@ -371,36 +357,42 @@ where A: DoubleEndedIterator + ExactSizeIterator, B: DoubleEndedIterator + ExactSizeIterator, { - if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT { - let sz_a = self.a.size(); - let sz_b = self.b.size(); - // Adjust a, b to equal length, make sure that only the first call - // of `next_back` does this, otherwise we will break the restriction - // on calls to `self.next_back()` after calling `get_unchecked()`. - if sz_a != sz_b { + // No effects when the iterator is exhausted, to reduce the number of + // cases the unsafe code has to handle. + // See #137255 for a case where where too many epicycles lead to unsoundness. + if self.index < self.len { + let old_len = self.len; + + // since get_unchecked and the side-effecting code can execute user code + // which can panic we decrement the counter beforehand + // so that the same index won't be accessed twice, as required by TrustedRandomAccess. + // Additionally this will ensure that the side-effects code won't run a second time. + self.len -= 1; + + // Adjust a, b to equal length if we're iterating backwards. + if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT { + // note if some forward-iteration already happened then these aren't the real + // remaining lengths of the inner iterators, so we have to relate them to + // Zip's internal length-tracking. let sz_a = self.a.size(); - if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len { - for _ in 0..sz_a - self.len { - // since next_back() may panic we increment the counters beforehand - // to keep Zip's state in sync with the underlying iterator source - self.a_len -= 1; - self.a.next_back(); - } - debug_assert_eq!(self.a_len, self.len); - } let sz_b = self.b.size(); - if B::MAY_HAVE_SIDE_EFFECT && sz_b > self.len { - for _ in 0..sz_b - self.len { - self.b.next_back(); + // This condition can and must only be true on the first `next_back` call, + // otherwise we will break the restriction on calls to `self.next_back()` + // after calling `get_unchecked()`. + if sz_a != sz_b && (old_len == sz_a || old_len == sz_b) { + if A::MAY_HAVE_SIDE_EFFECT && sz_a > old_len { + for _ in 0..sz_a - old_len { + self.a.next_back(); + } } + if B::MAY_HAVE_SIDE_EFFECT && sz_b > old_len { + for _ in 0..sz_b - old_len { + self.b.next_back(); + } + } + debug_assert_eq!(self.a.size(), self.b.size()); } } - } - if self.index < self.len { - // since get_unchecked executes code which can panic we increment the counters beforehand - // so that the same index won't be accessed twice, as required by TrustedRandomAccess - self.len -= 1; - self.a_len -= 1; let i = self.len; // SAFETY: `i` is smaller than the previous value of `self.len`, // which is also smaller than or equal to `self.a.len()` and `self.b.len()` diff --git a/library/coretests/tests/iter/adapters/cloned.rs b/library/coretests/tests/iter/adapters/cloned.rs index 78babb7feab1..0a3dd1ce46e8 100644 --- a/library/coretests/tests/iter/adapters/cloned.rs +++ b/library/coretests/tests/iter/adapters/cloned.rs @@ -31,7 +31,8 @@ fn test_cloned_side_effects() { .zip(&[1]); for _ in iter {} } - assert_eq!(count, 2); + // Zip documentation provides some leeway about side-effects + assert!([1, 2].iter().any(|v| *v == count)); } #[test] diff --git a/library/coretests/tests/iter/adapters/zip.rs b/library/coretests/tests/iter/adapters/zip.rs index 70392dca0fa1..b00433c70fe9 100644 --- a/library/coretests/tests/iter/adapters/zip.rs +++ b/library/coretests/tests/iter/adapters/zip.rs @@ -107,9 +107,19 @@ fn test_zip_next_back_side_effects_exhausted() { iter.next(); iter.next(); iter.next(); - iter.next(); + assert_eq!(iter.next(), None); assert_eq!(iter.next_back(), None); - assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); + + assert!(a.starts_with(&[1, 2, 3])); + let a_len = a.len(); + // Tail-side-effects of forward-iteration are "at most one" per next(). + // And for reverse iteration we don't guarantee much either. + // But we can put some bounds on the possible behaviors. + assert!(a_len <= 6); + assert!(a_len >= 3); + a.sort(); + assert_eq!(a, &[1, 2, 3, 4, 5, 6][..a.len()]); + assert_eq!(b, vec![200, 300, 400]); } @@ -120,7 +130,8 @@ fn test_zip_cloned_sideffectful() { for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} - assert_eq!(&xs, &[1, 1, 1, 0][..]); + // Zip documentation permits either case. + assert!([&[1, 1, 1, 0], &[1, 1, 0, 0]].iter().any(|v| &xs == *v)); assert_eq!(&ys, &[1, 1][..]); let xs = [CountClone::new(), CountClone::new()]; @@ -139,7 +150,8 @@ fn test_zip_map_sideffectful() { for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} - assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); + // Zip documentation permits either case. + assert!([&[1, 1, 1, 1, 1, 0], &[1, 1, 1, 1, 0, 0]].iter().any(|v| &xs == *v)); assert_eq!(&ys, &[1, 1, 1, 1]); let mut xs = [0; 4]; @@ -168,7 +180,8 @@ fn test_zip_map_rev_sideffectful() { { let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); - (&mut it).take(5).count(); + // the current impl only trims the tails if the iterator isn't exhausted + (&mut it).take(3).count(); it.next_back(); } assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]); @@ -211,9 +224,18 @@ fn test_zip_nth_back_side_effects_exhausted() { iter.next(); iter.next(); iter.next(); - iter.next(); + assert_eq!(iter.next(), None); assert_eq!(iter.nth_back(0), None); - assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); + assert!(a.starts_with(&[1, 2, 3])); + let a_len = a.len(); + // Tail-side-effects of forward-iteration are "at most one" per next(). + // And for reverse iteration we don't guarantee much either. + // But we can put some bounds on the possible behaviors. + assert!(a_len <= 6); + assert!(a_len >= 3); + a.sort(); + assert_eq!(a, &[1, 2, 3, 4, 5, 6][..a.len()]); + assert_eq!(b, vec![200, 300, 400]); } @@ -237,32 +259,6 @@ fn test_zip_trusted_random_access_composition() { assert_eq!(z2.next().unwrap(), ((1, 1), 1)); } -#[test] -#[cfg(panic = "unwind")] -fn test_zip_trusted_random_access_next_back_drop() { - use std::panic::{AssertUnwindSafe, catch_unwind}; - - let mut counter = 0; - - let it = [42].iter().map(|e| { - let c = counter; - counter += 1; - if c == 0 { - panic!("bomb"); - } - - e - }); - let it2 = [(); 0].iter(); - let mut zip = it.zip(it2); - catch_unwind(AssertUnwindSafe(|| { - zip.next_back(); - })) - .unwrap_err(); - assert!(zip.next().is_none()); - assert_eq!(counter, 1); -} - #[test] fn test_double_ended_zip() { let xs = [1, 2, 3, 4, 5, 6]; @@ -275,6 +271,41 @@ fn test_double_ended_zip() { assert_eq!(it.next(), None); } +#[test] +#[cfg(panic = "unwind")] +fn test_nested_zip_panic_safety() { + use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; + use std::sync::atomic::{AtomicUsize, Ordering}; + + let mut panic = true; + let witness = [8, 9, 10, 11, 12].map(|i| (i, AtomicUsize::new(0))); + let a = witness.as_slice().iter().map(|e| { + e.1.fetch_add(1, Ordering::Relaxed); + if panic { + panic = false; + resume_unwind(Box::new(())) + } + e.0 + }); + let b = [1, 2, 3, 4].as_slice().iter().copied(); + let c = [5, 6, 7].as_slice().iter().copied(); + let ab = zip(a, b); + + let mut abc = zip(ab, c); + + assert_eq!(abc.len(), 3); + catch_unwind(AssertUnwindSafe(|| abc.next_back())).ok(); + assert_eq!(abc.len(), 2); + assert_eq!(abc.next(), Some(((8, 1), 5))); + assert_eq!(abc.next_back(), Some(((9, 2), 6))); + for (i, (_, w)) in witness.iter().enumerate() { + let v = w.load(Ordering::Relaxed); + assert!(v <= 1, "expected idx {i} to be visited at most once, actual: {v}"); + } + // backwards trimming panicked and should only run once, so this one won't be visited. + assert_eq!(witness[3].1.load(Ordering::Relaxed), 0); +} + #[test] fn test_issue_82282() { fn overflowed_zip(arr: &[i32]) -> impl Iterator { From 61c2c1211fc0591ff000fcb742f352f4e319ea82 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Thu, 5 Jun 2025 01:25:19 +0200 Subject: [PATCH 002/363] add comments to Zip unsoundness regression test --- library/coretests/tests/iter/adapters/zip.rs | 26 ++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/library/coretests/tests/iter/adapters/zip.rs b/library/coretests/tests/iter/adapters/zip.rs index b00433c70fe9..83279380175e 100644 --- a/library/coretests/tests/iter/adapters/zip.rs +++ b/library/coretests/tests/iter/adapters/zip.rs @@ -273,11 +273,18 @@ fn test_double_ended_zip() { #[test] #[cfg(panic = "unwind")] +/// Regresion test for #137255 +/// A previous implementation of Zip TrustedRandomAccess specializations tried to do a lot of work +/// to preserve side-effects of equalizing the iterator lengths during backwards iteration. +/// This lead to several cases of unsoundness, twice due to being left in an inconsistent state +/// after panics. +/// The new implementation does not try as hard, but we still need panic-safety. fn test_nested_zip_panic_safety() { use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; use std::sync::atomic::{AtomicUsize, Ordering}; let mut panic = true; + // keeps track of how often element get visited, must be at most once each let witness = [8, 9, 10, 11, 12].map(|i| (i, AtomicUsize::new(0))); let a = witness.as_slice().iter().map(|e| { e.1.fetch_add(1, Ordering::Relaxed); @@ -287,22 +294,37 @@ fn test_nested_zip_panic_safety() { } e.0 }); + // shorter than `a`, so `a` will get trimmed let b = [1, 2, 3, 4].as_slice().iter().copied(); + // shorter still, so `ab` will get trimmed.` let c = [5, 6, 7].as_slice().iter().copied(); - let ab = zip(a, b); + // This will panic during backwards trimming. + let ab = zip(a, b); + // This being Zip + TrustedRandomAccess means it will only call `next_back`` + // during trimming and otherwise do calls `__iterator_get_unchecked` on `ab`. let mut abc = zip(ab, c); assert_eq!(abc.len(), 3); + // This will first trigger backwards trimming before it would normally obtain the + // actual element if it weren't for the panic. + // This used to corrupt the internal state of `abc`, which then lead to + // TrustedRandomAccess safety contract violations in calls to `ab`, + // which ultimately lead to UB. catch_unwind(AssertUnwindSafe(|| abc.next_back())).ok(); + // check for sane outward behavior after the panic, which indicates a sane internal state. + // Technically these outcomes are not required because a panic frees us from correctness obligations. assert_eq!(abc.len(), 2); assert_eq!(abc.next(), Some(((8, 1), 5))); assert_eq!(abc.next_back(), Some(((9, 2), 6))); for (i, (_, w)) in witness.iter().enumerate() { let v = w.load(Ordering::Relaxed); + // required by TRA contract assert!(v <= 1, "expected idx {i} to be visited at most once, actual: {v}"); } - // backwards trimming panicked and should only run once, so this one won't be visited. + // Trimming panicked and should only run once, so this one won't be visited. + // Implementation detail, but not trying to run it again is what keeps + // things simple. assert_eq!(witness[3].1.load(Ordering::Relaxed), 0); } From b9382e9ef1649222561b9031b07782fa07284467 Mon Sep 17 00:00:00 2001 From: sayantn Date: Thu, 5 Jun 2025 20:41:41 +0530 Subject: [PATCH 003/363] Implement `simd_round_ties_even` for miri, cg_clif and cg_gcc --- src/intrinsic/simd.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 82ef0d0b13a4..18ba1ca3d77e 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -779,6 +779,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( sym::simd_fsin => "sin", sym::simd_fsqrt => "sqrt", sym::simd_round => "round", + sym::simd_round_ties_even => "rint", sym::simd_trunc => "trunc", _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }), }; @@ -826,6 +827,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( | sym::simd_fsin | sym::simd_fsqrt | sym::simd_round + | sym::simd_round_ties_even | sym::simd_trunc ) { return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args); From 89e5db8fea71e1055437454285d1c128576ec9b9 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 24 Dec 2023 01:04:16 +0000 Subject: [PATCH 004/363] Only inherit local hash for paths. --- compiler/rustc_hir/src/definitions.rs | 16 +++++++++++++--- tests/mir-opt/inline/cycle.rs | 2 +- tests/ui/symbol-names/basic.legacy.stderr | 4 ++-- tests/ui/symbol-names/issue-60925.legacy.stderr | 4 ++-- tests/ui/thir-print/thir-tree-match.stdout | 8 ++++---- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index f93b9e5af534..d9fea542100e 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -140,7 +140,9 @@ impl DefKey { pub(crate) fn compute_stable_hash(&self, parent: DefPathHash) -> DefPathHash { let mut hasher = StableHasher::new(); - parent.hash(&mut hasher); + // The new path is in the same crate as `parent`, and will contain the stable_crate_id. + // Therefore, we only need to include information of the parent's local hash. + parent.local_hash().hash(&mut hasher); let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data; @@ -361,8 +363,16 @@ impl Definitions { }, }; - let parent_hash = DefPathHash::new(stable_crate_id, Hash64::ZERO); - let def_path_hash = key.compute_stable_hash(parent_hash); + // We want *both* halves of a DefPathHash to depend on the crate-id of the defining crate. + // The crate-id can be more easily changed than the DefPath of an item, so, in the case of + // a crate-local DefPathHash collision, the user can simply "roll the dice again" for all + // DefPathHashes in the crate by changing the crate disambiguator (e.g. via bumping the + // crate's version number). + // + // Children paths will only hash the local portion, and still inherit the change to the + // root hash. + let def_path_hash = + DefPathHash::new(stable_crate_id, Hash64::new(stable_crate_id.as_u64())); // Create the root definition. let mut table = DefPathTable::new(stable_crate_id); diff --git a/tests/mir-opt/inline/cycle.rs b/tests/mir-opt/inline/cycle.rs index 383d0796a884..6e0f45bb3e9f 100644 --- a/tests/mir-opt/inline/cycle.rs +++ b/tests/mir-opt/inline/cycle.rs @@ -13,7 +13,7 @@ fn f(g: impl Fn()) { #[inline(always)] fn g() { // CHECK-LABEL: fn g( - // CHECK-NOT: (inlined f::) + // CHECK-NOT: inlined f(main); } diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr index 167262dcf06b..a028f4331725 100644 --- a/tests/ui/symbol-names/basic.legacy.stderr +++ b/tests/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17hc88b9d80a69d119aE) +error: symbol-name(_ZN5basic4main17h1dddcfd03744167fE) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::hc88b9d80a69d119a) +error: demangling(basic::main::h1dddcfd03744167f) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr index 4e17bdc45777..14cbd877d9f8 100644 --- a/tests/ui/symbol-names/issue-60925.legacy.stderr +++ b/tests/ui/symbol-names/issue-60925.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hbddb77d6f71afb32E) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h4b3099ec5dc5d306E) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo::foo::hbddb77d6f71afb32) +error: demangling(issue_60925::foo::Foo::foo::h4b3099ec5dc5d306) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 910582ae4d9e..2049c531abd9 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -94,7 +94,7 @@ body: did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 } args: [] variant_index: 0 subpatterns: [ @@ -108,7 +108,7 @@ body: did: DefId(0:3 ~ thir_tree_match[fcf8]::Bar) variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[fcf8]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[fcf8]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], tainted: None, flags: }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[fcf8]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[fcf8]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], tainted: None, flags: }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[fcf8]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[fcf8]::Bar::Third::{constructor#0}))), name: "Third", discr: Relative(2), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 10333377570083945360 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 7908585036048874241 } args: [] variant_index: 0 subpatterns: [] @@ -156,7 +156,7 @@ body: did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 } args: [] variant_index: 0 subpatterns: [ @@ -208,7 +208,7 @@ body: did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 } args: [] variant_index: 1 subpatterns: [] From 1b4a19d4ac514bd50a98b28421a9149159e7c2f4 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 22 Jun 2025 16:03:28 +0000 Subject: [PATCH 005/363] Hash less while hashing def-ids. --- compiler/rustc_span/src/def_id.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 641bac88ad02..77f01548bca2 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -110,6 +110,7 @@ impl DefPathHash { /// Builds a new [DefPathHash] with the given [StableCrateId] and /// `local_hash`, where `local_hash` must be unique within its crate. + #[inline] pub fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> DefPathHash { DefPathHash(Fingerprint::new(stable_crate_id.0, local_hash)) } @@ -404,21 +405,21 @@ rustc_data_structures::define_id_collections!( impl HashStable for DefId { #[inline] fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.to_stable_hash_key(hcx).hash_stable(hcx, hasher); + hcx.def_path_hash(*self).hash_stable(hcx, hasher); } } impl HashStable for LocalDefId { #[inline] fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.to_stable_hash_key(hcx).hash_stable(hcx, hasher); + hcx.def_path_hash(self.to_def_id()).local_hash().hash_stable(hcx, hasher); } } impl HashStable for CrateNum { #[inline] fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.to_stable_hash_key(hcx).hash_stable(hcx, hasher); + self.as_def_id().to_stable_hash_key(hcx).stable_crate_id().hash_stable(hcx, hasher); } } @@ -464,30 +465,36 @@ macro_rules! typed_def_id { pub struct $Name(DefId); impl $Name { + #[inline] pub const fn new_unchecked(def_id: DefId) -> Self { Self(def_id) } + #[inline] pub fn to_def_id(self) -> DefId { self.into() } + #[inline] pub fn is_local(self) -> bool { self.0.is_local() } + #[inline] pub fn as_local(self) -> Option<$LocalName> { self.0.as_local().map($LocalName::new_unchecked) } } impl From<$LocalName> for $Name { + #[inline] fn from(local: $LocalName) -> Self { Self(local.0.to_def_id()) } } impl From<$Name> for DefId { + #[inline] fn from(typed: $Name) -> Self { typed.0 } @@ -500,26 +507,31 @@ macro_rules! typed_def_id { impl !PartialOrd for $LocalName {} impl $LocalName { + #[inline] pub const fn new_unchecked(def_id: LocalDefId) -> Self { Self(def_id) } + #[inline] pub fn to_def_id(self) -> DefId { self.0.into() } + #[inline] pub fn to_local_def_id(self) -> LocalDefId { self.0 } } impl From<$LocalName> for LocalDefId { + #[inline] fn from(typed: $LocalName) -> Self { typed.0 } } impl From<$LocalName> for DefId { + #[inline] fn from(typed: $LocalName) -> Self { typed.0.into() } From aa460dc24751c038a6598a8adff7914065025b93 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Tue, 10 Jun 2025 19:25:36 +0200 Subject: [PATCH 006/363] tests: Add `RUST_BACKTRACE` and `-Cpanic` revisions to `panic-main.rs` test --- tests/ui/panics/panic-main.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/ui/panics/panic-main.rs b/tests/ui/panics/panic-main.rs index 3876dbb37c37..bf79de78a579 100644 --- a/tests/ui/panics/panic-main.rs +++ b/tests/ui/panics/panic-main.rs @@ -1,3 +1,26 @@ +//@ revisions: default abort-zero abort-one abort-full unwind-zero unwind-one unwind-full + +//@[abort-zero] compile-flags: -Cpanic=abort +//@[abort-zero] no-prefer-dynamic +//@[abort-zero] exec-env:RUST_BACKTRACE=0 + +//@[abort-one] compile-flags: -Cpanic=abort +//@[abort-one] no-prefer-dynamic +//@[abort-one] exec-env:RUST_BACKTRACE=1 + +//@[abort-full] compile-flags: -Cpanic=abort +//@[abort-full] no-prefer-dynamic +//@[abort-full] exec-env:RUST_BACKTRACE=full + +//@[unwind-zero] compile-flags: -Cpanic=unwind +//@[unwind-zero] exec-env:RUST_BACKTRACE=0 + +//@[unwind-one] compile-flags: -Cpanic=unwind +//@[unwind-one] exec-env:RUST_BACKTRACE=1 + +//@[unwind-full] compile-flags: -Cpanic=unwind +//@[unwind-full] exec-env:RUST_BACKTRACE=full + //@ run-fail //@ error-pattern:moop //@ needs-subprocess From 068f3ac20b4074b523e80c07b3bf139ced9374dd Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 24 Jun 2025 04:05:27 +0000 Subject: [PATCH 007/363] Update test. --- compiler/rustc_hir/src/tests.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs index 18c2bfdac8ce..3b797c1f1038 100644 --- a/compiler/rustc_hir/src/tests.rs +++ b/compiler/rustc_hir/src/tests.rs @@ -28,7 +28,8 @@ fn def_path_hash_depends_on_crate_id() { assert_ne!(h0.local_hash(), h1.local_hash()); fn mk_test_hash(stable_crate_id: StableCrateId) -> DefPathHash { - let parent_hash = DefPathHash::new(stable_crate_id, Hash64::ZERO); + let parent_hash = + DefPathHash::new(stable_crate_id, Hash64::new(stable_crate_id.as_u64())); let key = DefKey { parent: None, From 56af6625c8a1b5815b5628425c145d8e43e1ec26 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 28 Jun 2025 23:37:08 +0200 Subject: [PATCH 008/363] Merge commit 'b7091eca6d8eb0fe88b58cc9a7aec405d8de5b85' into subtree-update_cg_gcc_2025-06-28 --- build_system/src/abi_test.rs | 65 +++++++++++++++++++ build_system/src/main.rs | 8 ++- build_system/src/test.rs | 9 +-- ...001-Pin-compiler_builtins-to-0.1.160.patch | 39 ----------- rust-toolchain | 2 +- src/builder.rs | 65 ++++++++++++------- src/common.rs | 13 ---- src/context.rs | 33 +++++----- src/debuginfo.rs | 6 +- src/declare.rs | 5 +- src/intrinsic/mod.rs | 21 +++--- tests/failing-ui-tests.txt | 1 + 12 files changed, 150 insertions(+), 117 deletions(-) create mode 100644 build_system/src/abi_test.rs delete mode 100644 patches/0001-Pin-compiler_builtins-to-0.1.160.patch diff --git a/build_system/src/abi_test.rs b/build_system/src/abi_test.rs new file mode 100644 index 000000000000..3c1531be27a5 --- /dev/null +++ b/build_system/src/abi_test.rs @@ -0,0 +1,65 @@ +use std::ffi::OsStr; +use std::path::Path; + +use crate::utils::run_command_with_output; + +fn show_usage() { + println!( + r#" +`abi-test` command help: + --help : Show this help"# + ); +} + +pub fn run() -> Result<(), String> { + let mut args = std::env::args().skip(2); + // FractalFir: In the future, I'd like to add some more subcommands / options. + // So, this loop ought to stay for that purpose. It should also stay as a while loop(to parse args) + #[allow(clippy::never_loop, clippy::while_let_on_iterator)] + while let Some(arg) = args.next() { + match arg.as_str() { + "--help" => { + show_usage(); + return Ok(()); + } + _ => return Err(format!("Unknown option {arg:?}")), + } + } + // Ensure that we have a cloned version of abi-cafe on hand. + crate::utils::git_clone( + "https://github.com/Gankra/abi-cafe.git", + Some("clones/abi-cafe".as_ref()), + true, + ) + .map_err(|err| (format!("Git clone failed with message: {err:?}!")))?; + // Configure abi-cafe to use the exact same rustc version we use - this is crucial. + // Otherwise, the concept of ABI compatibility becomes meanignless. + std::fs::copy("rust-toolchain", "clones/abi-cafe/rust-toolchain") + .expect("Could not copy toolchain configs!"); + // Get the backend path. + // We will use the *debug* build of the backend - it has more checks enabled. + let backend_path = std::path::absolute("target/debug/librustc_codegen_gcc.so").unwrap(); + let backend_arg = format!("--add-rustc-codegen-backend=cg_gcc:{}", backend_path.display()); + // Run ABI cafe using cargo. + let cmd: &[&dyn AsRef] = &[ + &"cargo", + &"run", + &"--release", + &"--", + &backend_arg, + // Test rust-LLVM to Rust-GCC calls + &"--pairs", + &"rustc_calls_cg_gcc", + &"--pairs", + &"cg_gcc_calls_rustc", + // Test Rust-GCC to C calls + &"--pairs", + &"cg_gcc_calls_c", + &"--pairs", + &"c_calls_cg_gcc", + ]; + // Run ABI cafe. + run_command_with_output(cmd, Some(Path::new("clones/abi-cafe")))?; + + Ok(()) +} diff --git a/build_system/src/main.rs b/build_system/src/main.rs index 078a4726ba80..ae975c94fff2 100644 --- a/build_system/src/main.rs +++ b/build_system/src/main.rs @@ -1,5 +1,6 @@ use std::{env, process}; +mod abi_test; mod build; mod clean; mod clone_gcc; @@ -12,7 +13,6 @@ mod rust_tools; mod rustc_info; mod test; mod utils; - const BUILD_DIR: &str = "build"; macro_rules! arg_error { @@ -44,7 +44,8 @@ Commands: info : Displays information about the build environment and project configuration. clone-gcc : Clones the GCC compiler from a specified source. fmt : Runs rustfmt - fuzz : Fuzzes `cg_gcc` using rustlantis" + fuzz : Fuzzes `cg_gcc` using rustlantis + abi-test : Runs the abi-cafe test suite on the codegen, checking for ABI compatibility with LLVM" ); } @@ -59,6 +60,7 @@ pub enum Command { Info, Fmt, Fuzz, + AbiTest, } fn main() { @@ -77,6 +79,7 @@ fn main() { Some("test") => Command::Test, Some("info") => Command::Info, Some("clone-gcc") => Command::CloneGcc, + Some("abi-test") => Command::AbiTest, Some("fmt") => Command::Fmt, Some("fuzz") => Command::Fuzz, Some("--help") => { @@ -102,6 +105,7 @@ fn main() { Command::CloneGcc => clone_gcc::run(), Command::Fmt => fmt::run(), Command::Fuzz => fuzz::run(), + Command::AbiTest => abi_test::run(), } { eprintln!("Command failed to run: {e}"); process::exit(1); diff --git a/build_system/src/test.rs b/build_system/src/test.rs index bcaab0fb526b..f1f31f83ca24 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -738,14 +738,7 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> { let path = get_sysroot_dir().join("sysroot_src/library/coretests"); let _ = remove_dir_all(path.join("target")); // TODO(antoyo): run in release mode when we fix the failures. - // TODO(antoyo): remove the --skip f16::test_total_cmp when this issue is fixed: - // https://github.com/rust-lang/rust/issues/141503 - run_cargo_command( - &[&"test", &"--", &"--skip", &"f16::test_total_cmp"], - Some(&path), - env, - args, - )?; + run_cargo_command(&[&"test"], Some(&path), env, args)?; Ok(()) } diff --git a/patches/0001-Pin-compiler_builtins-to-0.1.160.patch b/patches/0001-Pin-compiler_builtins-to-0.1.160.patch deleted file mode 100644 index 39266e081ede..000000000000 --- a/patches/0001-Pin-compiler_builtins-to-0.1.160.patch +++ /dev/null @@ -1,39 +0,0 @@ -From cdb3d407740e4f15c3746051f8ba89b8e74e99d3 Mon Sep 17 00:00:00 2001 -From: None -Date: Fri, 30 May 2025 13:46:22 -0400 -Subject: [PATCH] Pin compiler_builtins to 0.1.160 - ---- - library/alloc/Cargo.toml | 2 +- - library/std/Cargo.toml | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml -index 9d0d957..365c9dc 100644 ---- a/library/alloc/Cargo.toml -+++ b/library/alloc/Cargo.toml -@@ -16,7 +16,7 @@ bench = false - - [dependencies] - core = { path = "../core", public = true } --compiler_builtins = { version = "=0.1.159", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "=0.1.160", features = ['rustc-dep-of-std'] } - - [features] - compiler-builtins-mem = ['compiler_builtins/mem'] -diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml -index 4ff4895..31371f0 100644 ---- a/library/std/Cargo.toml -+++ b/library/std/Cargo.toml -@@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } - panic_unwind = { path = "../panic_unwind", optional = true } - panic_abort = { path = "../panic_abort" } - core = { path = "../core", public = true } --compiler_builtins = { version = "=0.1.159" } -+compiler_builtins = { version = "=0.1.160" } - unwind = { path = "../unwind" } - hashbrown = { version = "0.15", default-features = false, features = [ - 'rustc-dep-of-std', --- -2.49.0 - diff --git a/rust-toolchain b/rust-toolchain index bafe497a2a2a..8be204c15810 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-05-21" +channel = "nightly-2025-06-02" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/src/builder.rs b/src/builder.rs index 7852aebe0c23..a4454cd9c734 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -520,8 +520,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.block } - fn append_block(cx: &'a CodegenCx<'gcc, 'tcx>, func: RValue<'gcc>, name: &str) -> Block<'gcc> { - let func = cx.rvalue_as_function(func); + fn append_block(_: &'a CodegenCx<'gcc, 'tcx>, func: Function<'gcc>, name: &str) -> Block<'gcc> { func.new_block(name) } @@ -782,6 +781,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { return self.context.new_call(self.location, fmod, &[a, b]); } TypeKind::FP128 => { + // TODO(antoyo): use get_simple_function_f128_2args. let f128_type = self.type_f128(); let fmodf128 = self.context.new_function( None, @@ -938,22 +938,36 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { let block = self.llbb(); let function = block.get_function(); + // NOTE(FractalFir): In some cases, we *should* skip the call to get_aligned. + // For example, calling `get_aligned` on a i8 is pointless(since it can only be 1 aligned) + // Calling get_aligned on a `u128`/`i128` causes the attribute to become "stacked" + // + // From GCCs perspective: + // __int128_t __attribute__((aligned(16))) __attribute__((aligned(16))) + // and: + // __int128_t __attribute__((aligned(16))) + // are 2 distinct, incompatible types. + // + // So, we skip the call to `get_aligned` in such a case. *Ideally*, we could do this for all the types, + // but the GCC APIs to facilitate this just aren't quite there yet. + + // This checks that we only skip `get_aligned` on 128 bit ints if they have the correct alignment. + // Otherwise, this may be an under-aligned load, so we will still call get_aligned. + let mut can_skip_align = (pointee_ty == self.cx.u128_type + || pointee_ty == self.cx.i128_type) + && align == self.int128_align; + // We can skip the call to `get_aligned` for byte-sized types with alignment of 1. + can_skip_align = can_skip_align + || (pointee_ty == self.cx.u8_type || pointee_ty == self.cx.i8_type) + && align.bytes() == 1; + // Skip the call to `get_aligned` when possible. + let aligned_type = + if can_skip_align { pointee_ty } else { pointee_ty.get_aligned(align.bytes()) }; + + let ptr = self.context.new_cast(self.location, ptr, aligned_type.make_pointer()); // NOTE: instead of returning the dereference here, we have to assign it to a variable in // the current basic block. Otherwise, it could be used in another basic block, causing a // dereference after a drop, for instance. - // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type. - // Ideally, we shouldn't need to do this check. - // FractalFir: the `align == self.int128_align` check ensures we *do* call `get_aligned` if - // the alignment of a `u128`/`i128` is not the one mandated by the ABI. This ensures we handle - // under-aligned loads correctly. - let aligned_type = if (pointee_ty == self.cx.u128_type || pointee_ty == self.cx.i128_type) - && align == self.int128_align - { - pointee_ty - } else { - pointee_ty.get_aligned(align.bytes()) - }; - let ptr = self.context.new_cast(self.location, ptr, aligned_type.make_pointer()); let deref = ptr.dereference(self.location).to_rvalue(); let loaded_value = function.new_local( self.location, @@ -1105,7 +1119,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo) } - fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { + fn store(&mut self, mut val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { + if self.structs_as_pointer.borrow().contains(&val) { + // NOTE: hack to workaround a limitation of the rustc API: see comment on + // CodegenCx.structs_as_pointer + val = val.dereference(self.location).to_rvalue(); + } + self.store_with_flags(val, ptr, align, MemFlags::empty()) } @@ -1551,16 +1571,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { aggregate_value } - fn set_personality_fn(&mut self, _personality: RValue<'gcc>) { + fn set_personality_fn(&mut self, _personality: Function<'gcc>) { #[cfg(feature = "master")] - { - let personality = self.rvalue_as_function(_personality); - self.current_func().set_personality_function(personality); - } + self.current_func().set_personality_function(_personality); } #[cfg(feature = "master")] - fn cleanup_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { + fn cleanup_landing_pad(&mut self, pers_fn: Function<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { self.set_personality_fn(pers_fn); // NOTE: insert the current block in a variable so that a later call to invoke knows to @@ -1581,7 +1598,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } #[cfg(not(feature = "master"))] - fn cleanup_landing_pad(&mut self, _pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { + fn cleanup_landing_pad(&mut self, _pers_fn: Function<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { let value1 = self .current_func() .new_local(self.location, self.u8_type.make_pointer(), "landing_pad0") @@ -1591,7 +1608,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { (value1, value2) } - fn filter_landing_pad(&mut self, pers_fn: RValue<'gcc>) { + fn filter_landing_pad(&mut self, pers_fn: Function<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { // TODO(antoyo): generate the correct landing pad self.cleanup_landing_pad(pers_fn); } diff --git a/src/common.rs b/src/common.rs index 58ff2f1f8f06..fdd47821b515 100644 --- a/src/common.rs +++ b/src/common.rs @@ -234,19 +234,6 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { match cv { Scalar::Int(int) => { let data = int.to_bits(layout.size(self)); - - // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code - // the paths for floating-point values. - // TODO: Remove this code? - /*if ty == self.float_type { - return self - .context - .new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64); - } - if ty == self.double_type { - return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64)); - }*/ - let value = self.const_uint_big(self.type_ix(bitsize), data); let bytesize = layout.size(self).bytes(); if bitsize > 1 && ty.is_integral() && bytesize as u32 == ty.get_size() { diff --git a/src/context.rs b/src/context.rs index ff141ad365bd..1d029811dfe9 100644 --- a/src/context.rs +++ b/src/context.rs @@ -118,14 +118,15 @@ pub struct CodegenCx<'gcc, 'tcx> { /// A counter that is used for generating local symbol names local_gen_sym_counter: Cell, - eh_personality: Cell>>, + eh_personality: Cell>>, #[cfg(feature = "master")] pub rust_try_fn: Cell, Function<'gcc>)>>, pub pointee_infos: RefCell, Size), Option>>, /// NOTE: a hack is used because the rustc API is not suitable to libgccjit and as such, - /// `const_undef()` returns struct as pointer so that they can later be assigned a value. + /// `const_undef()` returns struct as pointer so that they can later be assigned a value (in + /// e.g. Builder::insert_value). /// As such, this set remembers which of these pointers were returned by this function so that /// they can be dereferenced later. /// FIXME(antoyo): fix the rustc API to avoid having this hack. @@ -155,6 +156,13 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(rust_type)) .unwrap(); let align = layout.align.abi.bytes(); + // For types with size 1, the alignment can be 1 and only 1 + // So, we can skip the call to ``get_aligned`. + // In the future, we can add a GCC API to query the type align, + // and call `get_aligned` if and only if that differs from Rust's expectations. + if layout.size.bytes() == 1 { + return context.new_c_type(ctype); + } #[cfg(feature = "master")] { context.new_c_type(ctype).get_aligned(align) @@ -373,8 +381,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> { type Value = RValue<'gcc>; type Metadata = RValue<'gcc>; - // TODO(antoyo): change to Function<'gcc>. - type Function = RValue<'gcc>; + type Function = Function<'gcc>; type BasicBlock = Block<'gcc>; type Type = Type<'gcc>; @@ -392,11 +399,10 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { &self.vtables } - fn get_fn(&self, instance: Instance<'tcx>) -> RValue<'gcc> { + fn get_fn(&self, instance: Instance<'tcx>) -> Function<'gcc> { let func = get_fn(self, instance); *self.current_func.borrow_mut() = Some(func); - // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. - unsafe { std::mem::transmute(func) } + func } fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> { @@ -420,7 +426,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { ptr } - fn eh_personality(&self) -> RValue<'gcc> { + fn eh_personality(&self) -> Function<'gcc> { // The exception handling personality function. // // If our compilation unit has the `eh_personality` lang item somewhere @@ -458,9 +464,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let symbol_name = tcx.symbol_name(instance).name; let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); self.linkage.set(FunctionType::Extern); - let func = self.declare_fn(symbol_name, fn_abi); - let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; - func + self.declare_fn(symbol_name, fn_abi) } _ => { let name = if wants_msvc_seh(self.sess()) { @@ -468,8 +472,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } else { "rust_eh_personality" }; - let func = self.declare_func(name, self.type_i32(), &[], true); - unsafe { std::mem::transmute::, RValue<'gcc>>(func) } + self.declare_func(name, self.type_i32(), &[], true) } }; // TODO(antoyo): apply target cpu attributes. @@ -481,11 +484,11 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.tcx.sess } - fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) { + fn set_frame_pointer_type(&self, _llfn: Function<'gcc>) { // TODO(antoyo) } - fn apply_target_cpu_attr(&self, _llfn: RValue<'gcc>) { + fn apply_target_cpu_attr(&self, _llfn: Function<'gcc>) { // TODO(antoyo) } diff --git a/src/debuginfo.rs b/src/debuginfo.rs index 3a265fbc64f8..4c8585192a1b 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -1,7 +1,7 @@ use std::ops::Range; use std::sync::Arc; -use gccjit::{Location, RValue}; +use gccjit::{Function, Location, RValue}; use rustc_abi::Size; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind}; use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoCodegenMethods}; @@ -221,7 +221,7 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { &self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - llfn: RValue<'gcc>, + llfn: Function<'gcc>, mir: &mir::Body<'tcx>, ) -> Option> { if self.sess().opts.debuginfo == DebugInfo::None { @@ -272,7 +272,7 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { &self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - _maybe_definition_llfn: Option>, + _maybe_definition_llfn: Option>, ) -> Self::DIScope { // TODO(antoyo): implement. } diff --git a/src/declare.rs b/src/declare.rs index bed82073e2c4..691fd8729e39 100644 --- a/src/declare.rs +++ b/src/declare.rs @@ -94,7 +94,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { _fn_type: Type<'gcc>, #[cfg(feature = "master")] callconv: Option>, #[cfg(not(feature = "master"))] callconv: Option<()>, - ) -> RValue<'gcc> { + ) -> Function<'gcc> { // TODO(antoyo): use the fn_type parameter. let const_string = self.context.new_type::().make_pointer().make_pointer(); let return_type = self.type_i32(); @@ -111,8 +111,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { // NOTE: it is needed to set the current_func here as well, because get_fn() is not called // for the main function. *self.current_func.borrow_mut() = Some(func); - // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. - unsafe { std::mem::transmute(func) } + func } pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> { diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 09132c34aae3..4c10380fe745 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -4,7 +4,9 @@ mod simd; #[cfg(feature = "master")] use std::iter; -use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, Type, UnaryOp}; +#[cfg(feature = "master")] +use gccjit::Type; +use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, UnaryOp}; #[cfg(feature = "master")] use rustc_abi::ExternAbi; use rustc_abi::{BackendRepr, HasDataLayout}; @@ -300,6 +302,8 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let fn_args = instance.args; let simple = get_simple_intrinsic(self, name); + // TODO(antoyo): Only call get_simple_function_f128 and get_simple_function_f128_2args when + // it is the symbols for the supported f128 builtins. let simple_func = get_simple_function(self, name) .or_else(|| get_simple_function_f128(self, name)) .or_else(|| get_simple_function_f128_2args(self, name)); @@ -441,7 +445,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc match int_type_width_signed(args[0].layout.ty, self) { Some((width, signed)) => match name { sym::ctlz | sym::cttz => { - let func = self.current_func.borrow().expect("func"); + let func = self.current_func(); let then_block = func.new_block("then"); let else_block = func.new_block("else"); let after_block = func.new_block("after"); @@ -1109,7 +1113,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // for (int counter = 0; value != 0; counter++) { // value &= value - 1; // } - let func = self.current_func.borrow().expect("func"); + let func = self.current_func(); let loop_head = func.new_block("head"); let loop_body = func.new_block("body"); let loop_tail = func.new_block("tail"); @@ -1188,7 +1192,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let result_type = lhs.get_type(); if signed { // Based on algorithm from: https://stackoverflow.com/a/56531252/389119 - let func = self.current_func.borrow().expect("func"); + let func = self.current_func(); let res = func.new_local(self.location, result_type, "saturating_sum"); let supports_native_type = self.is_native_int_type(result_type); let overflow = if supports_native_type { @@ -1259,7 +1263,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let result_type = lhs.get_type(); if signed { // Based on algorithm from: https://stackoverflow.com/a/56531252/389119 - let func = self.current_func.borrow().expect("func"); + let func = self.current_func(); let res = func.new_local(self.location, result_type, "saturating_diff"); let supports_native_type = self.is_native_int_type(result_type); let overflow = if supports_native_type { @@ -1483,10 +1487,9 @@ fn gen_fn<'a, 'gcc, 'tcx>( // FIXME(eddyb) find a nicer way to do this. cx.linkage.set(FunctionType::Internal); let func = cx.declare_fn(name, fn_abi); - let func_val = unsafe { std::mem::transmute::, RValue<'gcc>>(func) }; - cx.set_frame_pointer_type(func_val); - cx.apply_target_cpu_attr(func_val); - let block = Builder::append_block(cx, func_val, "entry-block"); + cx.set_frame_pointer_type(func); + cx.apply_target_cpu_attr(func); + let block = Builder::append_block(cx, func, "entry-block"); let bx = Builder::build(cx, block); codegen(bx); (return_type, func) diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index d931f0d3b5eb..544d0bfc7105 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -9,6 +9,7 @@ tests/ui/iterators/iter-sum-overflow-debug.rs tests/ui/iterators/iter-sum-overflow-overflow-checks.rs tests/ui/mir/mir_drop_order.rs tests/ui/mir/mir_let_chains_drop_order.rs +tests/ui/mir/mir_match_guard_let_chains_drop_order.rs tests/ui/oom_unwind.rs tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs tests/ui/panic-runtime/abort.rs From 5a29dddfdd47f1f37b6e6e38e77a4b0f94f007d6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 28 Jun 2025 23:50:00 +0200 Subject: [PATCH 009/363] Remove unwanted semi-colon in `rustc_codegen_gcc` --- src/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index a4454cd9c734..805f68cd74ce 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1610,7 +1610,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn filter_landing_pad(&mut self, pers_fn: Function<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { // TODO(antoyo): generate the correct landing pad - self.cleanup_landing_pad(pers_fn); + self.cleanup_landing_pad(pers_fn) } #[cfg(feature = "master")] From 2359b6bd91631d5d0489109743093056e149ed82 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 29 Jun 2025 00:00:58 +0200 Subject: [PATCH 010/363] Fix signature of `filter_landing_pad` --- src/builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 805f68cd74ce..7f16d804103d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1608,9 +1608,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { (value1, value2) } - fn filter_landing_pad(&mut self, pers_fn: Function<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { + fn filter_landing_pad(&mut self, pers_fn: Function<'gcc>) -> () { // TODO(antoyo): generate the correct landing pad - self.cleanup_landing_pad(pers_fn) + self.cleanup_landing_pad(pers_fn); } #[cfg(feature = "master")] From 6e635990da9ceabfbd67d1d129e45879be97813d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Jun 2025 15:20:33 +0200 Subject: [PATCH 011/363] give Pointer::into_parts a more scary name and offer a safer alternative --- src/common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common.rs b/src/common.rs index 58ff2f1f8f06..cc077059dba7 100644 --- a/src/common.rs +++ b/src/common.rs @@ -261,7 +261,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { } } Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative + let (prov, offset) = ptr.prov_and_relative_offset(); let alloc_id = prov.alloc_id(); let base_addr = match self.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { From a7715a44b8b48dc74c530d121ec50399f26d5e22 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 29 Jun 2025 00:20:15 +0200 Subject: [PATCH 012/363] Remove `()` returned value --- src/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index 7f16d804103d..1fce547ad1b4 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1608,7 +1608,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { (value1, value2) } - fn filter_landing_pad(&mut self, pers_fn: Function<'gcc>) -> () { + fn filter_landing_pad(&mut self, pers_fn: Function<'gcc>) { // TODO(antoyo): generate the correct landing pad self.cleanup_landing_pad(pers_fn); } From f1d6f48e9133f73277e096ed667820e584d021eb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 21 Jun 2025 11:26:27 +0000 Subject: [PATCH 013/363] Stop backends from needing to support nullary intrinsics --- example/mini_core_hello_world.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index c3bd62e5897c..6b6f71edaf8c 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -6,6 +6,7 @@ )] #![no_core] #![allow(dead_code, internal_features, non_camel_case_types)] +#![rustfmt::skip] extern crate mini_core; @@ -197,10 +198,10 @@ fn main() { assert_eq!(intrinsics::align_of::() as u8, 2); assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); - assert!(!intrinsics::needs_drop::()); - assert!(!intrinsics::needs_drop::<[u8]>()); - assert!(intrinsics::needs_drop::()); - assert!(intrinsics::needs_drop::()); + assert!(!const { intrinsics::needs_drop::() }); + assert!(!const { intrinsics::needs_drop::<[u8]>() }); + assert!(const { intrinsics::needs_drop::() }); + assert!(const { intrinsics::needs_drop::() }); Unique { pointer: 0 as *const &str, From 609a8abaabb1de574ba07f23ef5de9e6db5fb68a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 30 Jun 2025 16:12:42 +0200 Subject: [PATCH 014/363] Merge commit '4b5c44b14166083eef8d71f15f5ea1f53fc976a0' into subtree-update_cg_gcc_2025-06-30 --- build_system/build_sysroot/Cargo.toml | 1 + build_system/src/test.rs | 28 +--- ...karound-to-make-a-run-make-test-pass.patch | 25 ---- rust-toolchain | 2 +- src/abi.rs | 4 +- src/builder.rs | 46 ++----- src/common.rs | 10 +- src/context.rs | 9 -- src/intrinsic/archs.rs | 124 ++++++++++-------- src/intrinsic/llvm.rs | 37 ++++++ src/intrinsic/mod.rs | 4 +- tools/generate_intrinsics.py | 12 +- 12 files changed, 131 insertions(+), 171 deletions(-) delete mode 100644 patches/tests/0001-Workaround-to-make-a-run-make-test-pass.patch diff --git a/build_system/build_sysroot/Cargo.toml b/build_system/build_sysroot/Cargo.toml index 931f6097abc2..29a3bcec304c 100644 --- a/build_system/build_sysroot/Cargo.toml +++ b/build_system/build_sysroot/Cargo.toml @@ -6,6 +6,7 @@ resolver = "2" [dependencies] core = { path = "./sysroot_src/library/core" } +compiler_builtins = { path = "./sysroot_src/library/compiler-builtins/compiler-builtins" } alloc = { path = "./sysroot_src/library/alloc" } std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] } test = { path = "./sysroot_src/library/test" } diff --git a/build_system/src/test.rs b/build_system/src/test.rs index f1f31f83ca24..cbb0f9493838 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -9,8 +9,8 @@ use crate::build; use crate::config::{Channel, ConfigInfo}; use crate::utils::{ create_dir, get_sysroot_dir, get_toolchain, git_clone, git_clone_root_dir, remove_file, - run_command, run_command_with_env, run_command_with_output, run_command_with_output_and_env, - rustc_version_info, split_args, walk_dir, + run_command, run_command_with_env, run_command_with_output_and_env, rustc_version_info, + split_args, walk_dir, }; type Env = HashMap; @@ -485,30 +485,6 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result { run_command_with_output_and_env(&[&"git", &"checkout"], rust_dir, Some(env))?; } - let mut patches = Vec::new(); - walk_dir( - "patches/tests", - &mut |_| Ok(()), - &mut |file_path: &Path| { - patches.push(file_path.to_path_buf()); - Ok(()) - }, - false, - )?; - patches.sort(); - // TODO: remove duplication with prepare.rs by creating a apply_patch function in the utils - // module. - for file_path in patches { - println!("[GIT] apply `{}`", file_path.display()); - let path = Path::new("../..").join(file_path); - run_command_with_output(&[&"git", &"apply", &path], rust_dir)?; - run_command_with_output(&[&"git", &"add", &"-A"], rust_dir)?; - run_command_with_output( - &[&"git", &"commit", &"--no-gpg-sign", &"-m", &format!("Patch {}", path.display())], - rust_dir, - )?; - } - let cargo = String::from_utf8( run_command_with_env(&[&"rustup", &"which", &"cargo"], rust_dir, Some(env))?.stdout, ) diff --git a/patches/tests/0001-Workaround-to-make-a-run-make-test-pass.patch b/patches/tests/0001-Workaround-to-make-a-run-make-test-pass.patch deleted file mode 100644 index a329d09a95e5..000000000000 --- a/patches/tests/0001-Workaround-to-make-a-run-make-test-pass.patch +++ /dev/null @@ -1,25 +0,0 @@ -From a131c69e54b5c02fe3b517e8f3ad23d4f784ffc8 Mon Sep 17 00:00:00 2001 -From: Antoni Boucher -Date: Fri, 13 Jun 2025 20:25:33 -0400 -Subject: [PATCH] Workaround to make a run-make test pass - ---- - tests/run-make/linker-warning/rmake.rs | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs -index bc21739fefc..0946a7e2a48 100644 ---- a/tests/run-make/linker-warning/rmake.rs -+++ b/tests/run-make/linker-warning/rmake.rs -@@ -55,7 +55,7 @@ fn main() { - diff() - .expected_file("short-error.txt") - .actual_text("(linker error)", out.stderr()) -- .normalize(r#"/rustc[^/]*/"#, "/rustc/") -+ .normalize(r#"/tmp/rustc[^/]*/"#, "/tmp/rustc/") - .normalize( - regex::escape(run_make_support::build_root().to_str().unwrap()), - "/build-root", --- -2.49.0 - diff --git a/rust-toolchain b/rust-toolchain index 8be204c15810..bccbc6cd2c5c 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-06-02" +channel = "nightly-2025-06-28" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/src/abi.rs b/src/abi.rs index 08f3d2819040..0b359f1c5c81 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -1,7 +1,9 @@ #[cfg(feature = "master")] use gccjit::FnAttribute; use gccjit::{ToLValue, ToRValue, Type}; -use rustc_abi::{ArmCall, CanonAbi, InterruptKind, Reg, RegKind, X86Call}; +#[cfg(feature = "master")] +use rustc_abi::{ArmCall, CanonAbi, InterruptKind, X86Call}; +use rustc_abi::{Reg, RegKind}; use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeCodegenMethods}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; diff --git a/src/builder.rs b/src/builder.rs index 1fce547ad1b4..b1785af444a1 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -538,11 +538,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn ret(&mut self, mut value: RValue<'gcc>) { - if self.structs_as_pointer.borrow().contains(&value) { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - value = value.dereference(self.location).to_rvalue(); - } let expected_return_type = self.current_func().get_return_type(); if !expected_return_type.is_compatible_with(value.get_type()) { // NOTE: due to opaque pointers now being used, we need to cast here. @@ -700,7 +695,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let a = self.gcc_int_cast(a, a_type); let b_type = b.get_type().to_unsigned(self); let b = self.gcc_int_cast(b, b_type); - a / b + self.gcc_udiv(a, b) } fn sdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -712,8 +707,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they // should be the same. let typ = a.get_type().to_signed(self); - let b = self.context.new_cast(self.location, b, typ); - a / b + let b = self.gcc_int_cast(b, typ); + self.gcc_sdiv(a, b) } fn fdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -1119,13 +1114,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo) } - fn store(&mut self, mut val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { - if self.structs_as_pointer.borrow().contains(&val) { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - val = val.dereference(self.location).to_rvalue(); - } - + fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { self.store_with_flags(val, ptr, align, MemFlags::empty()) } @@ -1508,16 +1497,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { element.get_address(self.location) } else if value_type.dyncast_vector().is_some() { panic!(); - } else if let Some(pointer_type) = value_type.get_pointee() { - if let Some(struct_type) = pointer_type.is_struct() { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - aggregate_value - .dereference_field(self.location, struct_type.get_field(idx as i32)) - .to_rvalue() - } else { - panic!("Unexpected type {:?}", value_type); - } } else if let Some(struct_type) = value_type.is_struct() { aggregate_value .access_field(self.location, struct_type.get_field(idx as i32)) @@ -1537,21 +1516,18 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { assert_eq!(idx as usize as u64, idx); let value_type = aggregate_value.get_type(); + let new_val = self.current_func().new_local(None, value_type, "aggregate_value"); + self.block.add_assignment(None, new_val, aggregate_value); + let lvalue = if value_type.dyncast_array().is_some() { let index = self .context .new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - self.context.new_array_access(self.location, aggregate_value, index) + self.context.new_array_access(self.location, new_val, index) } else if value_type.dyncast_vector().is_some() { panic!(); - } else if let Some(pointer_type) = value_type.get_pointee() { - if let Some(struct_type) = pointer_type.is_struct() { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - aggregate_value.dereference_field(self.location, struct_type.get_field(idx as i32)) - } else { - panic!("Unexpected type {:?}", value_type); - } + } else if let Some(struct_type) = value_type.is_struct() { + new_val.access_field(None, struct_type.get_field(idx as i32)) } else { panic!("Unexpected type {:?}", value_type); }; @@ -1568,7 +1544,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.llbb().add_assignment(self.location, lvalue, value); - aggregate_value + new_val.to_rvalue() } fn set_personality_fn(&mut self, _personality: Function<'gcc>) { diff --git a/src/common.rs b/src/common.rs index fdd47821b515..38348a48e475 100644 --- a/src/common.rs +++ b/src/common.rs @@ -117,15 +117,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> { let local = self.current_func.borrow().expect("func").new_local(None, typ, "undefined"); - if typ.is_struct().is_some() { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - let pointer = local.get_address(None); - self.structs_as_pointer.borrow_mut().insert(pointer); - pointer - } else { - local.to_rvalue() - } + local.to_rvalue() } fn const_poison(&self, typ: Type<'gcc>) -> RValue<'gcc> { diff --git a/src/context.rs b/src/context.rs index 1d029811dfe9..665cf22ddbae 100644 --- a/src/context.rs +++ b/src/context.rs @@ -124,14 +124,6 @@ pub struct CodegenCx<'gcc, 'tcx> { pub pointee_infos: RefCell, Size), Option>>, - /// NOTE: a hack is used because the rustc API is not suitable to libgccjit and as such, - /// `const_undef()` returns struct as pointer so that they can later be assigned a value (in - /// e.g. Builder::insert_value). - /// As such, this set remembers which of these pointers were returned by this function so that - /// they can be dereferenced later. - /// FIXME(antoyo): fix the rustc API to avoid having this hack. - pub structs_as_pointer: RefCell>>, - #[cfg(feature = "master")] pub cleanup_blocks: RefCell>>, /// The alignment of a u128/i128 type. @@ -304,7 +296,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { #[cfg(feature = "master")] rust_try_fn: Cell::new(None), pointee_infos: Default::default(), - structs_as_pointer: Default::default(), #[cfg(feature = "master")] cleanup_blocks: Default::default(), }; diff --git a/src/intrinsic/archs.rs b/src/intrinsic/archs.rs index f0352c5e6e5d..915ed875e32f 100644 --- a/src/intrinsic/archs.rs +++ b/src/intrinsic/archs.rs @@ -1,9 +1,9 @@ // File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py` // DO NOT EDIT IT! /// Translate a given LLVM intrinsic name to an equivalent GCC one. -fn map_arch_intrinsic(name: &str) -> &str { - let Some(name) = name.strip_prefix("llvm.") else { - unimplemented!("***** unsupported LLVM intrinsic {}", name) +fn map_arch_intrinsic(full_name: &str) -> &'static str { + let Some(name) = full_name.strip_prefix("llvm.") else { + unimplemented!("***** unsupported LLVM intrinsic {}", full_name) }; let Some((arch, name)) = name.split_once('.') else { unimplemented!("***** unsupported LLVM intrinsic {}", name) @@ -11,7 +11,7 @@ fn map_arch_intrinsic(name: &str) -> &str { match arch { "AMDGPU" => { #[allow(non_snake_case)] - fn AMDGPU(name: &str) -> &str { + fn AMDGPU(name: &str, full_name: &str) -> &'static str { match name { // AMDGPU "div.fixup.f32" => "__builtin_amdgpu_div_fixup", @@ -42,14 +42,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "trig.preop.f64" => "__builtin_amdgpu_trig_preop", "trig.preop.v2f64" => "__builtin_amdgpu_trig_preop", "trig.preop.v4f32" => "__builtin_amdgpu_trig_preop", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - AMDGPU(name) + AMDGPU(name, full_name) } "aarch64" => { #[allow(non_snake_case)] - fn aarch64(name: &str) -> &str { + fn aarch64(name: &str, full_name: &str) -> &'static str { match name { // aarch64 "chkfeat" => "__builtin_arm_chkfeat", @@ -75,14 +75,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "tcommit" => "__builtin_arm_tcommit", "tstart" => "__builtin_arm_tstart", "ttest" => "__builtin_arm_ttest", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - aarch64(name) + aarch64(name, full_name) } "amdgcn" => { #[allow(non_snake_case)] - fn amdgcn(name: &str) -> &str { + fn amdgcn(name: &str, full_name: &str) -> &'static str { match name { // amdgcn "alignbyte" => "__builtin_amdgcn_alignbyte", @@ -99,6 +99,8 @@ fn map_arch_intrinsic(name: &str) -> &str { "cvt.f32.fp8" => "__builtin_amdgcn_cvt_f32_fp8", "cvt.off.f32.i4" => "__builtin_amdgcn_cvt_off_f32_i4", "cvt.pk.bf8.f32" => "__builtin_amdgcn_cvt_pk_bf8_f32", + "cvt.pk.f16.bf8" => "__builtin_amdgcn_cvt_pk_f16_bf8", + "cvt.pk.f16.fp8" => "__builtin_amdgcn_cvt_pk_f16_fp8", "cvt.pk.f32.bf8" => "__builtin_amdgcn_cvt_pk_f32_bf8", "cvt.pk.f32.fp8" => "__builtin_amdgcn_cvt_pk_f32_fp8", "cvt.pk.fp8.f32" => "__builtin_amdgcn_cvt_pk_fp8_f32", @@ -292,6 +294,7 @@ fn map_arch_intrinsic(name: &str) -> &str { "s.sendmsg" => "__builtin_amdgcn_s_sendmsg", "s.sendmsghalt" => "__builtin_amdgcn_s_sendmsghalt", "s.setprio" => "__builtin_amdgcn_s_setprio", + "s.setprio.inc.wg" => "__builtin_amdgcn_s_setprio_inc_wg", "s.setreg" => "__builtin_amdgcn_s_setreg", "s.sleep" => "__builtin_amdgcn_s_sleep", "s.sleep.var" => "__builtin_amdgcn_s_sleep_var", @@ -356,14 +359,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "workitem.id.x" => "__builtin_amdgcn_workitem_id_x", "workitem.id.y" => "__builtin_amdgcn_workitem_id_y", "workitem.id.z" => "__builtin_amdgcn_workitem_id_z", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - amdgcn(name) + amdgcn(name, full_name) } "arm" => { #[allow(non_snake_case)] - fn arm(name: &str) -> &str { + fn arm(name: &str, full_name: &str) -> &'static str { match name { // arm "cdp" => "__builtin_arm_cdp", @@ -465,14 +468,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "usub8" => "__builtin_arm_usub8", "uxtab16" => "__builtin_arm_uxtab16", "uxtb16" => "__builtin_arm_uxtb16", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - arm(name) + arm(name, full_name) } "bpf" => { #[allow(non_snake_case)] - fn bpf(name: &str) -> &str { + fn bpf(name: &str, full_name: &str) -> &'static str { match name { // bpf "btf.type.id" => "__builtin_bpf_btf_type_id", @@ -487,25 +490,25 @@ fn map_arch_intrinsic(name: &str) -> &str { "preserve.field.info" => "__builtin_bpf_preserve_field_info", "preserve.type.info" => "__builtin_bpf_preserve_type_info", "pseudo" => "__builtin_bpf_pseudo", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - bpf(name) + bpf(name, full_name) } "cuda" => { #[allow(non_snake_case)] - fn cuda(name: &str) -> &str { + fn cuda(name: &str, full_name: &str) -> &'static str { match name { // cuda "syncthreads" => "__syncthreads", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - cuda(name) + cuda(name, full_name) } "hexagon" => { #[allow(non_snake_case)] - fn hexagon(name: &str) -> &str { + fn hexagon(name: &str, full_name: &str) -> &'static str { match name { // hexagon "A2.abs" => "__builtin_HEXAGON_A2_abs", @@ -2479,14 +2482,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "prefetch" => "__builtin_HEXAGON_prefetch", "vmemcpy" => "__builtin_hexagon_vmemcpy", "vmemset" => "__builtin_hexagon_vmemset", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - hexagon(name) + hexagon(name, full_name) } "loongarch" => { #[allow(non_snake_case)] - fn loongarch(name: &str) -> &str { + fn loongarch(name: &str, full_name: &str) -> &'static str { match name { // loongarch "asrtgt.d" => "__builtin_loongarch_asrtgt_d", @@ -3988,14 +3991,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "movfcsr2gr" => "__builtin_loongarch_movfcsr2gr", "movgr2fcsr" => "__builtin_loongarch_movgr2fcsr", "syscall" => "__builtin_loongarch_syscall", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - loongarch(name) + loongarch(name, full_name) } "mips" => { #[allow(non_snake_case)] - fn mips(name: &str) -> &str { + fn mips(name: &str, full_name: &str) -> &'static str { match name { // mips "absq.s.ph" => "__builtin_mips_absq_s_ph", @@ -4669,14 +4672,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "wrdsp" => "__builtin_mips_wrdsp", "xor.v" => "__builtin_msa_xor_v", "xori.b" => "__builtin_msa_xori_b", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - mips(name) + mips(name, full_name) } "nvvm" => { #[allow(non_snake_case)] - fn nvvm(name: &str) -> &str { + fn nvvm(name: &str, full_name: &str) -> &'static str { match name { // nvvm "abs.i" => "__nvvm_abs_i", @@ -5024,6 +5027,7 @@ fn map_arch_intrinsic(name: &str) -> &str { "nanosleep" => "__nvvm_nanosleep", "neg.bf16" => "__nvvm_neg_bf16", "neg.bf16x2" => "__nvvm_neg_bf16x2", + "pm.event.mask" => "__nvvm_pm_event_mask", "popc.i" => "__nvvm_popc_i", "popc.ll" => "__nvvm_popc_ll", "prmt" => "__nvvm_prmt", @@ -5448,14 +5452,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "vote.ballot.sync" => "__nvvm_vote_ballot_sync", "vote.uni" => "__nvvm_vote_uni", "vote.uni.sync" => "__nvvm_vote_uni_sync", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - nvvm(name) + nvvm(name, full_name) } "ppc" => { #[allow(non_snake_case)] - fn ppc(name: &str) -> &str { + fn ppc(name: &str, full_name: &str) -> &'static str { match name { // ppc "addex" => "__builtin_ppc_addex", @@ -5842,7 +5846,10 @@ fn map_arch_intrinsic(name: &str) -> &str { "mulhdu" => "__builtin_ppc_mulhdu", "mulhw" => "__builtin_ppc_mulhw", "mulhwu" => "__builtin_ppc_mulhwu", + "national2packed" => "__builtin_ppc_national2packed", "pack.longdouble" => "__builtin_pack_longdouble", + "packed2national" => "__builtin_ppc_packed2national", + "packed2zoned" => "__builtin_ppc_packed2zoned", "pdepd" => "__builtin_pdepd", "pextd" => "__builtin_pextd", "qpx.qvfabs" => "__builtin_qpx_qvfabs", @@ -6035,14 +6042,15 @@ fn map_arch_intrinsic(name: &str) -> &str { "vsx.xxinsertw" => "__builtin_vsx_xxinsertw", "vsx.xxleqv" => "__builtin_vsx_xxleqv", "vsx.xxpermx" => "__builtin_vsx_xxpermx", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + "zoned2packed" => "__builtin_ppc_zoned2packed", + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - ppc(name) + ppc(name, full_name) } "ptx" => { #[allow(non_snake_case)] - fn ptx(name: &str) -> &str { + fn ptx(name: &str, full_name: &str) -> &'static str { match name { // ptx "bar.sync" => "__builtin_ptx_bar_sync", @@ -6063,14 +6071,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "read.pm3" => "__builtin_ptx_read_pm3", "read.smid" => "__builtin_ptx_read_smid", "read.warpid" => "__builtin_ptx_read_warpid", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - ptx(name) + ptx(name, full_name) } "r600" => { #[allow(non_snake_case)] - fn r600(name: &str) -> &str { + fn r600(name: &str, full_name: &str) -> &'static str { match name { // r600 "group.barrier" => "__builtin_r600_group_barrier", @@ -6088,14 +6096,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "read.tidig.x" => "__builtin_r600_read_tidig_x", "read.tidig.y" => "__builtin_r600_read_tidig_y", "read.tidig.z" => "__builtin_r600_read_tidig_z", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - r600(name) + r600(name, full_name) } "riscv" => { #[allow(non_snake_case)] - fn riscv(name: &str) -> &str { + fn riscv(name: &str, full_name: &str) -> &'static str { match name { // riscv "aes32dsi" => "__builtin_riscv_aes32dsi", @@ -6119,14 +6127,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "sha512sum0r" => "__builtin_riscv_sha512sum0r", "sha512sum1" => "__builtin_riscv_sha512sum1", "sha512sum1r" => "__builtin_riscv_sha512sum1r", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - riscv(name) + riscv(name, full_name) } "s390" => { #[allow(non_snake_case)] - fn s390(name: &str) -> &str { + fn s390(name: &str, full_name: &str) -> &'static str { match name { // s390 "bdepg" => "__builtin_s390_bdepg", @@ -6313,14 +6321,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "vupllf" => "__builtin_s390_vupllf", "vupllg" => "__builtin_s390_vupllg", "vupllh" => "__builtin_s390_vupllh", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - s390(name) + s390(name, full_name) } "ve" => { #[allow(non_snake_case)] - fn ve(name: &str) -> &str { + fn ve(name: &str, full_name: &str) -> &'static str { match name { // ve "vl.andm.MMM" => "__builtin_ve_vl_andm_MMM", @@ -7586,14 +7594,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "vl.vxor.vvvvl" => "__builtin_ve_vl_vxor_vvvvl", "vl.xorm.MMM" => "__builtin_ve_vl_xorm_MMM", "vl.xorm.mmm" => "__builtin_ve_vl_xorm_mmm", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - ve(name) + ve(name, full_name) } "x86" => { #[allow(non_snake_case)] - fn x86(name: &str) -> &str { + fn x86(name: &str, full_name: &str) -> &'static str { match name { // x86 "aadd32" => "__builtin_ia32_aadd32", @@ -10154,25 +10162,25 @@ fn map_arch_intrinsic(name: &str) -> &str { "xresldtrk" => "__builtin_ia32_xresldtrk", "xsusldtrk" => "__builtin_ia32_xsusldtrk", "xtest" => "__builtin_ia32_xtest", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - x86(name) + x86(name, full_name) } "xcore" => { #[allow(non_snake_case)] - fn xcore(name: &str) -> &str { + fn xcore(name: &str, full_name: &str) -> &'static str { match name { // xcore "bitrev" => "__builtin_bitrev", "getid" => "__builtin_getid", "getps" => "__builtin_getps", "setps" => "__builtin_setps", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - xcore(name) + xcore(name, full_name) } - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM architecture {arch}, intrinsic:{full_name}"), } } diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 0b77694f1156..39dba28b24c9 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -648,6 +648,11 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( new_args.push(handle); args = new_args.into(); } + "__builtin_ia32_rdtscp" => { + let result = builder.current_func().new_local(None, builder.u32_type, "result"); + let new_args = vec![result.get_address(None).to_rvalue()]; + args = new_args.into(); + } _ => (), } } else { @@ -764,6 +769,14 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( new_args.swap(0, 1); args = new_args.into(); } + "__builtin_ia32_dpps256" => { + let mut new_args = args.to_vec(); + // NOTE: without this cast to u8 (and it needs to be a u8 to fix the issue), we + // would get the following error: + // the last argument must be an 8-bit immediate + new_args[2] = builder.context.new_cast(None, new_args[2], builder.cx.type_u8()); + args = new_args.into(); + } _ => (), } } @@ -935,6 +948,19 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>( ); return_value = result.to_rvalue(); } + "__builtin_ia32_rdtscp" => { + let field1 = builder.context.new_field(None, return_value.get_type(), "rdtscpField1"); + let return2 = args[0].dereference(None).to_rvalue(); + let field2 = builder.context.new_field(None, return2.get_type(), "rdtscpField2"); + let struct_type = + builder.context.new_struct_type(None, "rdtscpResult", &[field1, field2]); + return_value = builder.context.new_struct_constructor( + None, + struct_type.as_type(), + None, + &[return_value, return2], + ); + } _ => (), } @@ -1529,6 +1555,17 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.aesdecwide128kl" => "__builtin_ia32_aesdecwide128kl_u8", "llvm.x86.aesencwide256kl" => "__builtin_ia32_aesencwide256kl_u8", "llvm.x86.aesdecwide256kl" => "__builtin_ia32_aesdecwide256kl_u8", + "llvm.x86.avx512.uitofp.round.v8f16.v8i16" => "__builtin_ia32_vcvtuw2ph128_mask", + "llvm.x86.avx512.uitofp.round.v16f16.v16i16" => "__builtin_ia32_vcvtuw2ph256_mask", + "llvm.x86.avx512.uitofp.round.v32f16.v32i16" => "__builtin_ia32_vcvtuw2ph512_mask_round", + "llvm.x86.avx512.uitofp.round.v8f16.v8i32" => "__builtin_ia32_vcvtudq2ph256_mask", + "llvm.x86.avx512.uitofp.round.v16f16.v16i32" => "__builtin_ia32_vcvtudq2ph512_mask_round", + "llvm.x86.avx512.uitofp.round.v8f16.v8i64" => "__builtin_ia32_vcvtuqq2ph512_mask_round", + "llvm.x86.avx512.uitofp.round.v8f64.v8i64" => "__builtin_ia32_cvtuqq2pd512_mask", + "llvm.x86.avx512.uitofp.round.v2f64.v2i64" => "__builtin_ia32_cvtuqq2pd128_mask", + "llvm.x86.avx512.uitofp.round.v4f64.v4i64" => "__builtin_ia32_cvtuqq2pd256_mask", + "llvm.x86.avx512.uitofp.round.v8f32.v8i64" => "__builtin_ia32_cvtuqq2ps512_mask", + "llvm.x86.avx512.uitofp.round.v4f32.v4i64" => "__builtin_ia32_cvtuqq2ps256_mask", // TODO: support the tile builtins: "llvm.x86.ldtilecfg" => "__builtin_trap", diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 4c10380fe745..497605978fe2 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -114,7 +114,6 @@ fn get_simple_intrinsic<'gcc, 'tcx>( } sym::copysignf32 => "copysignf", sym::copysignf64 => "copysign", - sym::copysignf128 => "copysignl", sym::floorf32 => "floorf", sym::floorf64 => "floor", sym::ceilf32 => "ceilf", @@ -238,6 +237,7 @@ fn get_simple_function_f128_2args<'gcc, 'tcx>( let func_name = match name { sym::maxnumf128 => "fmaxf128", sym::minnumf128 => "fminf128", + sym::copysignf128 => "copysignf128", _ => return None, }; Some(cx.context.new_function( @@ -261,6 +261,7 @@ fn f16_builtin<'gcc, 'tcx>( let f32_type = cx.type_f32(); let builtin_name = match name { sym::ceilf16 => "__builtin_ceilf", + sym::copysignf16 => "__builtin_copysignf", sym::floorf16 => "__builtin_floorf", sym::fmaf16 => "fmaf", sym::maxnumf16 => "__builtin_fmaxf", @@ -330,6 +331,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc ) } sym::ceilf16 + | sym::copysignf16 | sym::floorf16 | sym::fmaf16 | sym::maxnumf16 diff --git a/tools/generate_intrinsics.py b/tools/generate_intrinsics.py index ed0ebf007195..88927f39b93e 100644 --- a/tools/generate_intrinsics.py +++ b/tools/generate_intrinsics.py @@ -176,14 +176,14 @@ def update_intrinsics(llvm_path, llvmint, llvmint2): out.write("// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`\n") out.write("// DO NOT EDIT IT!\n") out.write("/// Translate a given LLVM intrinsic name to an equivalent GCC one.\n") - out.write("fn map_arch_intrinsic(name:&str)->&str{\n") - out.write('let Some(name) = name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", name) };\n') + out.write("fn map_arch_intrinsic(full_name:&str)->&'static str{\n") + out.write('let Some(name) = full_name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", full_name) };\n') out.write('let Some((arch, name)) = name.split_once(\'.\') else { unimplemented!("***** unsupported LLVM intrinsic {}", name) };\n') out.write("match arch {\n") for arch in archs: if len(intrinsics[arch]) == 0: continue - out.write("\"{}\" => {{ #[allow(non_snake_case)] fn {}(name: &str) -> &str {{ match name {{".format(arch,arch)) + out.write("\"{}\" => {{ #[allow(non_snake_case)] fn {}(name: &str,full_name:&str) -> &'static str {{ match name {{".format(arch,arch)) intrinsics[arch].sort(key=lambda x: (x[0], x[2])) out.write(' // {}\n'.format(arch)) for entry in intrinsics[arch]: @@ -196,9 +196,9 @@ def update_intrinsics(llvm_path, llvmint, llvmint2): out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(llvm_name, entry[1])) else: out.write(' "{}" => "{}",\n'.format(llvm_name, entry[1])) - out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n') - out.write("}} }} {}(name) }}\n,".format(arch)) - out.write(' _ => unimplemented!("***** unsupported LLVM architecture {}", name),\n') + out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),\n') + out.write("}} }} {}(name,full_name) }}\n,".format(arch)) + out.write(' _ => unimplemented!("***** unsupported LLVM architecture {arch}, intrinsic:{full_name}"),\n') out.write("}\n}") subprocess.call(["rustfmt", output_file]) print("Done!") From fba4177d0fd07fc3f2d2202b39199ab913fb6164 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 23 Jun 2025 16:08:01 +0000 Subject: [PATCH 015/363] Simplify assignments. --- compiler/rustc_mir_transform/src/gvn.rs | 59 ++++++++++++++----------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index bda71ceaa551..b19323239b6f 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1755,7 +1755,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { self.simplify_place_projection(place, location); - if context.is_mutating_use() && !place.projection.is_empty() { + if context.is_mutating_use() && place.is_indirect() { // Non-local mutation maybe invalidate deref. self.invalidate_derefs(); } @@ -1767,36 +1767,41 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { self.super_operand(operand, location); } - fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) { - if let StatementKind::Assign(box (ref mut lhs, ref mut rvalue)) = stmt.kind { - self.simplify_place_projection(lhs, location); + fn visit_assign( + &mut self, + lhs: &mut Place<'tcx>, + rvalue: &mut Rvalue<'tcx>, + location: Location, + ) { + self.simplify_place_projection(lhs, location); - let value = self.simplify_rvalue(lhs, rvalue, location); - let value = if let Some(local) = lhs.as_local() - && self.ssa.is_ssa(local) - // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark - // `local` as reusable if we have an exact type match. - && self.local_decls[local].ty == rvalue.ty(self.local_decls, self.tcx) + let value = self.simplify_rvalue(lhs, rvalue, location); + if let Some(value) = value { + if let Some(const_) = self.try_as_constant(value) { + *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_))); + } else if let Some(place) = self.try_as_place(value, location, false) + && *rvalue != Rvalue::Use(Operand::Move(place)) + && *rvalue != Rvalue::Use(Operand::Copy(place)) { - let value = value.unwrap_or_else(|| self.new_opaque()); - self.assign(local, value); - Some(value) - } else { - value - }; - if let Some(value) = value { - if let Some(const_) = self.try_as_constant(value) { - *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_))); - } else if let Some(place) = self.try_as_place(value, location, false) - && *rvalue != Rvalue::Use(Operand::Move(place)) - && *rvalue != Rvalue::Use(Operand::Copy(place)) - { - *rvalue = Rvalue::Use(Operand::Copy(place)); - self.reused_locals.insert(place.local); - } + *rvalue = Rvalue::Use(Operand::Copy(place)); + self.reused_locals.insert(place.local); } } - self.super_statement(stmt, location); + + if lhs.is_indirect() { + // Non-local mutation maybe invalidate deref. + self.invalidate_derefs(); + } + + if let Some(local) = lhs.as_local() + && self.ssa.is_ssa(local) + // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark + // `local` as reusable if we have an exact type match. + && self.local_decls[local].ty == rvalue.ty(self.local_decls, self.tcx) + { + let value = value.unwrap_or_else(|| self.new_opaque()); + self.assign(local, value); + } } fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { From ac70dc85e74d789b82b8352a895335b18e1a569e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 30 Jun 2025 18:26:37 +0000 Subject: [PATCH 016/363] Introduce Value::RawPtr as it behaves differently from other aggregates. --- compiler/rustc_mir_transform/src/gvn.rs | 126 +++++++++++++----------- 1 file changed, 69 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index b19323239b6f..b59b73531129 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -163,12 +163,6 @@ enum AggregateTy<'tcx> { Array, Tuple, Def(DefId, ty::GenericArgsRef<'tcx>), - RawPtr { - /// Needed for cast propagation. - data_pointer_ty: Ty<'tcx>, - /// The data pointer can be anything thin, so doesn't determine the output. - output_pointer_ty: Ty<'tcx>, - }, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -194,6 +188,17 @@ enum Value<'tcx> { /// An aggregate value, either tuple/closure/struct/enum. /// This does not contain unions, as we cannot reason with the value. Aggregate(AggregateTy<'tcx>, VariantIdx, Vec), + /// A raw pointer aggregate built from a thin pointer and metadata. + RawPtr { + /// Thin pointer component. This is field 0 in MIR. + pointer: VnIndex, + /// Metadata component. This is field 1 in MIR. + metadata: VnIndex, + /// Needed for cast propagation. + data_pointer_ty: Ty<'tcx>, + /// The data pointer can be anything thin, so doesn't determine the output. + output_pointer_ty: Ty<'tcx>, + }, /// This corresponds to a `[value; count]` expression. Repeat(VnIndex, ty::Const<'tcx>), /// The address of a place. @@ -402,22 +407,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { AggregateTy::Def(def_id, args) => { self.tcx.type_of(def_id).instantiate(self.tcx, args) } - AggregateTy::RawPtr { output_pointer_ty, .. } => output_pointer_ty, }; let variant = if ty.is_enum() { Some(variant) } else { None }; let ty = self.ecx.layout_of(ty).ok()?; if ty.is_zst() { ImmTy::uninit(ty).into() - } else if matches!(kind, AggregateTy::RawPtr { .. }) { - // Pointers don't have fields, so don't `project_field` them. - let data = self.ecx.read_pointer(fields[0]).discard_err()?; - let meta = if fields[1].layout.is_zst() { - MemPlaceMeta::None - } else { - MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).discard_err()?) - }; - let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); - ImmTy::from_immediate(ptr_imm, ty).into() } else if matches!( ty.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..) @@ -446,6 +440,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return None; } } + RawPtr { pointer, metadata, output_pointer_ty, data_pointer_ty: _ } => { + let pointer = self.evaluated[pointer].as_ref()?; + let metadata = self.evaluated[metadata].as_ref()?; + let output_pointer_ty = self.ecx.layout_of(output_pointer_ty).ok()?; + debug_assert!(!output_pointer_ty.is_zst()); + + // Pointers don't have fields, so don't `project_field` them. + let data = self.ecx.read_pointer(pointer).discard_err()?; + let meta = if metadata.layout.is_zst() { + MemPlaceMeta::None + } else { + MemPlaceMeta::Meta(self.ecx.read_scalar(metadata).discard_err()?) + }; + let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); + ImmTy::from_immediate(ptr_imm, output_pointer_ty).into() + } Projection(base, elem) => { let value = self.evaluated[base].as_ref()?; @@ -1026,7 +1036,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } - let (mut ty, variant_index) = match *kind { + let fields: Vec<_> = field_ops + .iter_mut() + .map(|op| self.simplify_operand(op, location).unwrap_or_else(|| self.new_opaque())) + .collect(); + + let (ty, variant_index) = match *kind { AggregateKind::Array(..) => { assert!(!field_ops.is_empty()); (AggregateTy::Array, FIRST_VARIANT) @@ -1045,42 +1060,42 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { AggregateKind::Adt(_, _, _, _, Some(_)) => return None, AggregateKind::RawPtr(pointee_ty, mtbl) => { assert_eq!(field_ops.len(), 2); - let data_pointer_ty = field_ops[FieldIdx::ZERO].ty(self.local_decls, self.tcx); + let mut data_pointer_ty = field_ops[FieldIdx::ZERO].ty(self.local_decls, self.tcx); let output_pointer_ty = Ty::new_ptr(self.tcx, pointee_ty, mtbl); - (AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty }, FIRST_VARIANT) + + let [mut pointer, metadata] = fields.try_into().unwrap(); + + // Any thin pointer of matching mutability is fine as the data pointer. + let mut was_updated = false; + while let Value::Cast { + kind: CastKind::PtrToPtr, + value: cast_value, + from: cast_from, + to: _, + } = self.get(pointer) + && let ty::RawPtr(from_pointee_ty, from_mtbl) = cast_from.kind() + && let ty::RawPtr(_, output_mtbl) = output_pointer_ty.kind() + && from_mtbl == output_mtbl + && from_pointee_ty.is_sized(self.tcx, self.typing_env()) + { + pointer = *cast_value; + data_pointer_ty = *cast_from; + was_updated = true; + } + + if was_updated && let Some(op) = self.try_as_operand(pointer, location) { + field_ops[FieldIdx::ZERO] = op; + } + + return Some(self.insert(Value::RawPtr { + output_pointer_ty, + data_pointer_ty, + pointer, + metadata, + })); } }; - let mut fields: Vec<_> = field_ops - .iter_mut() - .map(|op| self.simplify_operand(op, location).unwrap_or_else(|| self.new_opaque())) - .collect(); - - if let AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty } = &mut ty { - let mut was_updated = false; - - // Any thin pointer of matching mutability is fine as the data pointer. - while let Value::Cast { - kind: CastKind::PtrToPtr, - value: cast_value, - from: cast_from, - to: _, - } = self.get(fields[0]) - && let ty::RawPtr(from_pointee_ty, from_mtbl) = cast_from.kind() - && let ty::RawPtr(_, output_mtbl) = output_pointer_ty.kind() - && from_mtbl == output_mtbl - && from_pointee_ty.is_sized(self.tcx, self.typing_env()) - { - fields[0] = *cast_value; - *data_pointer_ty = *cast_from; - was_updated = true; - } - - if was_updated && let Some(op) = self.try_as_operand(fields[0], location) { - field_ops[FieldIdx::ZERO] = op; - } - } - if let AggregateTy::Array = ty && fields.len() > 4 { @@ -1165,9 +1180,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => { Value::BinaryOp(BinOp::Eq, *lhs, *rhs) } - (UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => { - return Some(fields[1]); - } + (UnOp::PtrMetadata, Value::RawPtr { metadata, .. }) => return Some(*metadata), // We have an unsizing cast, which assigns the length to wide pointer metadata. ( UnOp::PtrMetadata, @@ -1399,16 +1412,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // If a cast just casts away the metadata again, then we can get it by // casting the original thin pointer passed to `from_raw_parts` if let PtrToPtr = kind - && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) = - self.get(value) + && let Value::RawPtr { data_pointer_ty, pointer, .. } = self.get(value) && let ty::RawPtr(to_pointee, _) = to.kind() && to_pointee.is_sized(self.tcx, self.typing_env()) { from = *data_pointer_ty; - value = fields[0]; + value = *pointer; was_updated_this_iteration = true; if *data_pointer_ty == to { - return Some(fields[0]); + return Some(*pointer); } } From be41333604c15acef2766619beac604bb3726538 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 30 Jun 2025 19:27:27 +0000 Subject: [PATCH 017/363] Store a full Ty with each Value. --- compiler/rustc_mir_transform/src/gvn.rs | 244 ++++++++---------- tests/mir-opt/const_prop/transmute.rs | 2 +- ...ransmute.unreachable_direct.GVN.32bit.diff | 2 +- ...ransmute.unreachable_direct.GVN.64bit.diff | 2 +- ...generic_cast_metadata.GVN.panic-abort.diff | 3 +- ...eneric_cast_metadata.GVN.panic-unwind.diff | 3 +- tests/mir-opt/gvn.rs | 2 +- 7 files changed, 122 insertions(+), 136 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index b59b73531129..3e4c05b355f6 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -130,7 +130,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { let mut state = VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls); for local in body.args_iter().filter(|&local| ssa.is_ssa(local)) { - let opaque = state.new_opaque(); + let opaque = state.new_opaque(body.local_decls[local].ty); state.assign(local, opaque); } @@ -238,7 +238,7 @@ struct VnState<'body, 'tcx> { /// Locals that are assigned that value. // This vector does not hold all the values of `VnIndex` that we create. rev_locals: IndexVec>, - values: FxIndexSet>, + values: FxIndexSet<(Value<'tcx>, Ty<'tcx>)>, /// Values evaluated as constants if possible. evaluated: IndexVec>>, /// Counter to generate different values. @@ -287,8 +287,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } #[instrument(level = "trace", skip(self), ret)] - fn insert(&mut self, value: Value<'tcx>) -> VnIndex { - let (index, new) = self.values.insert_full(value); + fn insert(&mut self, ty: Ty<'tcx>, value: Value<'tcx>) -> VnIndex { + let (index, new) = self.values.insert_full((value, ty)); let index = VnIndex::from_usize(index); if new { // Grow `evaluated` and `rev_locals` here to amortize the allocations. @@ -310,20 +310,33 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { /// Create a new `Value` for which we have no information at all, except that it is distinct /// from all the others. #[instrument(level = "trace", skip(self), ret)] - fn new_opaque(&mut self) -> VnIndex { + fn new_opaque(&mut self, ty: Ty<'tcx>) -> VnIndex { let value = Value::Opaque(self.next_opaque()); - self.insert(value) + self.insert(ty, value) } /// Create a new `Value::Address` distinct from all the others. #[instrument(level = "trace", skip(self), ret)] fn new_pointer(&mut self, place: Place<'tcx>, kind: AddressKind) -> VnIndex { + let pty = place.ty(self.local_decls, self.tcx).ty; + let ty = match kind { + AddressKind::Ref(bk) => { + Ty::new_ref(self.tcx, self.tcx.lifetimes.re_erased, pty, bk.to_mutbl_lossy()) + } + AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, pty, mutbl.to_mutbl_lossy()), + }; let value = Value::Address { place, kind, provenance: self.next_opaque() }; - self.insert(value) + self.insert(ty, value) } + #[inline] fn get(&self, index: VnIndex) -> &Value<'tcx> { - self.values.get_index(index.as_usize()).unwrap() + &self.values.get_index(index.as_usize()).unwrap().0 + } + + #[inline] + fn ty(&self, index: VnIndex) -> Ty<'tcx> { + self.values.get_index(index.as_usize()).unwrap().1 } /// Record that `local` is assigned `value`. `local` must be SSA. @@ -346,29 +359,29 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { debug_assert_ne!(disambiguator, 0); disambiguator }; - self.insert(Value::Constant { value, disambiguator }) + self.insert(value.ty(), Value::Constant { value, disambiguator }) } fn insert_bool(&mut self, flag: bool) -> VnIndex { // Booleans are deterministic. let value = Const::from_bool(self.tcx, flag); debug_assert!(value.is_deterministic()); - self.insert(Value::Constant { value, disambiguator: 0 }) + self.insert(self.tcx.types.bool, Value::Constant { value, disambiguator: 0 }) } - fn insert_scalar(&mut self, scalar: Scalar, ty: Ty<'tcx>) -> VnIndex { + fn insert_scalar(&mut self, ty: Ty<'tcx>, scalar: Scalar) -> VnIndex { // Scalars are deterministic. let value = Const::from_scalar(self.tcx, scalar, ty); debug_assert!(value.is_deterministic()); - self.insert(Value::Constant { value, disambiguator: 0 }) + self.insert(ty, Value::Constant { value, disambiguator: 0 }) } - fn insert_tuple(&mut self, values: Vec) -> VnIndex { - self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::ZERO, values)) + fn insert_tuple(&mut self, ty: Ty<'tcx>, values: Vec) -> VnIndex { + self.insert(ty, Value::Aggregate(AggregateTy::Tuple, VariantIdx::ZERO, values)) } - fn insert_deref(&mut self, value: VnIndex) -> VnIndex { - let value = self.insert(Value::Projection(value, ProjectionElem::Deref)); + fn insert_deref(&mut self, ty: Ty<'tcx>, value: VnIndex) -> VnIndex { + let value = self.insert(ty, Value::Projection(value, ProjectionElem::Deref)); self.derefs.push(value); value } @@ -376,14 +389,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fn invalidate_derefs(&mut self) { for deref in std::mem::take(&mut self.derefs) { let opaque = self.next_opaque(); - *self.values.get_index_mut2(deref.index()).unwrap() = Value::Opaque(opaque); + self.values.get_index_mut2(deref.index()).unwrap().0 = Value::Opaque(opaque); } } #[instrument(level = "trace", skip(self), ret)] fn eval_to_const(&mut self, value: VnIndex) -> Option> { use Value::*; + let ty = self.ty(value); + let ty = self.ecx.layout_of(ty).ok()?; let op = match *self.get(value) { + _ if ty.is_zst() => ImmTy::uninit(ty).into(), + Opaque(_) => return None, // Do not bother evaluating repeat expressions. This would uselessly consume memory. Repeat(..) => return None, @@ -391,31 +408,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Constant { ref value, disambiguator: _ } => { self.ecx.eval_mir_constant(value, DUMMY_SP, None).discard_err()? } - Aggregate(kind, variant, ref fields) => { + Aggregate(_, variant, ref fields) => { let fields = fields .iter() .map(|&f| self.evaluated[f].as_ref()) .collect::>>()?; - let ty = match kind { - AggregateTy::Array => { - assert!(fields.len() > 0); - Ty::new_array(self.tcx, fields[0].layout.ty, fields.len() as u64) - } - AggregateTy::Tuple => { - Ty::new_tup_from_iter(self.tcx, fields.iter().map(|f| f.layout.ty)) - } - AggregateTy::Def(def_id, args) => { - self.tcx.type_of(def_id).instantiate(self.tcx, args) - } - }; - let variant = if ty.is_enum() { Some(variant) } else { None }; - let ty = self.ecx.layout_of(ty).ok()?; - if ty.is_zst() { - ImmTy::uninit(ty).into() - } else if matches!( - ty.backend_repr, - BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..) - ) { + let variant = if ty.ty.is_enum() { Some(variant) } else { None }; + if matches!(ty.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) + { let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; let variant_dest = if let Some(variant) = variant { self.ecx.project_downcast(&dest, variant).discard_err()? @@ -440,11 +440,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return None; } } - RawPtr { pointer, metadata, output_pointer_ty, data_pointer_ty: _ } => { + RawPtr { pointer, metadata, output_pointer_ty: _, data_pointer_ty: _ } => { let pointer = self.evaluated[pointer].as_ref()?; let metadata = self.evaluated[metadata].as_ref()?; - let output_pointer_ty = self.ecx.layout_of(output_pointer_ty).ok()?; - debug_assert!(!output_pointer_ty.is_zst()); // Pointers don't have fields, so don't `project_field` them. let data = self.ecx.read_pointer(pointer).discard_err()?; @@ -454,7 +452,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { MemPlaceMeta::Meta(self.ecx.read_scalar(metadata).discard_err()?) }; let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); - ImmTy::from_immediate(ptr_imm, output_pointer_ty).into() + ImmTy::from_immediate(ptr_imm, ty).into() } Projection(base, elem) => { @@ -481,7 +479,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { }; self.ecx.project(value, elem).discard_err()? } - Address { place, kind, provenance: _ } => { + Address { place, kind: _, provenance: _ } => { if !place.is_indirect_first_projection() { return None; } @@ -497,19 +495,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { mplace = self.ecx.project(&mplace, proj).discard_err()?; } let pointer = mplace.to_ref(&self.ecx); - let ty = match kind { - AddressKind::Ref(bk) => Ty::new_ref( - self.tcx, - self.tcx.lifetimes.re_erased, - mplace.layout.ty, - bk.to_mutbl_lossy(), - ), - AddressKind::Address(mutbl) => { - Ty::new_ptr(self.tcx, mplace.layout.ty, mutbl.to_mutbl_lossy()) - } - }; - let layout = self.ecx.layout_of(ty).ok()?; - ImmTy::from_immediate(pointer, layout).into() + ImmTy::from_immediate(pointer, ty).into() } Discriminant(base) => { @@ -521,32 +507,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } Len(slice) => { let slice = self.evaluated[slice].as_ref()?; - let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); let len = slice.len(&self.ecx).discard_err()?; - let imm = ImmTy::from_uint(len, usize_layout); - imm.into() + ImmTy::from_uint(len, ty).into() } - NullaryOp(null_op, ty) => { - let layout = self.ecx.layout_of(ty).ok()?; + NullaryOp(null_op, arg_ty) => { + let arg_layout = self.ecx.layout_of(arg_ty).ok()?; if let NullOp::SizeOf | NullOp::AlignOf = null_op - && layout.is_unsized() + && arg_layout.is_unsized() { return None; } let val = match null_op { - NullOp::SizeOf => layout.size.bytes(), - NullOp::AlignOf => layout.align.abi.bytes(), + NullOp::SizeOf => arg_layout.size.bytes(), + NullOp::AlignOf => arg_layout.align.abi.bytes(), NullOp::OffsetOf(fields) => self .ecx .tcx - .offset_of_subfield(self.typing_env(), layout, fields.iter()) + .offset_of_subfield(self.typing_env(), arg_layout, fields.iter()) .bytes(), NullOp::UbChecks => return None, NullOp::ContractChecks => return None, }; - let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); - let imm = ImmTy::from_uint(val, usize_layout); - imm.into() + ImmTy::from_uint(val, ty).into() } UnaryOp(un_op, operand) => { let operand = self.evaluated[operand].as_ref()?; @@ -562,30 +544,27 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let val = self.ecx.binary_op(bin_op, &lhs, &rhs).discard_err()?; val.into() } - Cast { kind, value, from: _, to } => match kind { + Cast { kind, value, from: _, to: _ } => match kind { CastKind::IntToInt | CastKind::IntToFloat => { let value = self.evaluated[value].as_ref()?; let value = self.ecx.read_immediate(value).discard_err()?; - let to = self.ecx.layout_of(to).ok()?; - let res = self.ecx.int_to_int_or_float(&value, to).discard_err()?; + let res = self.ecx.int_to_int_or_float(&value, ty).discard_err()?; res.into() } CastKind::FloatToFloat | CastKind::FloatToInt => { let value = self.evaluated[value].as_ref()?; let value = self.ecx.read_immediate(value).discard_err()?; - let to = self.ecx.layout_of(to).ok()?; - let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?; + let res = self.ecx.float_to_float_or_int(&value, ty).discard_err()?; res.into() } CastKind::Transmute => { let value = self.evaluated[value].as_ref()?; - let to = self.ecx.layout_of(to).ok()?; // `offset` for immediates generally only supports projections that match the // type of the immediate. However, as a HACK, we exploit that it can also do // limited transmutes: it only works between types with the same layout, and // cannot transmute pointers to integers. if value.as_mplace_or_imm().is_right() { - let can_transmute = match (value.layout.backend_repr, to.backend_repr) { + let can_transmute = match (value.layout.backend_repr, ty.backend_repr) { (BackendRepr::Scalar(s1), BackendRepr::Scalar(s2)) => { s1.size(&self.ecx) == s2.size(&self.ecx) && !matches!(s1.primitive(), Primitive::Pointer(..)) @@ -605,13 +584,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return None; } } - value.offset(Size::ZERO, to, &self.ecx).discard_err()? + value.offset(Size::ZERO, ty, &self.ecx).discard_err()? } CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) => { let src = self.evaluated[value].as_ref()?; - let to = self.ecx.layout_of(to).ok()?; - let dest = self.ecx.allocate(to, MemoryKind::Stack).discard_err()?; - self.ecx.unsize_into(src, to, &dest.clone().into()).discard_err()?; + let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; + self.ecx.unsize_into(src, ty, &dest.clone().into()).discard_err()?; self.ecx .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) .discard_err()?; @@ -620,15 +598,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { CastKind::FnPtrToPtr | CastKind::PtrToPtr => { let src = self.evaluated[value].as_ref()?; let src = self.ecx.read_immediate(src).discard_err()?; - let to = self.ecx.layout_of(to).ok()?; - let ret = self.ecx.ptr_to_ptr(&src, to).discard_err()?; + let ret = self.ecx.ptr_to_ptr(&src, ty).discard_err()?; ret.into() } CastKind::PointerCoercion(ty::adjustment::PointerCoercion::UnsafeFnPointer, _) => { let src = self.evaluated[value].as_ref()?; let src = self.ecx.read_immediate(src).discard_err()?; - let to = self.ecx.layout_of(to).ok()?; - ImmTy::from_immediate(*src, to).into() + ImmTy::from_immediate(*src, ty).into() } _ => return None, }, @@ -638,21 +614,20 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fn project( &mut self, - place: PlaceRef<'tcx>, + place_ty: PlaceTy<'tcx>, value: VnIndex, proj: PlaceElem<'tcx>, from_non_ssa_index: &mut bool, - ) -> Option { + ) -> Option<(PlaceTy<'tcx>, VnIndex)> { + let projection_ty = place_ty.projection_ty(self.tcx, proj); let proj = match proj { ProjectionElem::Deref => { - let ty = place.ty(self.local_decls, self.tcx).ty; - if let Some(Mutability::Not) = ty.ref_mutability() - && let Some(pointee_ty) = ty.builtin_deref(true) - && pointee_ty.is_freeze(self.tcx, self.typing_env()) + if let Some(Mutability::Not) = place_ty.ty.ref_mutability() + && projection_ty.ty.is_freeze(self.tcx, self.typing_env()) { // An immutable borrow `_x` always points to the same value for the // lifetime of the borrow, so we can merge all instances of `*_x`. - return Some(self.insert_deref(value)); + return Some((projection_ty, self.insert_deref(projection_ty.ty, value))); } else { return None; } @@ -660,7 +635,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ProjectionElem::Downcast(name, index) => ProjectionElem::Downcast(name, index), ProjectionElem::Field(f, ty) => { if let Value::Aggregate(_, _, fields) = self.get(value) { - return Some(fields[f.as_usize()]); + return Some((projection_ty, fields[f.as_usize()])); } else if let Value::Projection(outer_value, ProjectionElem::Downcast(_, read_variant)) = self.get(value) && let Value::Aggregate(_, written_variant, fields) = self.get(*outer_value) // This pass is not aware of control-flow, so we do not know whether the @@ -680,14 +655,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // a downcast to an inactive variant. && written_variant == read_variant { - return Some(fields[f.as_usize()]); + return Some((projection_ty, fields[f.as_usize()])); } ProjectionElem::Field(f, ty) } ProjectionElem::Index(idx) => { if let Value::Repeat(inner, _) = self.get(value) { *from_non_ssa_index |= self.locals[idx].is_none(); - return Some(*inner); + return Some((projection_ty, *inner)); } let idx = self.locals[idx]?; ProjectionElem::Index(idx) @@ -695,7 +670,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ProjectionElem::ConstantIndex { offset, min_length, from_end } => { match self.get(value) { Value::Repeat(inner, _) => { - return Some(*inner); + return Some((projection_ty, *inner)); } Value::Aggregate(AggregateTy::Array, _, operands) => { let offset = if from_end { @@ -703,7 +678,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } else { offset as usize }; - return operands.get(offset).copied(); + let value = operands.get(offset).copied()?; + return Some((projection_ty, value)); } _ => {} }; @@ -717,7 +693,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty), }; - Some(self.insert(Value::Projection(value, proj))) + let value = self.insert(projection_ty.ty, Value::Projection(value, proj)); + Some((projection_ty, value)) } /// Simplify the projection chain if we know better. @@ -779,6 +756,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Invariant: `value` holds the value up-to the `index`th projection excluded. let mut value = self.locals[place.local]?; + // Invariant: `value` has type `place_ty`, with optional downcast variant if needed. + let mut place_ty = PlaceTy::from_ty(self.local_decls[place.local].ty); let mut from_non_ssa_index = false; for (index, proj) in place.projection.iter().enumerate() { if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value) @@ -796,8 +775,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { place_ref = PlaceRef { local, projection: &place.projection[index..] }; } - let base = PlaceRef { local: place.local, projection: &place.projection[..index] }; - value = self.project(base, value, proj, &mut from_non_ssa_index)?; + (place_ty, value) = self.project(place_ty, value, proj, &mut from_non_ssa_index)?; } if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value) @@ -906,8 +884,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Unsupported values. Rvalue::ThreadLocalRef(..) | Rvalue::ShallowInitBox(..) => return None, }; - debug!(?value); - Some(self.insert(value)) + let ty = rvalue.ty(self.local_decls, self.tcx); + Some(self.insert(ty, value)) } fn simplify_discriminant(&mut self, place: VnIndex) -> Option { @@ -917,7 +895,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { { let enum_ty = self.tcx.type_of(enum_did).instantiate(self.tcx, enum_args); let discr = self.ecx.discriminant_for_variant(enum_ty, variant).discard_err()?; - return Some(self.insert_scalar(discr.to_scalar(), discr.layout.ty)); + return Some(self.insert_scalar(discr.layout.ty, discr.to_scalar())); } None @@ -1014,9 +992,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { rvalue: &mut Rvalue<'tcx>, location: Location, ) -> Option { + let tcx = self.tcx; + let ty = rvalue.ty(self.local_decls, tcx); + let Rvalue::Aggregate(box ref kind, ref mut field_ops) = *rvalue else { bug!() }; - let tcx = self.tcx; if field_ops.is_empty() { let is_zst = match *kind { AggregateKind::Array(..) @@ -1031,17 +1011,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { }; if is_zst { - let ty = rvalue.ty(self.local_decls, tcx); return Some(self.insert_constant(Const::zero_sized(ty))); } } let fields: Vec<_> = field_ops .iter_mut() - .map(|op| self.simplify_operand(op, location).unwrap_or_else(|| self.new_opaque())) + .map(|op| { + self.simplify_operand(op, location) + .unwrap_or_else(|| self.new_opaque(op.ty(self.local_decls, self.tcx))) + }) .collect(); - let (ty, variant_index) = match *kind { + let (aty, variant_index) = match *kind { AggregateKind::Array(..) => { assert!(!field_ops.is_empty()); (AggregateTy::Array, FIRST_VARIANT) @@ -1058,10 +1040,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // Do not track unions. AggregateKind::Adt(_, _, _, _, Some(_)) => return None, - AggregateKind::RawPtr(pointee_ty, mtbl) => { + AggregateKind::RawPtr(..) => { assert_eq!(field_ops.len(), 2); let mut data_pointer_ty = field_ops[FieldIdx::ZERO].ty(self.local_decls, self.tcx); - let output_pointer_ty = Ty::new_ptr(self.tcx, pointee_ty, mtbl); let [mut pointer, metadata] = fields.try_into().unwrap(); @@ -1074,7 +1055,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { to: _, } = self.get(pointer) && let ty::RawPtr(from_pointee_ty, from_mtbl) = cast_from.kind() - && let ty::RawPtr(_, output_mtbl) = output_pointer_ty.kind() + && let ty::RawPtr(_, output_mtbl) = ty.kind() && from_mtbl == output_mtbl && from_pointee_ty.is_sized(self.tcx, self.typing_env()) { @@ -1087,16 +1068,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { field_ops[FieldIdx::ZERO] = op; } - return Some(self.insert(Value::RawPtr { - output_pointer_ty, - data_pointer_ty, - pointer, - metadata, - })); + return Some(self.insert( + ty, + Value::RawPtr { output_pointer_ty: ty, data_pointer_ty, pointer, metadata }, + )); } }; - if let AggregateTy::Array = ty + if let AggregateTy::Array = aty && fields.len() > 4 { let first = fields[0]; @@ -1105,18 +1084,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if let Some(op) = self.try_as_operand(first, location) { *rvalue = Rvalue::Repeat(op, len); } - return Some(self.insert(Value::Repeat(first, len))); + return Some(self.insert(ty, Value::Repeat(first, len))); } } - if let AggregateTy::Def(_, _) = ty + if let AggregateTy::Def(_, _) = aty && let Some(value) = self.simplify_aggregate_to_copy(lhs, rvalue, location, &fields, variant_index) { return Some(value); } - Some(self.insert(Value::Aggregate(ty, variant_index, fields))) + Some(self.insert(ty, Value::Aggregate(aty, variant_index, fields))) } #[instrument(level = "trace", skip(self), ret)] @@ -1197,7 +1176,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } _ => Value::UnaryOp(op, arg_index), }; - Some(self.insert(value)) + let ty = op.ty(self.tcx, self.ty(arg_index)); + Some(self.insert(ty, value)) } #[instrument(level = "trace", skip(self), ret)] @@ -1243,8 +1223,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if let Some(value) = self.simplify_binary_inner(op, lhs_ty, lhs, rhs) { return Some(value); } + let ty = op.ty(self.tcx, self.ty(lhs), self.ty(rhs)); let value = Value::BinaryOp(op, lhs, rhs); - Some(self.insert(value)) + Some(self.insert(ty, value)) } fn simplify_binary_inner( @@ -1336,19 +1317,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { | BinOp::Shr, Left(0), _, - ) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty), + ) => self.insert_scalar(lhs_ty, Scalar::from_uint(0u128, layout.size)), // Attempt to simplify `x | ALL_ONES` to `ALL_ONES`. (BinOp::BitOr, _, Left(ones)) | (BinOp::BitOr, Left(ones), _) if ones == layout.size.truncate(u128::MAX) || (layout.ty.is_bool() && ones == 1) => { - self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty) + self.insert_scalar(lhs_ty, Scalar::from_uint(ones, layout.size)) } // Sub/Xor with itself. (BinOp::Sub | BinOp::SubWithOverflow | BinOp::SubUnchecked | BinOp::BitXor, a, b) if a == b => { - self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty) + self.insert_scalar(lhs_ty, Scalar::from_uint(0u128, layout.size)) } // Comparison: // - if both operands can be computed as bits, just compare the bits; @@ -1362,8 +1343,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { }; if op.is_overflowing() { + let ty = Ty::new_tup(self.tcx, &[self.ty(result), self.tcx.types.bool]); let false_val = self.insert_bool(false); - Some(self.insert_tuple(vec![result, false_val])) + Some(self.insert_tuple(ty, vec![result, false_val])) } else { Some(result) } @@ -1389,7 +1371,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if let CastKind::PointerCoercion(ReifyFnPointer | ClosureFnPointer(_), _) = kind { // Each reification of a generic fn may get a different pointer. // Do not try to merge them. - return Some(self.new_opaque()); + return Some(self.new_opaque(to)); } let mut was_ever_updated = false; @@ -1497,7 +1479,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { *initial_kind = kind; } - Some(self.insert(Value::Cast { kind, value, from, to })) + Some(self.insert(to, Value::Cast { kind, value, from, to })) } fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option { @@ -1530,7 +1512,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // Fallback: a symbolic `Len`. - Some(self.insert(Value::Len(inner))) + Some(self.insert(self.tcx.types.usize, Value::Len(inner))) } fn pointers_have_same_metadata(&self, left_ptr_ty: Ty<'tcx>, right_ptr_ty: Ty<'tcx>) -> bool { @@ -1807,11 +1789,12 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { if let Some(local) = lhs.as_local() && self.ssa.is_ssa(local) + && let rvalue_ty = rvalue.ty(self.local_decls, self.tcx) // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark // `local` as reusable if we have an exact type match. - && self.local_decls[local].ty == rvalue.ty(self.local_decls, self.tcx) + && self.local_decls[local].ty == rvalue_ty { - let value = value.unwrap_or_else(|| self.new_opaque()); + let value = value.unwrap_or_else(|| self.new_opaque(rvalue_ty)); self.assign(local, value); } } @@ -1821,7 +1804,8 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { if let Some(local) = destination.as_local() && self.ssa.is_ssa(local) { - let opaque = self.new_opaque(); + let ty = self.local_decls[local].ty; + let opaque = self.new_opaque(ty); self.assign(local, opaque); } } diff --git a/tests/mir-opt/const_prop/transmute.rs b/tests/mir-opt/const_prop/transmute.rs index 892b91a5414c..33cbefbf053f 100644 --- a/tests/mir-opt/const_prop/transmute.rs +++ b/tests/mir-opt/const_prop/transmute.rs @@ -56,7 +56,7 @@ pub unsafe fn undef_union_as_integer() -> u32 { pub unsafe fn unreachable_direct() -> ! { // CHECK-LABEL: fn unreachable_direct( // CHECK: = const (); - // CHECK: = const () as Never (Transmute); + // CHECK: = const ZeroSized: Never; let x: Never = unsafe { transmute(()) }; match x {} } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff index 3364782022dc..5aeb55a5a6a5 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff @@ -15,7 +15,7 @@ - _2 = (); - _1 = move _2 as Never (Transmute); + _2 = const (); -+ _1 = const () as Never (Transmute); ++ _1 = const ZeroSized: Never; unreachable; } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff index 3364782022dc..5aeb55a5a6a5 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff @@ -15,7 +15,7 @@ - _2 = (); - _1 = move _2 as Never (Transmute); + _2 = const (); -+ _1 = const () as Never (Transmute); ++ _1 = const ZeroSized: Never; unreachable; } } diff --git a/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-abort.diff b/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-abort.diff index 770c67307753..ffe4a0272b4b 100644 --- a/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-abort.diff @@ -18,7 +18,8 @@ bb0: { _4 = copy _1 as *const T (PtrToPtr); - _5 = PtrMetadata(copy _4); +- _5 = PtrMetadata(copy _4); ++ _5 = const (); _6 = copy _1 as *const (&A, [T]) (PtrToPtr); - _7 = PtrMetadata(copy _6); + _7 = PtrMetadata(copy _1); diff --git a/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-unwind.diff b/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-unwind.diff index 770c67307753..ffe4a0272b4b 100644 --- a/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-unwind.diff @@ -18,7 +18,8 @@ bb0: { _4 = copy _1 as *const T (PtrToPtr); - _5 = PtrMetadata(copy _4); +- _5 = PtrMetadata(copy _4); ++ _5 = const (); _6 = copy _1 as *const (&A, [T]) (PtrToPtr); - _7 = PtrMetadata(copy _6); + _7 = PtrMetadata(copy _1); diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 6ef320c90de1..5d348bc3c1e4 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -869,7 +869,7 @@ fn generic_cast_metadata(ps: *const [T], pa: *const A, // Metadata usize -> (), do not optimize. // CHECK: [[T:_.+]] = copy _1 as - // CHECK-NEXT: PtrMetadata(copy [[T]]) + // CHECK-NEXT: const (); let t1 = CastPtrToPtr::<_, *const T>(ps); let m1 = PtrMetadata(t1); From 4750dff54eab52a308a1a1afd85b4614d652841a Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 30 Jun 2025 19:50:11 +0000 Subject: [PATCH 018/363] Remove extraneous types. --- compiler/rustc_mir_transform/src/gvn.rs | 209 +++++++----------- ...ted_loop.PreCodegen.after.panic-unwind.mir | 5 +- 2 files changed, 80 insertions(+), 134 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 3e4c05b355f6..e081d1fde93b 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -105,7 +105,6 @@ use rustc_middle::mir::*; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; -use rustc_span::def_id::DefId; use smallvec::SmallVec; use tracing::{debug, instrument, trace}; @@ -155,16 +154,6 @@ newtype_index! { struct VnIndex {} } -/// Computing the aggregate's type can be quite slow, so we only keep the minimal amount of -/// information to reconstruct it when needed. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -enum AggregateTy<'tcx> { - /// Invariant: this must not be used for an empty array. - Array, - Tuple, - Def(DefId, ty::GenericArgsRef<'tcx>), -} - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] enum AddressKind { Ref(BorrowKind), @@ -187,17 +176,13 @@ enum Value<'tcx> { }, /// An aggregate value, either tuple/closure/struct/enum. /// This does not contain unions, as we cannot reason with the value. - Aggregate(AggregateTy<'tcx>, VariantIdx, Vec), + Aggregate(VariantIdx, Vec), /// A raw pointer aggregate built from a thin pointer and metadata. RawPtr { /// Thin pointer component. This is field 0 in MIR. pointer: VnIndex, /// Metadata component. This is field 1 in MIR. metadata: VnIndex, - /// Needed for cast propagation. - data_pointer_ty: Ty<'tcx>, - /// The data pointer can be anything thin, so doesn't determine the output. - output_pointer_ty: Ty<'tcx>, }, /// This corresponds to a `[value; count]` expression. Repeat(VnIndex, ty::Const<'tcx>), @@ -211,7 +196,7 @@ enum Value<'tcx> { // Extractions. /// This is the *value* obtained by projecting another value. - Projection(VnIndex, ProjectionElem>), + Projection(VnIndex, ProjectionElem), /// Discriminant of the given value. Discriminant(VnIndex), /// Length of an array or slice. @@ -224,8 +209,6 @@ enum Value<'tcx> { Cast { kind: CastKind, value: VnIndex, - from: Ty<'tcx>, - to: Ty<'tcx>, }, } @@ -377,7 +360,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } fn insert_tuple(&mut self, ty: Ty<'tcx>, values: Vec) -> VnIndex { - self.insert(ty, Value::Aggregate(AggregateTy::Tuple, VariantIdx::ZERO, values)) + self.insert(ty, Value::Aggregate(VariantIdx::ZERO, values)) } fn insert_deref(&mut self, ty: Ty<'tcx>, value: VnIndex) -> VnIndex { @@ -408,7 +391,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Constant { ref value, disambiguator: _ } => { self.ecx.eval_mir_constant(value, DUMMY_SP, None).discard_err()? } - Aggregate(_, variant, ref fields) => { + Aggregate(variant, ref fields) => { let fields = fields .iter() .map(|&f| self.evaluated[f].as_ref()) @@ -440,7 +423,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return None; } } - RawPtr { pointer, metadata, output_pointer_ty: _, data_pointer_ty: _ } => { + RawPtr { pointer, metadata } => { let pointer = self.evaluated[pointer].as_ref()?; let metadata = self.evaluated[metadata].as_ref()?; @@ -456,28 +439,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } Projection(base, elem) => { - let value = self.evaluated[base].as_ref()?; + let base = self.evaluated[base].as_ref()?; let elem = match elem { ProjectionElem::Deref => ProjectionElem::Deref, ProjectionElem::Downcast(name, read_variant) => { ProjectionElem::Downcast(name, read_variant) } - ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty), + ProjectionElem::Field(f, ()) => ProjectionElem::Field(f, ty.ty), ProjectionElem::ConstantIndex { offset, min_length, from_end } => { ProjectionElem::ConstantIndex { offset, min_length, from_end } } ProjectionElem::Subslice { from, to, from_end } => { ProjectionElem::Subslice { from, to, from_end } } - ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty), - ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty), - ProjectionElem::UnwrapUnsafeBinder(ty) => { - ProjectionElem::UnwrapUnsafeBinder(ty) + ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty.ty), + ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty.ty), + ProjectionElem::UnwrapUnsafeBinder(()) => { + ProjectionElem::UnwrapUnsafeBinder(ty.ty) } // This should have been replaced by a `ConstantIndex` earlier. ProjectionElem::Index(_) => return None, }; - self.ecx.project(value, elem).discard_err()? + self.ecx.project(base, elem).discard_err()? } Address { place, kind: _, provenance: _ } => { if !place.is_indirect_first_projection() { @@ -544,7 +527,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let val = self.ecx.binary_op(bin_op, &lhs, &rhs).discard_err()?; val.into() } - Cast { kind, value, from: _, to: _ } => match kind { + Cast { kind, value } => match kind { CastKind::IntToInt | CastKind::IntToFloat => { let value = self.evaluated[value].as_ref()?; let value = self.ecx.read_immediate(value).discard_err()?; @@ -633,11 +616,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } ProjectionElem::Downcast(name, index) => ProjectionElem::Downcast(name, index), - ProjectionElem::Field(f, ty) => { - if let Value::Aggregate(_, _, fields) = self.get(value) { + ProjectionElem::Field(f, _) => { + if let Value::Aggregate(_, fields) = self.get(value) { return Some((projection_ty, fields[f.as_usize()])); } else if let Value::Projection(outer_value, ProjectionElem::Downcast(_, read_variant)) = self.get(value) - && let Value::Aggregate(_, written_variant, fields) = self.get(*outer_value) + && let Value::Aggregate(written_variant, fields) = self.get(*outer_value) // This pass is not aware of control-flow, so we do not know whether the // replacement we are doing is actually reachable. We could be in any arm of // ``` @@ -657,7 +640,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { { return Some((projection_ty, fields[f.as_usize()])); } - ProjectionElem::Field(f, ty) + ProjectionElem::Field(f, ()) } ProjectionElem::Index(idx) => { if let Value::Repeat(inner, _) = self.get(value) { @@ -672,7 +655,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Value::Repeat(inner, _) => { return Some((projection_ty, *inner)); } - Value::Aggregate(AggregateTy::Array, _, operands) => { + Value::Aggregate(_, operands) => { let offset = if from_end { operands.len() - offset as usize } else { @@ -688,9 +671,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ProjectionElem::Subslice { from, to, from_end } => { ProjectionElem::Subslice { from, to, from_end } } - ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty), - ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty), - ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty), + ProjectionElem::OpaqueCast(_) => ProjectionElem::OpaqueCast(()), + ProjectionElem::Subtype(_) => ProjectionElem::Subtype(()), + ProjectionElem::UnwrapUnsafeBinder(_) => ProjectionElem::UnwrapUnsafeBinder(()), }; let value = self.insert(projection_ty.ty, Value::Projection(value, proj)); @@ -852,14 +835,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { self.simplify_place_projection(place, location); return Some(self.new_pointer(*place, AddressKind::Address(mutbl))); } - Rvalue::WrapUnsafeBinder(ref mut op, ty) => { + Rvalue::WrapUnsafeBinder(ref mut op, _) => { let value = self.simplify_operand(op, location)?; - Value::Cast { - kind: CastKind::Transmute, - value, - from: op.ty(self.local_decls, self.tcx), - to: ty, - } + Value::Cast { kind: CastKind::Transmute, value } } // Operations. @@ -889,11 +867,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } fn simplify_discriminant(&mut self, place: VnIndex) -> Option { - if let Value::Aggregate(enum_ty, variant, _) = *self.get(place) - && let AggregateTy::Def(enum_did, enum_args) = enum_ty - && let DefKind::Enum = self.tcx.def_kind(enum_did) + let enum_ty = self.ty(place); + if enum_ty.is_enum() + && let Value::Aggregate(variant, _) = *self.get(place) { - let enum_ty = self.tcx.type_of(enum_did).instantiate(self.tcx, enum_args); let discr = self.ecx.discriminant_for_variant(enum_ty, variant).discard_err()?; return Some(self.insert_scalar(discr.layout.ty, discr.to_scalar())); } @@ -903,12 +880,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fn try_as_place_elem( &mut self, - proj: ProjectionElem>, + ty: Ty<'tcx>, + proj: ProjectionElem, loc: Location, ) -> Option> { Some(match proj { ProjectionElem::Deref => ProjectionElem::Deref, - ProjectionElem::Field(idx, ty) => ProjectionElem::Field(idx, ty), + ProjectionElem::Field(idx, ()) => ProjectionElem::Field(idx, ty), ProjectionElem::Index(idx) => { let Some(local) = self.try_as_local(idx, loc) else { return None; @@ -923,9 +901,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ProjectionElem::Subslice { from, to, from_end } } ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx), - ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx), - ProjectionElem::Subtype(idx) => ProjectionElem::Subtype(idx), - ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty), + ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty), + ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty), + ProjectionElem::UnwrapUnsafeBinder(()) => ProjectionElem::UnwrapUnsafeBinder(ty), }) } @@ -971,8 +949,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Allow introducing places with non-constant offsets, as those are still better than // reconstructing an aggregate. - if let Some(place) = self.try_as_place(copy_from_local_value, location, true) - && rvalue.ty(self.local_decls, self.tcx) == place.ty(self.local_decls, self.tcx).ty + if self.ty(copy_from_local_value) == rvalue.ty(self.local_decls, self.tcx) + && let Some(place) = self.try_as_place(copy_from_local_value, location, true) { // Avoid creating `*a = copy (*b)`, as they might be aliases resulting in overlapping assignments. // FIXME: This also avoids any kind of projection, not just derefs. We can add allowed projections. @@ -1023,44 +1001,31 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { }) .collect(); - let (aty, variant_index) = match *kind { - AggregateKind::Array(..) => { + let variant_index = match *kind { + AggregateKind::Array(..) | AggregateKind::Tuple => { assert!(!field_ops.is_empty()); - (AggregateTy::Array, FIRST_VARIANT) - } - AggregateKind::Tuple => { - assert!(!field_ops.is_empty()); - (AggregateTy::Tuple, FIRST_VARIANT) - } - AggregateKind::Closure(did, args) - | AggregateKind::CoroutineClosure(did, args) - | AggregateKind::Coroutine(did, args) => (AggregateTy::Def(did, args), FIRST_VARIANT), - AggregateKind::Adt(did, variant_index, args, _, None) => { - (AggregateTy::Def(did, args), variant_index) + FIRST_VARIANT } + AggregateKind::Closure(..) + | AggregateKind::CoroutineClosure(..) + | AggregateKind::Coroutine(..) => FIRST_VARIANT, + AggregateKind::Adt(_, variant_index, _, _, None) => variant_index, // Do not track unions. AggregateKind::Adt(_, _, _, _, Some(_)) => return None, AggregateKind::RawPtr(..) => { assert_eq!(field_ops.len(), 2); - let mut data_pointer_ty = field_ops[FieldIdx::ZERO].ty(self.local_decls, self.tcx); - let [mut pointer, metadata] = fields.try_into().unwrap(); // Any thin pointer of matching mutability is fine as the data pointer. let mut was_updated = false; - while let Value::Cast { - kind: CastKind::PtrToPtr, - value: cast_value, - from: cast_from, - to: _, - } = self.get(pointer) - && let ty::RawPtr(from_pointee_ty, from_mtbl) = cast_from.kind() + while let Value::Cast { kind: CastKind::PtrToPtr, value: cast_value } = + self.get(pointer) + && let ty::RawPtr(from_pointee_ty, from_mtbl) = self.ty(*cast_value).kind() && let ty::RawPtr(_, output_mtbl) = ty.kind() && from_mtbl == output_mtbl && from_pointee_ty.is_sized(self.tcx, self.typing_env()) { pointer = *cast_value; - data_pointer_ty = *cast_from; was_updated = true; } @@ -1068,16 +1033,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { field_ops[FieldIdx::ZERO] = op; } - return Some(self.insert( - ty, - Value::RawPtr { output_pointer_ty: ty, data_pointer_ty, pointer, metadata }, - )); + return Some(self.insert(ty, Value::RawPtr { pointer, metadata })); } }; - if let AggregateTy::Array = aty - && fields.len() > 4 - { + if ty.is_array() && fields.len() > 4 { let first = fields[0]; if fields.iter().all(|&v| v == first) { let len = ty::Const::from_target_usize(self.tcx, fields.len().try_into().unwrap()); @@ -1088,14 +1048,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } - if let AggregateTy::Def(_, _) = aty - && let Some(value) = - self.simplify_aggregate_to_copy(lhs, rvalue, location, &fields, variant_index) + if let Some(value) = + self.simplify_aggregate_to_copy(lhs, rvalue, location, &fields, variant_index) { return Some(value); } - Some(self.insert(ty, Value::Aggregate(aty, variant_index, fields))) + Some(self.insert(ty, Value::Aggregate(variant_index, fields))) } #[instrument(level = "trace", skip(self), ret)] @@ -1106,6 +1065,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { location: Location, ) -> Option { let mut arg_index = self.simplify_operand(arg_op, location)?; + let arg_ty = self.ty(arg_index); + let ret_ty = op.ty(self.tcx, arg_ty); // PtrMetadata doesn't care about *const vs *mut vs & vs &mut, // so start by removing those distinctions so we can update the `Operand` @@ -1121,8 +1082,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // we can't always know exactly what the metadata are. // To allow things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`, // it's fine to get a projection as the type. - Value::Cast { kind: CastKind::PtrToPtr, value: inner, from, to } - if self.pointers_have_same_metadata(*from, *to) => + Value::Cast { kind: CastKind::PtrToPtr, value: inner } + if self.pointers_have_same_metadata(self.ty(*inner), arg_ty) => { arg_index = *inner; was_updated = true; @@ -1165,19 +1126,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { UnOp::PtrMetadata, Value::Cast { kind: CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _), - from, - to, - .. + value: inner, }, - ) if let ty::Slice(..) = to.builtin_deref(true).unwrap().kind() - && let ty::Array(_, len) = from.builtin_deref(true).unwrap().kind() => + ) if let ty::Slice(..) = arg_ty.builtin_deref(true).unwrap().kind() + && let ty::Array(_, len) = self.ty(*inner).builtin_deref(true).unwrap().kind() => { return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); } _ => Value::UnaryOp(op, arg_index), }; - let ty = op.ty(self.tcx, self.ty(arg_index)); - Some(self.insert(ty, value)) + Some(self.insert(ret_ty, value)) } #[instrument(level = "trace", skip(self), ret)] @@ -1190,25 +1148,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ) -> Option { let lhs = self.simplify_operand(lhs_operand, location); let rhs = self.simplify_operand(rhs_operand, location); + // Only short-circuit options after we called `simplify_operand` // on both operands for side effect. let mut lhs = lhs?; let mut rhs = rhs?; - let lhs_ty = lhs_operand.ty(self.local_decls, self.tcx); + let lhs_ty = self.ty(lhs); // If we're comparing pointers, remove `PtrToPtr` casts if the from // types of both casts and the metadata all match. if let BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge = op && lhs_ty.is_any_ptr() - && let Value::Cast { - kind: CastKind::PtrToPtr, value: lhs_value, from: lhs_from, .. - } = self.get(lhs) - && let Value::Cast { - kind: CastKind::PtrToPtr, value: rhs_value, from: rhs_from, .. - } = self.get(rhs) - && lhs_from == rhs_from - && self.pointers_have_same_metadata(*lhs_from, lhs_ty) + && let Value::Cast { kind: CastKind::PtrToPtr, value: lhs_value } = self.get(lhs) + && let Value::Cast { kind: CastKind::PtrToPtr, value: rhs_value } = self.get(rhs) + && let lhs_from = self.ty(*lhs_value) + && lhs_from == self.ty(*rhs_value) + && self.pointers_have_same_metadata(lhs_from, lhs_ty) { lhs = *lhs_value; rhs = *rhs_value; @@ -1223,7 +1179,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if let Some(value) = self.simplify_binary_inner(op, lhs_ty, lhs, rhs) { return Some(value); } - let ty = op.ty(self.tcx, self.ty(lhs), self.ty(rhs)); + let ty = op.ty(self.tcx, lhs_ty, self.ty(rhs)); let value = Value::BinaryOp(op, lhs, rhs); Some(self.insert(ty, value)) } @@ -1361,9 +1317,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { use CastKind::*; use rustc_middle::ty::adjustment::PointerCoercion::*; - let mut from = initial_operand.ty(self.local_decls, self.tcx); let mut kind = *initial_kind; let mut value = self.simplify_operand(initial_operand, location)?; + let mut from = self.ty(value); if from == to { return Some(value); } @@ -1394,14 +1350,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // If a cast just casts away the metadata again, then we can get it by // casting the original thin pointer passed to `from_raw_parts` if let PtrToPtr = kind - && let Value::RawPtr { data_pointer_ty, pointer, .. } = self.get(value) + && let Value::RawPtr { pointer, .. } = self.get(value) && let ty::RawPtr(to_pointee, _) = to.kind() && to_pointee.is_sized(self.tcx, self.typing_env()) { - from = *data_pointer_ty; + from = self.ty(*pointer); value = *pointer; was_updated_this_iteration = true; - if *data_pointer_ty == to { + if from == to { return Some(*pointer); } } @@ -1409,7 +1365,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Aggregate-then-Transmute can just transmute the original field value, // so long as the bytes of a value from only from a single field. if let Transmute = kind - && let Value::Aggregate(_aggregate_ty, variant_idx, field_values) = self.get(value) + && let Value::Aggregate(variant_idx, field_values) = self.get(value) && let Some((field_idx, field_ty)) = self.value_is_all_in_one_field(from, *variant_idx) { @@ -1422,13 +1378,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // Various cast-then-cast cases can be simplified. - if let Value::Cast { - kind: inner_kind, - value: inner_value, - from: inner_from, - to: inner_to, - } = *self.get(value) - { + if let Value::Cast { kind: inner_kind, value: inner_value } = *self.get(value) { + let inner_from = self.ty(inner_value); let new_kind = match (inner_kind, kind) { // Even if there's a narrowing cast in here that's fine, because // things like `*mut [i32] -> *mut i32 -> *const i32` and @@ -1437,9 +1388,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // PtrToPtr-then-Transmute is fine so long as the pointer cast is identity: // `*const T -> *mut T -> NonNull` is fine, but we need to check for narrowing // to skip things like `*const [i32] -> *const i32 -> NonNull`. - (PtrToPtr, Transmute) - if self.pointers_have_same_metadata(inner_from, inner_to) => - { + (PtrToPtr, Transmute) if self.pointers_have_same_metadata(inner_from, from) => { Some(Transmute) } // Similarly, for Transmute-then-PtrToPtr. Note that we need to check different @@ -1450,7 +1399,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // If would be legal to always do this, but we don't want to hide information // from the backend that it'd otherwise be able to use for optimizations. (Transmute, Transmute) - if !self.type_may_have_niche_of_interest_to_backend(inner_to) => + if !self.type_may_have_niche_of_interest_to_backend(from) => { Some(Transmute) } @@ -1479,7 +1428,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { *initial_kind = kind; } - Some(self.insert(to, Value::Cast { kind, value, from, to })) + Some(self.insert(to, Value::Cast { kind, value })) } fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option { @@ -1501,11 +1450,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // We have an unsizing cast, which assigns the length to wide pointer metadata. - if let Value::Cast { kind, from, to, .. } = self.get(inner) + if let Value::Cast { kind, value: from } = self.get(inner) && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind - && let Some(from) = from.builtin_deref(true) + && let Some(from) = self.ty(*from).builtin_deref(true) && let ty::Array(_, len) = from.kind() - && let Some(to) = to.builtin_deref(true) + && let Some(to) = self.ty(inner).builtin_deref(true) && let ty::Slice(..) = to.kind() { return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); @@ -1721,7 +1670,7 @@ impl<'tcx> VnState<'_, 'tcx> { return Some(place); } else if let Value::Projection(pointer, proj) = *self.get(index) && (allow_complex_projection || proj.is_stable_offset()) - && let Some(proj) = self.try_as_place_elem(proj, loc) + && let Some(proj) = self.try_as_place_elem(self.ty(index), proj, loc) { projection.push(proj); index = pointer; diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index 3b58f1d61f4b..8c5fbda63921 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -109,7 +109,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb4: { - StorageLive(_15); _14 = &mut _13; _15 = > as Iterator>::next(move _14) -> [return: bb5, unwind: bb11]; } @@ -120,7 +119,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb6: { - StorageDead(_15); StorageDead(_13); drop(_2) -> [return: bb7, unwind continue]; } @@ -135,14 +133,13 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageLive(_19); _19 = &_2; StorageLive(_20); - _20 = (copy _17, copy _18); + _20 = copy ((_15 as Some).0: (usize, &T)); _21 = >::call(move _19, move _20) -> [return: bb9, unwind: bb11]; } bb9: { StorageDead(_20); StorageDead(_19); - StorageDead(_15); goto -> bb4; } From cbc3cf716e16c20ba8fb652f8a41dc1d62f03f66 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 1 Jul 2025 12:06:39 +0000 Subject: [PATCH 019/363] Avoid computing layouts inside coroutines. --- compiler/rustc_mir_transform/src/gvn.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index e081d1fde93b..461aa7e5284f 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -216,6 +216,7 @@ struct VnState<'body, 'tcx> { tcx: TyCtxt<'tcx>, ecx: InterpCx<'tcx, DummyMachine>, local_decls: &'body LocalDecls<'tcx>, + is_coroutine: bool, /// Value stored in each local. locals: IndexVec>, /// Locals that are assigned that value. @@ -253,6 +254,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { tcx, ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), local_decls, + is_coroutine: body.coroutine.is_some(), locals: IndexVec::from_elem(None, local_decls), rev_locals: IndexVec::with_capacity(num_values), values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()), @@ -380,7 +382,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fn eval_to_const(&mut self, value: VnIndex) -> Option> { use Value::*; let ty = self.ty(value); - let ty = self.ecx.layout_of(ty).ok()?; + // Avoid computing layouts inside a coroutine, as that can cause cycles. + let ty = if !self.is_coroutine || ty.is_scalar() { + self.ecx.layout_of(ty).ok()? + } else { + return None; + }; let op = match *self.get(value) { _ if ty.is_zst() => ImmTy::uninit(ty).into(), From c42b1773feb5808ae870f8b578a4a8601c7bd322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nurzhan=20Sak=C3=A9n?= Date: Tue, 1 Jul 2025 17:02:32 +0400 Subject: [PATCH 020/363] Add `uX::strict_sub_signed` --- library/core/src/num/uint_macros.rs | 45 ++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 079032f2f96d..cf34ab8a3cdb 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -556,7 +556,7 @@ macro_rules! uint_impl { pub const fn strict_add(self, rhs: Self) -> Self { let (a, b) = self.overflowing_add(rhs); if b { overflow_panic::add() } else { a } - } + } /// Unchecked integer addition. Computes `self + rhs`, assuming overflow /// cannot occur. @@ -653,7 +653,7 @@ macro_rules! uint_impl { pub const fn strict_add_signed(self, rhs: $SignedT) -> Self { let (a, b) = self.overflowing_add_signed(rhs); if b { overflow_panic::add() } else { a } - } + } /// Checked integer subtraction. Computes `self - rhs`, returning /// `None` if overflow occurred. @@ -713,7 +713,7 @@ macro_rules! uint_impl { pub const fn strict_sub(self, rhs: Self) -> Self { let (a, b) = self.overflowing_sub(rhs); if b { overflow_panic::sub() } else { a } - } + } /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow /// cannot occur. @@ -805,6 +805,43 @@ macro_rules! uint_impl { } } + /// Strict subtraction with a signed integer. Computes `self - rhs`, + /// panicking if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".strict_sub_signed(2), 1);")] + /// ``` + /// + /// The following panic because of overflow: + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_sub_signed(2);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub_signed(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_sub_signed(self, rhs: $SignedT) -> Self { + let (a, b) = self.overflowing_sub_signed(rhs); + if b { overflow_panic::sub() } else { a } + } + #[doc = concat!( "Checked integer subtraction. Computes `self - rhs` and checks if the result fits into an [`", stringify!($SignedT), "`], returning `None` if overflow occurred." @@ -913,7 +950,7 @@ macro_rules! uint_impl { pub const fn strict_mul(self, rhs: Self) -> Self { let (a, b) = self.overflowing_mul(rhs); if b { overflow_panic::mul() } else { a } - } + } /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow /// cannot occur. From 79ed7c1f415f40b3167d946c4a292b84b92eede5 Mon Sep 17 00:00:00 2001 From: Nurzhan Saken Date: Tue, 1 Jul 2025 22:32:19 +0400 Subject: [PATCH 021/363] Test upper overflow in `strict_sub_signed` Co-authored-by: zachs18 <8355914+zachs18@users.noreply.github.com> --- library/core/src/num/uint_macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index cf34ab8a3cdb..78002593b63e 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -830,7 +830,7 @@ macro_rules! uint_impl { /// /// ```should_panic /// #![feature(strict_overflow_ops)] - #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub_signed(3);")] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX).strict_sub_signed(-1);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ From 1d2b874b847e2d59a7deb639ef79999b87ee2837 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 1 Jul 2025 18:29:17 -0400 Subject: [PATCH 022/363] Remove OVERWRITE_TARGET_TRIPLE env var now that config.sh is gone --- .github/workflows/m68k.yml | 13 ++++++++++--- build_system/src/config.rs | 12 ++++++++---- doc/tips.md | 4 ++-- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 245bee7f2a3b..4a8ccebaf797 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -14,8 +14,6 @@ permissions: env: # Enable backtraces for easier debugging RUST_BACKTRACE: 1 - # TODO: remove when confish.sh is removed. - OVERWRITE_TARGET_TRIPLE: m68k-unknown-linux-gnu jobs: build: @@ -106,7 +104,16 @@ jobs: - name: Run tests run: | - ./y.sh test --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }} + ./y.sh test--target-triple m68k-unknown-linux-gnu --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }} + + - name: Run Hello World! + run: | + ./y.sh build --target-triple m68k-unknown-linux-gnu + + cd tests/hello-world + ../../y.sh cargo build --target m68k-unknown-linux-gnu + ../../y.sh cargo run --target m68k-unknown-linux-gnu > hello_world_stdout + test $(cat hello_world_stdout) == "Hello, world!" || exit 1 # Summary job for the merge queue. # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 650c030ca539..121c43822fdb 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -352,10 +352,14 @@ impl ConfigInfo { None => return Err("no host found".to_string()), }; - if self.target_triple.is_empty() - && let Some(overwrite) = env.get("OVERWRITE_TARGET_TRIPLE") - { - self.target_triple = overwrite.clone(); + if self.target_triple.is_empty() { + // TODO: set target triple. + // TODO: why do we even need to set target_triple? + // It seems to only be needed for the linker (we could add an environment variable to + // remove this need) and the sysroot (perhaps we could find another way to find it). + // TODO TODO: seems like we would still need OVERWRITE_TARGET_TRIPLE when using a + // json spec file. + // ====> maybe not since we specify both --target and --target-triple. } if self.target_triple.is_empty() { self.target_triple = self.host_triple.clone(); diff --git a/doc/tips.md b/doc/tips.md index 86c22db186e0..4ab135f3df66 100644 --- a/doc/tips.md +++ b/doc/tips.md @@ -63,13 +63,13 @@ generate it in [gimple.md](./doc/gimple.md). * Run `./y.sh prepare --cross` so that the sysroot is patched for the cross-compiling case. * Set the path to the cross-compiling libgccjit in `gcc-path` (in `config.toml`). * Make sure you have the linker for your target (for instance `m68k-unknown-linux-gnu-gcc`) in your `$PATH`. Currently, the linker name is hardcoded as being `$TARGET-gcc`. Specify the target when building the sysroot: `./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu`. - * Build your project by specifying the target: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../y.sh cargo build --target m68k-unknown-linux-gnu`. + * Build your project by specifying the target: `../y.sh cargo build --target m68k-unknown-linux-gnu`. If the target is not yet supported by the Rust compiler, create a [target specification file](https://docs.rust-embedded.org/embedonomicon/custom-target.html) (note that the `arch` specified in this file must be supported by the rust compiler). Then, you can use it the following way: * Add the target specification file using `--target` as an **absolute** path to build the sysroot: `./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu --target $(pwd)/m68k-unknown-linux-gnu.json` - * Build your project by specifying the target specification file: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../y.sh cargo build --target path/to/m68k-unknown-linux-gnu.json`. + * Build your project by specifying the target specification file: `../y.sh cargo build --target path/to/m68k-unknown-linux-gnu.json`. If you get the following error: From 1bbe5946f231b4c05818fb18f9252b68af251498 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 1 Jul 2025 18:50:39 -0400 Subject: [PATCH 023/363] Fix installation of libgccjit for m68k --- .github/workflows/m68k.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 4a8ccebaf797..04e09dc7b8cc 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -57,7 +57,7 @@ jobs: - name: Setup path to libgccjit run: | - sudo dpkg -i gcc-m68k-15.deb + sudo dpkg --force-overwrite -i gcc-m68k-15.deb echo 'gcc-path = "/usr/lib/"' > config.toml - name: Set env From 89f0cb3bfc97473a33cb5ae073be6073fa0931b9 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 1 Jul 2025 19:03:08 -0400 Subject: [PATCH 024/363] Specify linker in m68k CI --- .github/workflows/m68k.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 04e09dc7b8cc..249fb965be17 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -63,8 +63,6 @@ jobs: - name: Set env run: | echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - - #- name: Cache rust repository ## We only clone the rust repository for rustc tests @@ -85,7 +83,7 @@ jobs: run: | ./y.sh prepare --only-libcore --cross ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json - ./y.sh cargo build --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json + CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ./y.sh cargo build --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json ./y.sh clean all - name: Build From cf509d87d909c551c942b315ac16f2722a71db2e Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 1 Jul 2025 19:17:18 -0400 Subject: [PATCH 025/363] Add missing --target-triple flags in m68k CI --- .github/workflows/m68k.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 249fb965be17..b78f17c0e26b 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -90,8 +90,8 @@ jobs: run: | ./y.sh prepare --only-libcore --cross ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu - ./y.sh test --mini-tests - CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu ./y.sh test --cargo-tests + ./y.sh test --mini-tests --target-triple m68k-unknown-linux-gnu + CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu ./y.sh test --cargo-tests --target-triple m68k-unknown-linux-gnu ./y.sh clean all - name: Prepare dependencies From fec79b86a2fb9f7086229d1b94bafd204eec6c27 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 1 Jul 2025 19:35:39 -0400 Subject: [PATCH 026/363] Add missing space before --target-triple --- .github/workflows/m68k.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index b78f17c0e26b..511e2ff3dec8 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -102,7 +102,7 @@ jobs: - name: Run tests run: | - ./y.sh test--target-triple m68k-unknown-linux-gnu --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }} + ./y.sh test --target-triple m68k-unknown-linux-gnu --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }} - name: Run Hello World! run: | From 3021598bdfc5adec0e71401a191e780bdc0060fb Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 1 Jul 2025 19:44:00 -0400 Subject: [PATCH 027/363] Specify the linker when building the test project in m68k CI --- .github/workflows/m68k.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 511e2ff3dec8..5f347498f325 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -109,8 +109,8 @@ jobs: ./y.sh build --target-triple m68k-unknown-linux-gnu cd tests/hello-world - ../../y.sh cargo build --target m68k-unknown-linux-gnu - ../../y.sh cargo run --target m68k-unknown-linux-gnu > hello_world_stdout + CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../../y.sh cargo build --target m68k-unknown-linux-gnu + CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../../y.sh cargo run --target m68k-unknown-linux-gnu > hello_world_stdout test $(cat hello_world_stdout) == "Hello, world!" || exit 1 # Summary job for the merge queue. From 5773d38c7a7d522e6d867de1e57375d129ae478e Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Mon, 30 Jun 2025 14:29:59 +0000 Subject: [PATCH 028/363] fix: Fix TypePrintFn flag passing for autodiff codegen Signed-off-by: Karan Janthe --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 13 +++++++++++++ src/tools/enzyme | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index d4a05fbbbc5d..7771b41bd66a 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -700,6 +700,10 @@ struct LLVMRustSanitizerOptions { #ifdef ENZYME extern "C" void registerEnzymeAndPassPipeline(llvm::PassBuilder &PB, /* augmentPassBuilder */ bool); + +extern "C" { +extern llvm::cl::opt EnzymeFunctionToAnalyze; +} #endif extern "C" LLVMRustResult LLVMRustOptimize( @@ -1069,6 +1073,15 @@ extern "C" LLVMRustResult LLVMRustOptimize( return LLVMRustResult::Failure; } + // Check if PrintTAFn was used and add type analysis pass if needed + if (!EnzymeFunctionToAnalyze.empty()) { + if (auto Err = PB.parsePassPipeline(MPM, "print-type-analysis")) { + std::string ErrMsg = toString(std::move(Err)); + LLVMRustSetLastError(ErrMsg.c_str()); + return LLVMRustResult::Failure; + } + } + if (PrintAfterEnzyme) { // Handle the Rust flag `-Zautodiff=PrintModAfter`. std::string Banner = "Module after EnzymeNewPM"; diff --git a/src/tools/enzyme b/src/tools/enzyme index b5098d515d5e..0f65f31837a6 160000 --- a/src/tools/enzyme +++ b/src/tools/enzyme @@ -1 +1 @@ -Subproject commit b5098d515d5e1bd0f5470553bc0d18da9794ca8b +Subproject commit 0f65f31837a608db469ebde94adbc921be70bd8a From 4a95b165274f9de5c6a0d3c13ae3103e2ac23eb9 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 2 Jul 2025 10:42:07 +0000 Subject: [PATCH 029/363] Move crashes tests. --- .../mir/gvn-nonsensical-coroutine-layout.rs} | 6 ++++- .../gvn-nonsensical-coroutine-layout.stderr | 26 +++++++++++++++++++ .../mir/gvn-nonsensical-sized-str.rs} | 5 +++- tests/ui/mir/gvn-nonsensical-sized-str.stderr | 10 +++++++ 4 files changed, 45 insertions(+), 2 deletions(-) rename tests/{crashes/128094.rs => ui/mir/gvn-nonsensical-coroutine-layout.rs} (53%) create mode 100644 tests/ui/mir/gvn-nonsensical-coroutine-layout.stderr rename tests/{crashes/135128.rs => ui/mir/gvn-nonsensical-sized-str.rs} (51%) create mode 100644 tests/ui/mir/gvn-nonsensical-sized-str.stderr diff --git a/tests/crashes/128094.rs b/tests/ui/mir/gvn-nonsensical-coroutine-layout.rs similarity index 53% rename from tests/crashes/128094.rs rename to tests/ui/mir/gvn-nonsensical-coroutine-layout.rs index 56d09d78bed9..f0d174cd01b0 100644 --- a/tests/crashes/128094.rs +++ b/tests/ui/mir/gvn-nonsensical-coroutine-layout.rs @@ -1,15 +1,19 @@ -//@ known-bug: rust-lang/rust#128094 +//! Verify that we do not ICE when a coroutine body is malformed. //@ compile-flags: -Zmir-enable-passes=+GVN //@ edition: 2018 pub enum Request { TestSome(T), + //~^ ERROR cannot find type `T` in this scope [E0412] } pub async fn handle_event(event: Request) { async move { static instance: Request = Request { bar: 17 }; + //~^ ERROR expected struct, variant or union type, found enum `Request` [E0574] &instance } .await; } + +fn main() {} diff --git a/tests/ui/mir/gvn-nonsensical-coroutine-layout.stderr b/tests/ui/mir/gvn-nonsensical-coroutine-layout.stderr new file mode 100644 index 000000000000..abc7b16ca741 --- /dev/null +++ b/tests/ui/mir/gvn-nonsensical-coroutine-layout.stderr @@ -0,0 +1,26 @@ +error[E0412]: cannot find type `T` in this scope + --> $DIR/gvn-nonsensical-coroutine-layout.rs:6:14 + | +LL | TestSome(T), + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | pub enum Request { + | +++ + +error[E0574]: expected struct, variant or union type, found enum `Request` + --> $DIR/gvn-nonsensical-coroutine-layout.rs:12:36 + | +LL | static instance: Request = Request { bar: 17 }; + | ^^^^^^^ not a struct, variant or union type + | +help: consider importing this struct instead + | +LL + use std::error::Request; + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0412, E0574. +For more information about an error, try `rustc --explain E0412`. diff --git a/tests/crashes/135128.rs b/tests/ui/mir/gvn-nonsensical-sized-str.rs similarity index 51% rename from tests/crashes/135128.rs rename to tests/ui/mir/gvn-nonsensical-sized-str.rs index c718b758dc69..29a82f8ce2a1 100644 --- a/tests/crashes/135128.rs +++ b/tests/ui/mir/gvn-nonsensical-sized-str.rs @@ -1,13 +1,16 @@ -//@ known-bug: #135128 +//! Verify that we do not ICE when optimizing bodies with nonsensical bounds. //@ compile-flags: -Copt-level=1 //@ edition: 2021 +//@ build-pass #![feature(trivial_bounds)] async fn return_str() -> str where str: Sized, + //~^ WARN trait bound str: Sized does not depend on any type or lifetime parameters { *"Sized".to_string().into_boxed_str() } + fn main() {} diff --git a/tests/ui/mir/gvn-nonsensical-sized-str.stderr b/tests/ui/mir/gvn-nonsensical-sized-str.stderr new file mode 100644 index 000000000000..08f0193e9f61 --- /dev/null +++ b/tests/ui/mir/gvn-nonsensical-sized-str.stderr @@ -0,0 +1,10 @@ +warning: trait bound str: Sized does not depend on any type or lifetime parameters + --> $DIR/gvn-nonsensical-sized-str.rs:10:10 + | +LL | str: Sized, + | ^^^^^ + | + = note: `#[warn(trivial_bounds)]` on by default + +warning: 1 warning emitted + From 674724c741062ab12cd359ff1439388b0632f2a0 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 2 Jul 2025 12:26:20 +0000 Subject: [PATCH 030/363] remove deprecated from core::ffi::c_str --- library/core/src/ffi/c_str.rs | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 881a7a24083c..c43f3834630f 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -135,16 +135,20 @@ pub enum FromBytesWithNulError { } #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] -impl Error for FromBytesWithNulError { - #[allow(deprecated)] - fn description(&self) -> &str { +impl fmt::Display for FromBytesWithNulError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::InteriorNul { .. } => "data provided contains an interior nul byte", - Self::NotNulTerminated => "data provided is not nul terminated", + Self::InteriorNul { position } => { + write!(f, "data provided contains an interior nul byte at byte position {position}") + } + Self::NotNulTerminated => write!(f, "data provided is not nul terminated"), } } } +#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] +impl Error for FromBytesWithNulError {} + /// An error indicating that no nul byte was present. /// /// A slice used to create a [`CStr`] must contain a nul byte somewhere @@ -181,18 +185,6 @@ impl Default for &CStr { } } -#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] -impl fmt::Display for FromBytesWithNulError { - #[allow(deprecated, deprecated_in_future)] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.description())?; - if let Self::InteriorNul { position } = self { - write!(f, " at byte pos {position}")?; - } - Ok(()) - } -} - impl CStr { /// Wraps a raw C string with a safe C string wrapper. /// From 0b61286dd3a95522a5c9acea6d941fc27500cd38 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 2 Jul 2025 09:38:38 -0400 Subject: [PATCH 031/363] Fix m68k CI --- .github/workflows/m68k.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 245bee7f2a3b..179b36c1c7e9 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -59,14 +59,12 @@ jobs: - name: Setup path to libgccjit run: | - sudo dpkg -i gcc-m68k-15.deb + sudo dpkg --force-overwrite -i gcc-m68k-15.deb echo 'gcc-path = "/usr/lib/"' > config.toml - name: Set env run: | echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - - #- name: Cache rust repository ## We only clone the rust repository for rustc tests From ed1e9b7015a3b1599d1322a433771b5845beae68 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 2 Jul 2025 09:24:55 -0400 Subject: [PATCH 032/363] Manually run in a VM in the m68k CI --- .github/workflows/m68k.yml | 6 ++++-- build_system/src/config.rs | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 5f347498f325..8b8f58fef5fa 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -108,10 +108,12 @@ jobs: run: | ./y.sh build --target-triple m68k-unknown-linux-gnu + vm_dir=$(pwd)/vm cd tests/hello-world CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../../y.sh cargo build --target m68k-unknown-linux-gnu - CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../../y.sh cargo run --target m68k-unknown-linux-gnu > hello_world_stdout - test $(cat hello_world_stdout) == "Hello, world!" || exit 1 + sudo cp target/m68k-unknown-linux-gnu/debug/hello_world $vm_dir/home/ + sudo chroot $vm_dir qemu-m68k-static /home/hello_world > hello_world_stdout + test $(cat hello_world_stdout) == "Hello, world!" || (echo "Output differs. Actual output: $(cat hello_world_stdout)"; exit 1) # Summary job for the merge queue. # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 121c43822fdb..428f3766e5de 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -374,6 +374,7 @@ impl ConfigInfo { if self.target_triple.is_empty() { return Err("Unknown non-native platform".to_string()); } + // TODO: check if this is still needed. linker = Some(format!("-Clinker={}-gcc", self.target_triple)); self.run_in_vm = true; } From 21c8639d797850bfbb55546d69c09ba424361aa2 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 2 Jul 2025 11:39:27 -0400 Subject: [PATCH 033/363] Fix to use the correct expected output for m68k CI test --- .github/workflows/m68k.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 8b8f58fef5fa..4b67360df9df 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -113,7 +113,8 @@ jobs: CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../../y.sh cargo build --target m68k-unknown-linux-gnu sudo cp target/m68k-unknown-linux-gnu/debug/hello_world $vm_dir/home/ sudo chroot $vm_dir qemu-m68k-static /home/hello_world > hello_world_stdout - test $(cat hello_world_stdout) == "Hello, world!" || (echo "Output differs. Actual output: $(cat hello_world_stdout)"; exit 1) + expected_output="40" + test $(cat hello_world_stdout) == $expected_output || (echo "Output differs. Actual output: $(cat hello_world_stdout)"; exit 1) # Summary job for the merge queue. # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! From 188108733af702a7f60982c18da2d87d54ed8f5b Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 2 Jul 2025 11:48:49 -0400 Subject: [PATCH 034/363] Update the doc to reflect the new way to specify the linker for cross-compilation --- doc/tips.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/tips.md b/doc/tips.md index 4ab135f3df66..e62c3402a292 100644 --- a/doc/tips.md +++ b/doc/tips.md @@ -62,8 +62,8 @@ generate it in [gimple.md](./doc/gimple.md). * Run `./y.sh prepare --cross` so that the sysroot is patched for the cross-compiling case. * Set the path to the cross-compiling libgccjit in `gcc-path` (in `config.toml`). - * Make sure you have the linker for your target (for instance `m68k-unknown-linux-gnu-gcc`) in your `$PATH`. Currently, the linker name is hardcoded as being `$TARGET-gcc`. Specify the target when building the sysroot: `./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu`. - * Build your project by specifying the target: `../y.sh cargo build --target m68k-unknown-linux-gnu`. + * Make sure you have the linker for your target (for instance `m68k-unknown-linux-gnu-gcc`) in your `$PATH`. You can specify which linker to use via `CG_RUSTFLAGS="-Clinker="`, for instance: `CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc"`. Specify the target when building the sysroot: `./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu`. + * Build your project by specifying the target and the linker to use: `CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../y.sh cargo build --target m68k-unknown-linux-gnu`. If the target is not yet supported by the Rust compiler, create a [target specification file](https://docs.rust-embedded.org/embedonomicon/custom-target.html) (note that the `arch` specified in this file must be supported by the rust compiler). Then, you can use it the following way: From f1c71ffb4764b17d6d23b432d871c3f0c7bb9d91 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 2 Jul 2025 11:49:05 -0400 Subject: [PATCH 035/363] Clean some config stuff up --- build_system/src/config.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 428f3766e5de..a5f802e293a9 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -352,15 +352,6 @@ impl ConfigInfo { None => return Err("no host found".to_string()), }; - if self.target_triple.is_empty() { - // TODO: set target triple. - // TODO: why do we even need to set target_triple? - // It seems to only be needed for the linker (we could add an environment variable to - // remove this need) and the sysroot (perhaps we could find another way to find it). - // TODO TODO: seems like we would still need OVERWRITE_TARGET_TRIPLE when using a - // json spec file. - // ====> maybe not since we specify both --target and --target-triple. - } if self.target_triple.is_empty() { self.target_triple = self.host_triple.clone(); } @@ -374,7 +365,6 @@ impl ConfigInfo { if self.target_triple.is_empty() { return Err("Unknown non-native platform".to_string()); } - // TODO: check if this is still needed. linker = Some(format!("-Clinker={}-gcc", self.target_triple)); self.run_in_vm = true; } From f1b5a5638ec3aba301dc5a50daccb4c1ed69ac78 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Thu, 3 Jul 2025 08:57:32 +0000 Subject: [PATCH 036/363] wrapping shift: remove first bitmask and table --- library/core/src/num/wrapping.rs | 48 ++++---------------------------- 1 file changed, 6 insertions(+), 42 deletions(-) diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index 55fa91d0b9f4..c460f38bd2e4 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -94,9 +94,9 @@ macro_rules! sh_impl_signed { #[inline] fn shl(self, other: $f) -> Wrapping<$t> { if other < 0 { - Wrapping(self.0.wrapping_shr((-other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(-other as u32)) } else { - Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(other as u32)) } } } @@ -119,9 +119,9 @@ macro_rules! sh_impl_signed { #[inline] fn shr(self, other: $f) -> Wrapping<$t> { if other < 0 { - Wrapping(self.0.wrapping_shl((-other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(-other as u32)) } else { - Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(other as u32)) } } } @@ -147,7 +147,7 @@ macro_rules! sh_impl_unsigned { #[inline] fn shl(self, other: $f) -> Wrapping<$t> { - Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(other as u32)) } } forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f, @@ -168,7 +168,7 @@ macro_rules! sh_impl_unsigned { #[inline] fn shr(self, other: $f) -> Wrapping<$t> { - Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(other as u32)) } } forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f, @@ -1052,39 +1052,3 @@ macro_rules! wrapping_int_impl_unsigned { } wrapping_int_impl_unsigned! { usize u8 u16 u32 u64 u128 } - -mod shift_max { - #![allow(non_upper_case_globals)] - - #[cfg(target_pointer_width = "16")] - mod platform { - pub(crate) const usize: u32 = super::u16; - pub(crate) const isize: u32 = super::i16; - } - - #[cfg(target_pointer_width = "32")] - mod platform { - pub(crate) const usize: u32 = super::u32; - pub(crate) const isize: u32 = super::i32; - } - - #[cfg(target_pointer_width = "64")] - mod platform { - pub(crate) const usize: u32 = super::u64; - pub(crate) const isize: u32 = super::i64; - } - - pub(super) const i8: u32 = (1 << 3) - 1; - pub(super) const i16: u32 = (1 << 4) - 1; - pub(super) const i32: u32 = (1 << 5) - 1; - pub(super) const i64: u32 = (1 << 6) - 1; - pub(super) const i128: u32 = (1 << 7) - 1; - pub(super) use self::platform::isize; - - pub(super) const u8: u32 = i8; - pub(super) const u16: u32 = i16; - pub(super) const u32: u32 = i32; - pub(super) const u64: u32 = i64; - pub(super) const u128: u32 = i128; - pub(super) use self::platform::usize; -} From 653bb64c7530c86d00b875e1ef14ac75455d2d80 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 14:24:58 +0000 Subject: [PATCH 037/363] Remove LtoModuleCodegen Most uses of it either contain a fat or thin lto module. Only WorkItem::LTO could contain both, but splitting that enum variant doesn't complicate things much. --- compiler/rustc_codegen_gcc/src/back/lto.rs | 15 +++-- compiler/rustc_codegen_gcc/src/lib.rs | 6 +- compiler/rustc_codegen_llvm/src/back/lto.rs | 17 +++--- compiler/rustc_codegen_llvm/src/lib.rs | 6 +- compiler/rustc_codegen_ssa/src/back/lto.rs | 60 ------------------- compiler/rustc_codegen_ssa/src/back/write.rs | 48 +++++++++++---- .../rustc_codegen_ssa/src/traits/write.rs | 6 +- 7 files changed, 58 insertions(+), 100 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index 10fce860b777..e554dd2500bd 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -24,7 +24,7 @@ use std::sync::Arc; use gccjit::{Context, OutputKind}; use object::read::archive::ArchiveFile; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; @@ -176,7 +176,7 @@ pub(crate) fn run_fat( cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, -) -> Result, FatalError> { +) -> Result, FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, dcx)?; @@ -201,7 +201,7 @@ fn fat_lto( mut serialized_modules: Vec<(SerializedModule, CString)>, tmp_path: TempDir, //symbols_below_threshold: &[String], -) -> Result, FatalError> { +) -> Result, FatalError> { let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module"); info!("going for a fat lto"); @@ -334,7 +334,7 @@ fn fat_lto( // of now. module.module_llvm.temp_dir = Some(tmp_path); - Ok(LtoModuleCodegen::Fat(module)) + Ok(module) } pub struct ModuleBuffer(PathBuf); @@ -358,7 +358,7 @@ pub(crate) fn run_thin( cgcx: &CodegenContext, modules: Vec<(String, ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, -) -> Result<(Vec>, Vec), FatalError> { +) -> Result<(Vec>, Vec), FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, dcx)?; @@ -427,7 +427,7 @@ fn thin_lto( tmp_path: TempDir, cached_modules: Vec<(SerializedModule, WorkProduct)>, //_symbols_below_threshold: &[String], -) -> Result<(Vec>, Vec), FatalError> { +) -> Result<(Vec>, Vec), FatalError> { let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis"); info!("going for that thin, thin LTO"); @@ -573,8 +573,7 @@ fn thin_lto( }*/ info!(" - {}: re-compiled", module_name); - opt_jobs - .push(LtoModuleCodegen::Thin(ThinModule { shared: shared.clone(), idx: module_index })); + opt_jobs.push(ThinModule { shared: shared.clone(), idx: module_index }); } // Save the current ThinLTO import information for the next compilation diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index a912678ef2a1..a151a0ab7553 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -97,7 +97,7 @@ use gccjit::{CType, Context, OptimizationLevel}; use gccjit::{TargetInfo, Version}; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn, }; @@ -361,7 +361,7 @@ impl WriteBackendMethods for GccCodegenBackend { cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result, FatalError> { + ) -> Result, FatalError> { back::lto::run_fat(cgcx, modules, cached_modules) } @@ -369,7 +369,7 @@ impl WriteBackendMethods for GccCodegenBackend { cgcx: &CodegenContext, modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result<(Vec>, Vec), FatalError> { + ) -> Result<(Vec>, Vec), FatalError> { back::lto::run_thin(cgcx, modules, cached_modules) } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 9c62244f3c9f..0198b9f0cf0c 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use std::{io, iter, slice}; use object::read::archive::ArchiveFile; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; @@ -201,7 +201,7 @@ pub(crate) fn run_fat( cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, -) -> Result, FatalError> { +) -> Result, FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, dcx)?; @@ -217,7 +217,7 @@ pub(crate) fn run_thin( cgcx: &CodegenContext, modules: Vec<(String, ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, -) -> Result<(Vec>, Vec), FatalError> { +) -> Result<(Vec>, Vec), FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, dcx)?; @@ -248,7 +248,7 @@ fn fat_lto( cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, symbols_below_threshold: &[*const libc::c_char], -) -> Result, FatalError> { +) -> Result, FatalError> { let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_build_monolithic_module"); info!("going for a fat lto"); @@ -366,7 +366,7 @@ fn fat_lto( save_temp_bitcode(cgcx, &module, "lto.after-restriction"); } - Ok(LtoModuleCodegen::Fat(module)) + Ok(module) } pub(crate) struct Linker<'a>(&'a mut llvm::Linker<'a>); @@ -436,7 +436,7 @@ fn thin_lto( serialized_modules: Vec<(SerializedModule, CString)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, symbols_below_threshold: &[*const libc::c_char], -) -> Result<(Vec>, Vec), FatalError> { +) -> Result<(Vec>, Vec), FatalError> { let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis"); unsafe { info!("going for that thin, thin LTO"); @@ -568,10 +568,7 @@ fn thin_lto( } info!(" - {}: re-compiled", module_name); - opt_jobs.push(LtoModuleCodegen::Thin(ThinModule { - shared: Arc::clone(&shared), - idx: module_index, - })); + opt_jobs.push(ThinModule { shared: Arc::clone(&shared), idx: module_index }); } // Save the current ThinLTO import information for the next compilation diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index cdfffbe47bfa..57b37959e0d0 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -30,7 +30,7 @@ use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig}; use llvm_util::target_config; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn, }; @@ -178,14 +178,14 @@ impl WriteBackendMethods for LlvmCodegenBackend { cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result, FatalError> { + ) -> Result, FatalError> { back::lto::run_fat(cgcx, modules, cached_modules) } fn run_thin_lto( cgcx: &CodegenContext, modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result<(Vec>, Vec), FatalError> { + ) -> Result<(Vec>, Vec), FatalError> { back::lto::run_thin(cgcx, modules, cached_modules) } fn optimize( diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index ce6fe8a191b3..b49b6783bbd9 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -1,13 +1,8 @@ use std::ffi::CString; use std::sync::Arc; -use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_data_structures::memmap::Mmap; -use rustc_errors::FatalError; -use super::write::CodegenContext; -use crate::ModuleCodegen; -use crate::back::write::ModuleConfig; use crate::traits::*; pub struct ThinModule { @@ -42,61 +37,6 @@ pub struct ThinShared { pub module_names: Vec, } -pub enum LtoModuleCodegen { - Fat(ModuleCodegen), - Thin(ThinModule), -} - -impl LtoModuleCodegen { - pub fn name(&self) -> &str { - match *self { - LtoModuleCodegen::Fat(_) => "everything", - LtoModuleCodegen::Thin(ref m) => m.name(), - } - } - - /// Optimize this module within the given codegen context. - pub fn optimize( - self, - cgcx: &CodegenContext, - ) -> Result, FatalError> { - match self { - LtoModuleCodegen::Fat(mut module) => { - B::optimize_fat(cgcx, &mut module)?; - Ok(module) - } - LtoModuleCodegen::Thin(thin) => B::optimize_thin(cgcx, thin), - } - } - - /// A "gauge" of how costly it is to optimize this module, used to sort - /// biggest modules first. - pub fn cost(&self) -> u64 { - match *self { - // Only one module with fat LTO, so the cost doesn't matter. - LtoModuleCodegen::Fat(_) => 0, - LtoModuleCodegen::Thin(ref m) => m.cost(), - } - } - - /// Run autodiff on Fat LTO module - pub fn autodiff( - self, - cgcx: &CodegenContext, - diff_fncs: Vec, - config: &ModuleConfig, - ) -> Result, FatalError> { - match &self { - LtoModuleCodegen::Fat(module) => { - B::autodiff(cgcx, &module, diff_fncs, config)?; - } - _ => panic!("autodiff called with non-fat LTO module"), - } - - Ok(self) - } -} - pub enum SerializedModule { Local(M), FromRlib(Vec), diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 8330e4f7af0c..5395b55092b3 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -408,14 +408,16 @@ fn generate_lto_work( if !needs_fat_lto.is_empty() { assert!(needs_thin_lto.is_empty()); - let mut module = + let module = B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); if cgcx.lto == Lto::Fat && !autodiff.is_empty() { let config = cgcx.config(ModuleKind::Regular); - module = module.autodiff(cgcx, autodiff, config).unwrap_or_else(|e| e.raise()); + if let Err(err) = B::autodiff(cgcx, &module, autodiff, config) { + err.raise(); + } } // We are adding a single work item, so the cost doesn't matter. - vec![(WorkItem::LTO(module), 0)] + vec![(WorkItem::FatLto(module), 0)] } else { if !autodiff.is_empty() { let dcx = cgcx.create_dcx(); @@ -428,7 +430,7 @@ fn generate_lto_work( .into_iter() .map(|module| { let cost = module.cost(); - (WorkItem::LTO(module), cost) + (WorkItem::ThinLto(module), cost) }) .chain(copy_jobs.into_iter().map(|wp| { ( @@ -736,15 +738,19 @@ pub(crate) enum WorkItem { /// Copy the post-LTO artifacts from the incremental cache to the output /// directory. CopyPostLtoArtifacts(CachedModuleCodegen), - /// Performs (Thin)LTO on the given module. - LTO(lto::LtoModuleCodegen), + /// Performs fat LTO on the given module. + FatLto(ModuleCodegen), + /// Performs thin-LTO on the given module. + ThinLto(lto::ThinModule), } impl WorkItem { fn module_kind(&self) -> ModuleKind { match *self { WorkItem::Optimize(ref m) => m.kind, - WorkItem::CopyPostLtoArtifacts(_) | WorkItem::LTO(_) => ModuleKind::Regular, + WorkItem::CopyPostLtoArtifacts(_) | WorkItem::FatLto(_) | WorkItem::ThinLto(_) => { + ModuleKind::Regular + } } } @@ -792,7 +798,8 @@ impl WorkItem { match self { WorkItem::Optimize(m) => desc("opt", "optimize module", &m.name), WorkItem::CopyPostLtoArtifacts(m) => desc("cpy", "copy LTO artifacts for", &m.name), - WorkItem::LTO(m) => desc("lto", "LTO module", m.name()), + WorkItem::FatLto(_) => desc("lto", "fat LTO module", "everything"), + WorkItem::ThinLto(m) => desc("lto", "thin-LTO module", m.name()), } } } @@ -996,12 +1003,21 @@ fn execute_copy_from_cache_work_item( }) } -fn execute_lto_work_item( +fn execute_fat_lto_work_item( cgcx: &CodegenContext, - module: lto::LtoModuleCodegen, + mut module: ModuleCodegen, module_config: &ModuleConfig, ) -> Result, FatalError> { - let module = module.optimize(cgcx)?; + B::optimize_fat(cgcx, &mut module)?; + finish_intra_module_work(cgcx, module, module_config) +} + +fn execute_thin_lto_work_item( + cgcx: &CodegenContext, + module: lto::ThinModule, + module_config: &ModuleConfig, +) -> Result, FatalError> { + let module = B::optimize_thin(cgcx, module)?; finish_intra_module_work(cgcx, module, module_config) } @@ -1842,10 +1858,16 @@ fn spawn_work<'a, B: ExtraBackendMethods>( ); Ok(execute_copy_from_cache_work_item(&cgcx, m, module_config)) } - WorkItem::LTO(m) => { + WorkItem::FatLto(m) => { + let _timer = cgcx + .prof + .generic_activity_with_arg("codegen_module_perform_lto", "everything"); + execute_fat_lto_work_item(&cgcx, m, module_config) + } + WorkItem::ThinLto(m) => { let _timer = cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name()); - execute_lto_work_item(&cgcx, m, module_config) + execute_thin_lto_work_item(&cgcx, m, module_config) } }) }; diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 07a0609fda1a..78380973ffc8 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -2,7 +2,7 @@ use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_middle::dep_graph::WorkProduct; -use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use crate::back::lto::{SerializedModule, ThinModule}; use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig}; use crate::{CompiledModule, ModuleCodegen}; @@ -26,7 +26,7 @@ pub trait WriteBackendMethods: Clone + 'static { cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result, FatalError>; + ) -> Result, FatalError>; /// Performs thin LTO by performing necessary global analysis and returning two /// lists, one of the modules that need optimization and another for modules that /// can simply be copied over from the incr. comp. cache. @@ -34,7 +34,7 @@ pub trait WriteBackendMethods: Clone + 'static { cgcx: &CodegenContext, modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result<(Vec>, Vec), FatalError>; + ) -> Result<(Vec>, Vec), FatalError>; fn print_pass_timings(&self); fn print_statistics(&self); fn optimize( From 7fd78df3463c761a693ea79265a6a1faaf2ed51b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 14:43:09 +0000 Subject: [PATCH 038/363] Move dcx creation into WriteBackendMethods::codegen --- compiler/rustc_codegen_gcc/src/back/write.rs | 4 +++- compiler/rustc_codegen_gcc/src/lib.rs | 3 +-- compiler/rustc_codegen_llvm/src/back/write.rs | 4 +++- compiler/rustc_codegen_llvm/src/lib.rs | 3 +-- compiler/rustc_codegen_ssa/src/back/write.rs | 7 ++----- compiler/rustc_codegen_ssa/src/traits/write.rs | 1 - 6 files changed, 10 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index d03d063bdace..113abe70805b 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -16,10 +16,12 @@ use crate::{GccCodegenBackend, GccContext}; pub(crate) fn codegen( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { + let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); + let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name); { let context = &module.module_llvm.context; diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index a151a0ab7553..34452bdd2005 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -408,11 +408,10 @@ impl WriteBackendMethods for GccCodegenBackend { fn codegen( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { - back::write::codegen(cgcx, dcx, module, config) + back::write::codegen(cgcx, module, config) } fn prepare_thin( diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index bde6a9cf4bc6..1f7a785bbe72 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -817,10 +817,12 @@ pub(crate) fn link( pub(crate) fn codegen( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { + let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); + let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &*module.name); { let llmod = module.module_llvm.llmod(); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 57b37959e0d0..4d85683de8c4 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -212,11 +212,10 @@ impl WriteBackendMethods for LlvmCodegenBackend { } fn codegen( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { - back::write::codegen(cgcx, dcx, module, config) + back::write::codegen(cgcx, module, config) } fn prepare_thin( module: ModuleCodegen, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 5395b55092b3..29e67be6eb61 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1026,11 +1026,8 @@ fn finish_intra_module_work( module: ModuleCodegen, module_config: &ModuleConfig, ) -> Result, FatalError> { - let dcx = cgcx.create_dcx(); - let dcx = dcx.handle(); - if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Allocator { - let module = B::codegen(cgcx, dcx, module, module_config)?; + let module = B::codegen(cgcx, module, module_config)?; Ok(WorkItemResult::Finished(module)) } else { Ok(WorkItemResult::NeedsLink(module)) @@ -1718,7 +1715,7 @@ fn start_executing_work( let dcx = dcx.handle(); let module = B::run_link(&cgcx, dcx, needs_link).map_err(|_| ())?; let module = - B::codegen(&cgcx, dcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())?; + B::codegen(&cgcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())?; compiled_modules.push(module); } diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 78380973ffc8..c732c4b2ab86 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -53,7 +53,6 @@ pub trait WriteBackendMethods: Clone + 'static { ) -> Result, FatalError>; fn codegen( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result; From ee280a596d3b7c401547be9a6afadf7298ee3a55 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 14:44:26 +0000 Subject: [PATCH 039/363] Fat LTO always produces a single object file, so -Zcombine-cgu has no effect --- compiler/rustc_codegen_ssa/src/back/write.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 29e67be6eb61..762dc8f6c2d6 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1009,7 +1009,9 @@ fn execute_fat_lto_work_item( module_config: &ModuleConfig, ) -> Result, FatalError> { B::optimize_fat(cgcx, &mut module)?; - finish_intra_module_work(cgcx, module, module_config) + + let module = B::codegen(cgcx, module, module_config)?; + Ok(WorkItemResult::Finished(module)) } fn execute_thin_lto_work_item( From 797084dc92c251ff0c986adfdd4a7e261f499b02 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 14:50:28 +0000 Subject: [PATCH 040/363] Split generate_lto_work between fat and thin-LTO cases --- compiler/rustc_codegen_ssa/src/back/write.rs | 114 +++++++++++-------- 1 file changed, 64 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 762dc8f6c2d6..21d5d3ced000 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -397,52 +397,50 @@ impl CodegenContext { } } -fn generate_lto_work( +fn generate_fat_lto_work( cgcx: &CodegenContext, autodiff: Vec, needs_fat_lto: Vec>, + import_only_modules: Vec<(SerializedModule, WorkProduct)>, +) -> WorkItem { + let _prof_timer = cgcx.prof.generic_activity("codegen_generate_lto_work"); + + let module = + B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); + if cgcx.lto == Lto::Fat && !autodiff.is_empty() { + let config = cgcx.config(ModuleKind::Regular); + if let Err(err) = B::autodiff(cgcx, &module, autodiff, config) { + err.raise(); + } + } + WorkItem::FatLto(module) +} + +fn generate_thin_lto_work( + cgcx: &CodegenContext, needs_thin_lto: Vec<(String, B::ThinBuffer)>, import_only_modules: Vec<(SerializedModule, WorkProduct)>, ) -> Vec<(WorkItem, u64)> { - let _prof_timer = cgcx.prof.generic_activity("codegen_generate_lto_work"); + let _prof_timer = cgcx.prof.generic_activity("codegen_thin_generate_lto_work"); - if !needs_fat_lto.is_empty() { - assert!(needs_thin_lto.is_empty()); - let module = - B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); - if cgcx.lto == Lto::Fat && !autodiff.is_empty() { - let config = cgcx.config(ModuleKind::Regular); - if let Err(err) = B::autodiff(cgcx, &module, autodiff, config) { - err.raise(); - } - } - // We are adding a single work item, so the cost doesn't matter. - vec![(WorkItem::FatLto(module), 0)] - } else { - if !autodiff.is_empty() { - let dcx = cgcx.create_dcx(); - dcx.handle().emit_fatal(AutodiffWithoutLto {}); - } - assert!(needs_fat_lto.is_empty()); - let (lto_modules, copy_jobs) = B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules) - .unwrap_or_else(|e| e.raise()); - lto_modules - .into_iter() - .map(|module| { - let cost = module.cost(); - (WorkItem::ThinLto(module), cost) - }) - .chain(copy_jobs.into_iter().map(|wp| { - ( - WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen { - name: wp.cgu_name.clone(), - source: wp, - }), - 0, // copying is very cheap - ) - })) - .collect() - } + let (lto_modules, copy_jobs) = + B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules).unwrap_or_else(|e| e.raise()); + lto_modules + .into_iter() + .map(|module| { + let cost = module.cost(); + (WorkItem::ThinLto(module), cost) + }) + .chain(copy_jobs.into_iter().map(|wp| { + ( + WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen { + name: wp.cgu_name.clone(), + source: wp, + }), + 0, // copying is very cheap + ) + })) + .collect() } struct CompiledModules { @@ -1489,20 +1487,36 @@ fn start_executing_work( let needs_thin_lto = mem::take(&mut needs_thin_lto); let import_only_modules = mem::take(&mut lto_import_only_modules); - for (work, cost) in generate_lto_work( - &cgcx, - autodiff_items.clone(), - needs_fat_lto, - needs_thin_lto, - import_only_modules, - ) { - let insertion_index = work_items - .binary_search_by_key(&cost, |&(_, cost)| cost) - .unwrap_or_else(|e| e); - work_items.insert(insertion_index, (work, cost)); + if !needs_fat_lto.is_empty() { + assert!(needs_thin_lto.is_empty()); + + let work = generate_fat_lto_work( + &cgcx, + autodiff_items.clone(), + needs_fat_lto, + import_only_modules, + ); + work_items.push((work, 0)); if cgcx.parallel { helper.request_token(); } + } else { + if !autodiff_items.is_empty() { + let dcx = cgcx.create_dcx(); + dcx.handle().emit_fatal(AutodiffWithoutLto {}); + } + + for (work, cost) in + generate_thin_lto_work(&cgcx, needs_thin_lto, import_only_modules) + { + let insertion_index = work_items + .binary_search_by_key(&cost, |&(_, cost)| cost) + .unwrap_or_else(|e| e); + work_items.insert(insertion_index, (work, cost)); + if cgcx.parallel { + helper.request_token(); + } + } } } From 332f1b1bdddb01f2f203f47cd3f30f677ae8d9ea Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 15:39:19 +0000 Subject: [PATCH 041/363] Pass in autodiff items when starting the coordinator thread As opposed to sending a message to the coordinator thread. --- compiler/rustc_codegen_ssa/src/back/write.rs | 16 ++++------------ compiler/rustc_codegen_ssa/src/base.rs | 9 ++------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 21d5d3ced000..dcee7aec7339 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -470,6 +470,7 @@ pub(crate) fn start_async_codegen( backend: B, tcx: TyCtxt<'_>, target_cpu: String, + autodiff_items: &[AutoDiffItem], ) -> OngoingCodegen { let (coordinator_send, coordinator_receive) = channel(); @@ -488,6 +489,7 @@ pub(crate) fn start_async_codegen( backend.clone(), tcx, &crate_info, + autodiff_items, shared_emitter, codegen_worker_send, coordinator_receive, @@ -1044,9 +1046,6 @@ pub(crate) enum Message { /// Sent from a backend worker thread. WorkItem { result: Result, Option>, worker_id: usize }, - /// A vector containing all the AutoDiff tasks that we have to pass to Enzyme. - AddAutoDiffItems(Vec), - /// The frontend has finished generating something (backend IR or a /// post-LTO artifact) for a codegen unit, and it should be passed to the /// backend. Sent from the main thread. @@ -1113,6 +1112,7 @@ fn start_executing_work( backend: B, tcx: TyCtxt<'_>, crate_info: &CrateInfo, + autodiff_items: &[AutoDiffItem], shared_emitter: SharedEmitter, codegen_worker_send: Sender, coordinator_receive: Receiver>, @@ -1122,6 +1122,7 @@ fn start_executing_work( ) -> thread::JoinHandle> { let coordinator_send = tx_to_llvm_workers; let sess = tcx.sess; + let autodiff_items = autodiff_items.to_vec(); let mut each_linked_rlib_for_lto = Vec::new(); drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| { @@ -1375,7 +1376,6 @@ fn start_executing_work( // This is where we collect codegen units that have gone all the way // through codegen and LLVM. - let mut autodiff_items = Vec::new(); let mut compiled_modules = vec![]; let mut compiled_allocator_module = None; let mut needs_link = Vec::new(); @@ -1645,10 +1645,6 @@ fn start_executing_work( main_thread_state = MainThreadState::Idle; } - Message::AddAutoDiffItems(mut items) => { - autodiff_items.append(&mut items); - } - Message::CodegenComplete => { if codegen_state != Aborted { codegen_state = Completed; @@ -2117,10 +2113,6 @@ impl OngoingCodegen { drop(self.coordinator.sender.send(Box::new(Message::CodegenComplete::))); } - pub(crate) fn submit_autodiff_items(&self, items: Vec) { - drop(self.coordinator.sender.send(Box::new(Message::::AddAutoDiffItems(items)))); - } - pub(crate) fn check_for_errors(&self, sess: &Session) { self.shared_emitter_main.check(sess, false); } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 102d4ea2fa6c..01ce07f4ccfe 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -647,7 +647,7 @@ pub fn codegen_crate( ) -> OngoingCodegen { // Skip crate items and just output metadata in -Z no-codegen mode. if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { - let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu); + let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, &[]); ongoing_codegen.codegen_finished(tcx); @@ -667,7 +667,6 @@ pub fn codegen_crate( // codegen units. let MonoItemPartitions { codegen_units, autodiff_items, .. } = tcx.collect_and_partition_mono_items(()); - let autodiff_fncs = autodiff_items.to_vec(); // Force all codegen_unit queries so they are already either red or green // when compile_codegen_unit accesses them. We are not able to re-execute @@ -680,7 +679,7 @@ pub fn codegen_crate( } } - let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu); + let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu, autodiff_items); // Codegen an allocator shim, if necessary. if let Some(kind) = allocator_kind_for_codegen(tcx) { @@ -710,10 +709,6 @@ pub fn codegen_crate( ); } - if !autodiff_fncs.is_empty() { - ongoing_codegen.submit_autodiff_items(autodiff_fncs); - } - // For better throughput during parallel processing by LLVM, we used to sort // CGUs largest to smallest. This would lead to better thread utilization // by, for example, preventing a large CGU from being processed last and From 3c56c2ecf53b8bbaa863c32c9e93ef2d3b102e28 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 3 Jul 2025 23:39:31 +0800 Subject: [PATCH 042/363] stabilize `const_slice_reverse` --- library/core/src/slice/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 3a3f44c6b854..35bebdbe522a 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -967,7 +967,7 @@ impl [T] { /// assert!(v == [3, 2, 1]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_slice_reverse", issue = "135120")] + #[rustc_const_stable(feature = "const_slice_reverse", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn reverse(&mut self) { let half_len = self.len() / 2; @@ -1000,6 +1000,7 @@ impl [T] { // this check tells LLVM that the indexing below is // in-bounds. Then after inlining -- once the actual // lengths of the slices are known -- it's removed. + // FIXME(const_trait_impl) replace with let (a, b) = (&mut a[..n], &mut b[..n]); let (a, _) = a.split_at_mut(n); let (b, _) = b.split_at_mut(n); From 779cb00311dc0bbb942dbdaefa24f98bd2d4cbbe Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:05:38 +0000 Subject: [PATCH 043/363] Move run_fat_lto call into execute_fat_lto_work_item This will allow merging all fat LTO steps together. In addition it reduces the amount of work done on the coordinator thread without jobserver token. --- compiler/rustc_codegen_ssa/src/back/write.rs | 68 +++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index dcee7aec7339..c7d2fcef29f9 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -397,25 +397,6 @@ impl CodegenContext { } } -fn generate_fat_lto_work( - cgcx: &CodegenContext, - autodiff: Vec, - needs_fat_lto: Vec>, - import_only_modules: Vec<(SerializedModule, WorkProduct)>, -) -> WorkItem { - let _prof_timer = cgcx.prof.generic_activity("codegen_generate_lto_work"); - - let module = - B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); - if cgcx.lto == Lto::Fat && !autodiff.is_empty() { - let config = cgcx.config(ModuleKind::Regular); - if let Err(err) = B::autodiff(cgcx, &module, autodiff, config) { - err.raise(); - } - } - WorkItem::FatLto(module) -} - fn generate_thin_lto_work( cgcx: &CodegenContext, needs_thin_lto: Vec<(String, B::ThinBuffer)>, @@ -739,7 +720,11 @@ pub(crate) enum WorkItem { /// directory. CopyPostLtoArtifacts(CachedModuleCodegen), /// Performs fat LTO on the given module. - FatLto(ModuleCodegen), + FatLto { + needs_fat_lto: Vec>, + import_only_modules: Vec<(SerializedModule, WorkProduct)>, + autodiff: Vec, + }, /// Performs thin-LTO on the given module. ThinLto(lto::ThinModule), } @@ -748,7 +733,7 @@ impl WorkItem { fn module_kind(&self) -> ModuleKind { match *self { WorkItem::Optimize(ref m) => m.kind, - WorkItem::CopyPostLtoArtifacts(_) | WorkItem::FatLto(_) | WorkItem::ThinLto(_) => { + WorkItem::CopyPostLtoArtifacts(_) | WorkItem::FatLto { .. } | WorkItem::ThinLto(_) => { ModuleKind::Regular } } @@ -798,7 +783,7 @@ impl WorkItem { match self { WorkItem::Optimize(m) => desc("opt", "optimize module", &m.name), WorkItem::CopyPostLtoArtifacts(m) => desc("cpy", "copy LTO artifacts for", &m.name), - WorkItem::FatLto(_) => desc("lto", "fat LTO module", "everything"), + WorkItem::FatLto { .. } => desc("lto", "fat LTO module", "everything"), WorkItem::ThinLto(m) => desc("lto", "thin-LTO module", m.name()), } } @@ -1005,9 +990,21 @@ fn execute_copy_from_cache_work_item( fn execute_fat_lto_work_item( cgcx: &CodegenContext, - mut module: ModuleCodegen, + needs_fat_lto: Vec>, + import_only_modules: Vec<(SerializedModule, WorkProduct)>, + autodiff: Vec, module_config: &ModuleConfig, ) -> Result, FatalError> { + let mut module = + B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); + + if cgcx.lto == Lto::Fat && !autodiff.is_empty() { + let config = cgcx.config(ModuleKind::Regular); + if let Err(err) = B::autodiff(cgcx, &module, autodiff, config) { + err.raise(); + } + } + B::optimize_fat(cgcx, &mut module)?; let module = B::codegen(cgcx, module, module_config)?; @@ -1490,13 +1487,14 @@ fn start_executing_work( if !needs_fat_lto.is_empty() { assert!(needs_thin_lto.is_empty()); - let work = generate_fat_lto_work( - &cgcx, - autodiff_items.clone(), - needs_fat_lto, - import_only_modules, - ); - work_items.push((work, 0)); + work_items.push(( + WorkItem::FatLto { + needs_fat_lto, + import_only_modules, + autodiff: autodiff_items.clone(), + }, + 0, + )); if cgcx.parallel { helper.request_token(); } @@ -1867,11 +1865,17 @@ fn spawn_work<'a, B: ExtraBackendMethods>( ); Ok(execute_copy_from_cache_work_item(&cgcx, m, module_config)) } - WorkItem::FatLto(m) => { + WorkItem::FatLto { needs_fat_lto, import_only_modules, autodiff } => { let _timer = cgcx .prof .generic_activity_with_arg("codegen_module_perform_lto", "everything"); - execute_fat_lto_work_item(&cgcx, m, module_config) + execute_fat_lto_work_item( + &cgcx, + needs_fat_lto, + import_only_modules, + autodiff, + module_config, + ) } WorkItem::ThinLto(m) => { let _timer = From 9a3aa8fdb192b42e665eb9059a0061f865b3d352 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:07:28 +0000 Subject: [PATCH 044/363] Remove unnecessary check for fat LTO --- compiler/rustc_codegen_ssa/src/back/write.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index c7d2fcef29f9..433cb63882f6 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -998,7 +998,7 @@ fn execute_fat_lto_work_item( let mut module = B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); - if cgcx.lto == Lto::Fat && !autodiff.is_empty() { + if !autodiff.is_empty() { let config = cgcx.config(ModuleKind::Regular); if let Err(err) = B::autodiff(cgcx, &module, autodiff, config) { err.raise(); From 8d63c7a1d68cd30383dceb03a76499c658fa7f40 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:09:10 +0000 Subject: [PATCH 045/363] Remove unused config param from WriteBackendMethods::autodiff --- compiler/rustc_codegen_gcc/src/lib.rs | 1 - compiler/rustc_codegen_llvm/src/builder/autodiff.rs | 2 -- compiler/rustc_codegen_llvm/src/lib.rs | 3 +-- compiler/rustc_codegen_ssa/src/back/write.rs | 3 +-- compiler/rustc_codegen_ssa/src/traits/write.rs | 1 - 5 files changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 34452bdd2005..8e63ebc84940 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -437,7 +437,6 @@ impl WriteBackendMethods for GccCodegenBackend { _cgcx: &CodegenContext, _module: &ModuleCodegen, _diff_functions: Vec, - _config: &ModuleConfig, ) -> Result<(), FatalError> { unimplemented!() } diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index b07d9a5cfca8..c27e161ba994 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -2,7 +2,6 @@ use std::ptr; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode}; use rustc_codegen_ssa::ModuleCodegen; -use rustc_codegen_ssa::back::write::ModuleConfig; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::BaseTypeCodegenMethods; use rustc_errors::FatalError; @@ -461,7 +460,6 @@ pub(crate) fn differentiate<'ll>( module: &'ll ModuleCodegen, cgcx: &CodegenContext, diff_items: Vec, - _config: &ModuleConfig, ) -> Result<(), FatalError> { for item in &diff_items { trace!("{}", item); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 4d85683de8c4..7f54416ec0e3 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -231,13 +231,12 @@ impl WriteBackendMethods for LlvmCodegenBackend { cgcx: &CodegenContext, module: &ModuleCodegen, diff_fncs: Vec, - config: &ModuleConfig, ) -> Result<(), FatalError> { if cgcx.lto != Lto::Fat { let dcx = cgcx.create_dcx(); return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO)); } - builder::autodiff::differentiate(module, cgcx, diff_fncs, config) + builder::autodiff::differentiate(module, cgcx, diff_fncs) } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 433cb63882f6..24f648bdb2e4 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -999,8 +999,7 @@ fn execute_fat_lto_work_item( B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); if !autodiff.is_empty() { - let config = cgcx.config(ModuleKind::Regular); - if let Err(err) = B::autodiff(cgcx, &module, autodiff, config) { + if let Err(err) = B::autodiff(cgcx, &module, autodiff) { err.raise(); } } diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index c732c4b2ab86..949fb818c783 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -65,7 +65,6 @@ pub trait WriteBackendMethods: Clone + 'static { cgcx: &CodegenContext, module: &ModuleCodegen, diff_fncs: Vec, - config: &ModuleConfig, ) -> Result<(), FatalError>; } From 21026cae8d34241b65924198b72c7231ce4f5a3d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:22:32 +0000 Subject: [PATCH 046/363] Merge run_fat_lto, optimize_fat and autodiff into run_and_optimize_fat_lto --- compiler/rustc_codegen_gcc/src/lib.rs | 23 +++-------- compiler/rustc_codegen_llvm/messages.ftl | 1 - compiler/rustc_codegen_llvm/src/errors.rs | 4 -- compiler/rustc_codegen_llvm/src/lib.rs | 39 +++++++------------ compiler/rustc_codegen_ssa/src/back/write.rs | 12 +----- .../rustc_codegen_ssa/src/traits/write.rs | 16 ++------ 6 files changed, 26 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 8e63ebc84940..75c36fffec98 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -357,11 +357,16 @@ impl WriteBackendMethods for GccCodegenBackend { type ThinData = ThinData; type ThinBuffer = ThinBuffer; - fn run_fat_lto( + fn run_and_optimize_fat_lto( cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, + diff_fncs: Vec, ) -> Result, FatalError> { + if !diff_fncs.is_empty() { + unimplemented!(); + } + back::lto::run_fat(cgcx, modules, cached_modules) } @@ -391,14 +396,6 @@ impl WriteBackendMethods for GccCodegenBackend { Ok(()) } - fn optimize_fat( - _cgcx: &CodegenContext, - _module: &mut ModuleCodegen, - ) -> Result<(), FatalError> { - // TODO(antoyo) - Ok(()) - } - fn optimize_thin( cgcx: &CodegenContext, thin: ThinModule, @@ -432,14 +429,6 @@ impl WriteBackendMethods for GccCodegenBackend { ) -> Result, FatalError> { back::write::link(cgcx, dcx, modules) } - - fn autodiff( - _cgcx: &CodegenContext, - _module: &ModuleCodegen, - _diff_functions: Vec, - ) -> Result<(), FatalError> { - unimplemented!() - } } /// 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 3885f18271f1..f197ea744732 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -1,5 +1,4 @@ codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z autodiff=Enable -codegen_llvm_autodiff_without_lto = using the autodiff feature requires using fat-lto codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err} diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index d50ad8a1a9cb..31d49e863195 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -37,10 +37,6 @@ impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { } } -#[derive(Diagnostic)] -#[diag(codegen_llvm_autodiff_without_lto)] -pub(crate) struct AutoDiffWithoutLTO; - #[derive(Diagnostic)] #[diag(codegen_llvm_autodiff_without_enable)] pub(crate) struct AutoDiffWithoutEnable; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 7f54416ec0e3..5d551c3af87f 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -26,7 +26,7 @@ use std::mem::ManuallyDrop; use back::owned_target_machine::OwnedTargetMachine; use back::write::{create_informational_target_machine, create_target_machine}; use context::SimpleCx; -use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig}; +use errors::ParseTargetMachineConfig; use llvm_util::target_config; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; @@ -43,7 +43,7 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::Session; -use rustc_session::config::{Lto, OptLevel, OutputFilenames, PrintKind, PrintRequest}; +use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest}; use rustc_span::Symbol; mod back { @@ -174,12 +174,23 @@ impl WriteBackendMethods for LlvmCodegenBackend { ) -> Result, FatalError> { back::write::link(cgcx, dcx, modules) } - fn run_fat_lto( + fn run_and_optimize_fat_lto( cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, + diff_fncs: Vec, ) -> Result, FatalError> { - back::lto::run_fat(cgcx, modules, cached_modules) + let mut module = back::lto::run_fat(cgcx, modules, cached_modules)?; + + if !diff_fncs.is_empty() { + builder::autodiff::differentiate(&module, cgcx, diff_fncs)?; + } + + let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); + back::lto::run_pass_manager(cgcx, dcx, &mut module, false)?; + + Ok(module) } fn run_thin_lto( cgcx: &CodegenContext, @@ -196,14 +207,6 @@ impl WriteBackendMethods for LlvmCodegenBackend { ) -> Result<(), FatalError> { back::write::optimize(cgcx, dcx, module, config) } - fn optimize_fat( - cgcx: &CodegenContext, - module: &mut ModuleCodegen, - ) -> Result<(), FatalError> { - let dcx = cgcx.create_dcx(); - let dcx = dcx.handle(); - back::lto::run_pass_manager(cgcx, dcx, module, false) - } fn optimize_thin( cgcx: &CodegenContext, thin: ThinModule, @@ -226,18 +229,6 @@ impl WriteBackendMethods for LlvmCodegenBackend { fn serialize_module(module: ModuleCodegen) -> (String, Self::ModuleBuffer) { (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod())) } - /// Generate autodiff rules - fn autodiff( - cgcx: &CodegenContext, - module: &ModuleCodegen, - diff_fncs: Vec, - ) -> Result<(), FatalError> { - if cgcx.lto != Lto::Fat { - let dcx = cgcx.create_dcx(); - return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO)); - } - builder::autodiff::differentiate(module, cgcx, diff_fncs) - } } impl LlvmCodegenBackend { diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 24f648bdb2e4..26fc593da98a 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -995,17 +995,7 @@ fn execute_fat_lto_work_item( autodiff: Vec, module_config: &ModuleConfig, ) -> Result, FatalError> { - let mut module = - B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); - - if !autodiff.is_empty() { - if let Err(err) = B::autodiff(cgcx, &module, autodiff) { - err.raise(); - } - } - - B::optimize_fat(cgcx, &mut module)?; - + let module = B::run_and_optimize_fat_lto(cgcx, needs_fat_lto, import_only_modules, autodiff)?; let module = B::codegen(cgcx, module, module_config)?; Ok(WorkItemResult::Finished(module)) } diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 949fb818c783..5e993640472d 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -20,12 +20,13 @@ pub trait WriteBackendMethods: Clone + 'static { dcx: DiagCtxtHandle<'_>, modules: Vec>, ) -> Result, FatalError>; - /// Performs fat LTO by merging all modules into a single one and returning it - /// for further optimization. - fn run_fat_lto( + /// 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( cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, + diff_fncs: Vec, ) -> Result, FatalError>; /// Performs thin LTO by performing necessary global analysis and returning two /// lists, one of the modules that need optimization and another for modules that @@ -43,10 +44,6 @@ pub trait WriteBackendMethods: Clone + 'static { module: &mut ModuleCodegen, config: &ModuleConfig, ) -> Result<(), FatalError>; - fn optimize_fat( - cgcx: &CodegenContext, - llmod: &mut ModuleCodegen, - ) -> Result<(), FatalError>; fn optimize_thin( cgcx: &CodegenContext, thin: ThinModule, @@ -61,11 +58,6 @@ pub trait WriteBackendMethods: Clone + 'static { want_summary: bool, ) -> (String, Self::ThinBuffer); fn serialize_module(module: ModuleCodegen) -> (String, Self::ModuleBuffer); - fn autodiff( - cgcx: &CodegenContext, - module: &ModuleCodegen, - diff_fncs: Vec, - ) -> Result<(), FatalError>; } pub trait ThinBufferMethods: Send + Sync { From a7eefc3fc4c16786844841af511b09db832f6a01 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Fri, 4 Jul 2025 07:04:46 +0200 Subject: [PATCH 047/363] Enable xgot feature for mips64 musl targets This was missed in b65c2afdfd9aaee977302516c9ef177861abfe74, which only enabled it for the glibc targets. I didn't feel comfortable touching the OpenWRT target, whoever maintains that will probably want to take a look whether it is necessary there as well. Signed-off-by: Jens Reidel --- .../src/spec/targets/mips64_unknown_linux_muslabi64.rs | 2 +- .../src/spec/targets/mips64el_unknown_linux_muslabi64.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs index fd5095030530..f95ce7563549 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs @@ -5,7 +5,7 @@ use crate::spec::{Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); base.cpu = "mips64r2".into(); - base.features = "+mips64r2".into(); + base.features = "+mips64r2,+xgot".into(); base.max_atomic_width = Some(64); Target { // LLVM doesn't recognize "muslabi64" yet. diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs index aa087b1a35af..d42e097b0fd8 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs @@ -3,7 +3,7 @@ use crate::spec::{Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); base.cpu = "mips64r2".into(); - base.features = "+mips64r2".into(); + base.features = "+mips64r2,+xgot".into(); base.max_atomic_width = Some(64); // FIXME(compiler-team#422): musl targets should be dynamically linked by default. base.crt_static_default = true; From 92144e1ee183fc8ed097c937fcc4754242b69a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 4 Jul 2025 11:41:19 +0200 Subject: [PATCH 048/363] Remove `josh-sync` tooling and update README --- src/doc/rustc-dev-guide/README.md | 35 +- src/doc/rustc-dev-guide/josh-sync/Cargo.lock | 430 ------------------ src/doc/rustc-dev-guide/josh-sync/Cargo.toml | 9 - src/doc/rustc-dev-guide/josh-sync/README.md | 4 - src/doc/rustc-dev-guide/josh-sync/src/main.rs | 41 -- src/doc/rustc-dev-guide/josh-sync/src/sync.rs | 275 ----------- 6 files changed, 5 insertions(+), 789 deletions(-) delete mode 100644 src/doc/rustc-dev-guide/josh-sync/Cargo.lock delete mode 100644 src/doc/rustc-dev-guide/josh-sync/Cargo.toml delete mode 100644 src/doc/rustc-dev-guide/josh-sync/README.md delete mode 100644 src/doc/rustc-dev-guide/josh-sync/src/main.rs delete mode 100644 src/doc/rustc-dev-guide/josh-sync/src/sync.rs diff --git a/src/doc/rustc-dev-guide/README.md b/src/doc/rustc-dev-guide/README.md index 0425c15f83c1..f11290e44d8f 100644 --- a/src/doc/rustc-dev-guide/README.md +++ b/src/doc/rustc-dev-guide/README.md @@ -72,49 +72,24 @@ including the `` marker at the place where you want the TOC. ## Synchronizing josh subtree with rustc -This repository is linked to `rust-lang/rust` as a [josh](https://josh-project.github.io/josh/intro.html) subtree. You can use the following commands to synchronize the subtree in both directions. +This repository is linked to `rust-lang/rust` as a [josh](https://josh-project.github.io/josh/intro.html) subtree. You can use the [rustc-josh-sync](https://github.com/rust-lang/josh-sync) tool to perform synchronization. -You'll need to install `josh-proxy` locally via - -``` -cargo install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04 -``` -Older versions of `josh-proxy` may not round trip commits losslessly so it is important to install this exact version. +You can install the tool using `cargo install --locked --git https://github.com/rust-lang/josh-sync`. ### Pull changes from `rust-lang/rust` into this repository 1) Checkout a new branch that will be used to create a PR into `rust-lang/rustc-dev-guide` 2) Run the pull command ``` - cargo run --manifest-path josh-sync/Cargo.toml rustc-pull + rustc-josh-sync pull ``` 3) Push the branch to your fork and create a PR into `rustc-dev-guide` + - If you have `gh` CLI installed, `rustc-josh-sync` can create the PR for you. ### Push changes from this repository into `rust-lang/rust` -NOTE: If you use Git protocol to push to your fork of `rust-lang/rust`, -ensure that you have this entry in your Git config, -else the 2 steps that follow would prompt for a username and password: - -``` -[url "git@github.com:"] -insteadOf = "https://github.com/" -``` - 1) Run the push command to create a branch named `` in a `rustc` fork under the `` account ``` - cargo run --manifest-path josh-sync/Cargo.toml rustc-push + rustc-josh-sync push ``` 2) Create a PR from `` into `rust-lang/rust` - -#### Minimal git config - -For simplicity (ease of implementation purposes), the josh-sync script simply calls out to system git. This means that the git invocation may be influenced by global (or local) git configuration. - -You may observe "Nothing to pull" even if you *know* rustc-pull has something to pull if your global git config sets `fetch.prunetags = true` (and possibly other configurations may cause unexpected outcomes). - -To minimize the likelihood of this happening, you may wish to keep a separate *minimal* git config that *only* has `[user]` entries from global git config, then repoint system git to use the minimal git config instead. E.g. - -``` -GIT_CONFIG_GLOBAL=/path/to/minimal/gitconfig GIT_CONFIG_SYSTEM='' cargo run --manifest-path josh-sync/Cargo.toml -- rustc-pull -``` diff --git a/src/doc/rustc-dev-guide/josh-sync/Cargo.lock b/src/doc/rustc-dev-guide/josh-sync/Cargo.lock deleted file mode 100644 index a8183a740db3..000000000000 --- a/src/doc/rustc-dev-guide/josh-sync/Cargo.lock +++ /dev/null @@ -1,430 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" -dependencies = [ - "anstyle", - "windows-sys 0.59.0", -] - -[[package]] -name = "anyhow" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "4.5.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "directories" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "josh-sync" -version = "0.0.0" -dependencies = [ - "anyhow", - "clap", - "directories", - "xshell", -] - -[[package]] -name = "libc" -version = "0.2.169" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags", - "libc", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "proc-macro2" -version = "1.0.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - -[[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.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "xshell" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e7290c623014758632efe00737145b6867b66292c42167f2ec381eb566a373d" -dependencies = [ - "xshell-macros", -] - -[[package]] -name = "xshell-macros" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ac00cd3f8ec9c1d33fb3e7958a82df6989c42d747bd326c822b1d625283547" diff --git a/src/doc/rustc-dev-guide/josh-sync/Cargo.toml b/src/doc/rustc-dev-guide/josh-sync/Cargo.toml deleted file mode 100644 index 1f8bf2a00933..000000000000 --- a/src/doc/rustc-dev-guide/josh-sync/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "josh-sync" -edition = "2024" - -[dependencies] -anyhow = "1.0.95" -clap = { version = "4.5.21", features = ["derive"] } -directories = "5" -xshell = "0.2.6" diff --git a/src/doc/rustc-dev-guide/josh-sync/README.md b/src/doc/rustc-dev-guide/josh-sync/README.md deleted file mode 100644 index a3dd876e8b87..000000000000 --- a/src/doc/rustc-dev-guide/josh-sync/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Git josh sync -This utility serves for syncing the josh git subtree to and from the rust-lang/rust repository. - -See CLI help for usage. diff --git a/src/doc/rustc-dev-guide/josh-sync/src/main.rs b/src/doc/rustc-dev-guide/josh-sync/src/main.rs deleted file mode 100644 index aeedee5be22d..000000000000 --- a/src/doc/rustc-dev-guide/josh-sync/src/main.rs +++ /dev/null @@ -1,41 +0,0 @@ -use clap::Parser; - -use crate::sync::{GitSync, RustcPullError}; - -mod sync; - -#[derive(clap::Parser)] -enum Args { - /// Pull changes from the main `rustc` repository. - /// This creates new commits that should be then merged into `rustc-dev-guide`. - RustcPull, - /// Push changes from `rustc-dev-guide` to the given `branch` of a `rustc` fork under the given - /// GitHub `username`. - /// The pushed branch should then be merged into the `rustc` repository. - RustcPush { branch: String, github_username: String }, -} - -fn main() -> anyhow::Result<()> { - let args = Args::parse(); - let sync = GitSync::from_current_dir()?; - match args { - Args::RustcPull => { - if let Err(error) = sync.rustc_pull(None) { - match error { - RustcPullError::NothingToPull => { - eprintln!("Nothing to pull"); - std::process::exit(2); - } - RustcPullError::PullFailed(error) => { - eprintln!("Pull failure: {error:?}"); - std::process::exit(1); - } - } - } - } - Args::RustcPush { github_username, branch } => { - sync.rustc_push(github_username, branch)?; - } - } - Ok(()) -} diff --git a/src/doc/rustc-dev-guide/josh-sync/src/sync.rs b/src/doc/rustc-dev-guide/josh-sync/src/sync.rs deleted file mode 100644 index ed38d1403a02..000000000000 --- a/src/doc/rustc-dev-guide/josh-sync/src/sync.rs +++ /dev/null @@ -1,275 +0,0 @@ -use std::io::Write; -use std::ops::Not; -use std::path::PathBuf; -use std::time::Duration; -use std::{env, net, process}; - -use anyhow::{Context, anyhow, bail}; -use xshell::{Shell, cmd}; - -/// Used for rustc syncs. -const JOSH_FILTER: &str = ":/src/doc/rustc-dev-guide"; -const JOSH_PORT: u16 = 42042; -const UPSTREAM_REPO: &str = "rust-lang/rust"; - -pub enum RustcPullError { - /// No changes are available to be pulled. - NothingToPull, - /// A rustc-pull has failed, probably a git operation error has occurred. - PullFailed(anyhow::Error), -} - -impl From for RustcPullError -where - E: Into, -{ - fn from(error: E) -> Self { - Self::PullFailed(error.into()) - } -} - -pub struct GitSync { - dir: PathBuf, -} - -/// This code was adapted from the miri repository -/// (https://github.com/rust-lang/miri/blob/6a68a79f38064c3bc30617cca4bdbfb2c336b140/miri-script/src/commands.rs#L236). -impl GitSync { - pub fn from_current_dir() -> anyhow::Result { - Ok(Self { dir: std::env::current_dir()? }) - } - - pub fn rustc_pull(&self, commit: Option) -> Result<(), RustcPullError> { - let sh = Shell::new()?; - sh.change_dir(&self.dir); - let commit = commit.map(Ok).unwrap_or_else(|| { - let rust_repo_head = - cmd!(sh, "git ls-remote https://github.com/{UPSTREAM_REPO}/ 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() { - return Err(anyhow::anyhow!( - "working directory must be clean before performing rustc pull" - ) - .into()); - } - // Make sure josh is running. - let josh = Self::start_josh()?; - let josh_url = - format!("http://localhost:{JOSH_PORT}/{UPSTREAM_REPO}.git@{commit}{JOSH_FILTER}.git"); - - let previous_base_commit = sh.read_file("rust-version")?.trim().to_string(); - if previous_base_commit == commit { - return Err(RustcPullError::NothingToPull); - } - - // 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. - // 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 = || -> anyhow::Result { - Ok(cmd!(sh, "git rev-list HEAD --max-parents=0 --count") - .read() - .context("failed to determine the number of root commits")? - .parse::()?) - }; - let num_roots_before = num_roots()?; - - let sha = - cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout; - - // 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")?; - - let current_sha = - cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout; - if current_sha == sha { - cmd!(sh, "git reset --hard HEAD^") - .run() - .expect("FAILED to clean up after creating the preparation commit"); - eprintln!( - "No merge was performed, no changes to pull were found. Rolled back the preparation commit." - ); - return Err(RustcPullError::NothingToPull); - } - - // Check that the number of roots did not increase. - if num_roots()? != num_roots_before { - return Err(anyhow::anyhow!( - "Josh created a new root commit. This is probably not the history you want." - ) - .into()); - } - - drop(josh); - Ok(()) - } - - pub fn rustc_push(&self, github_user: String, branch: String) -> anyhow::Result<()> { - let sh = Shell::new()?; - sh.change_dir(&self.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 `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 repo. - println!( - "This will pull a copy of the rust-lang/rust history into this 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/{UPSTREAM_REPO} {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(&self.dir); - println!("Pushing 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 rustc-dev-guide properly. Please create a rustc PR:" - ); - println!( - // Open PR with `subtree update` title to silence the `no-merges` triagebot check - " https://github.com/{UPSTREAM_REPO}/compare/{github_user}:{branch}?quick_pull=1&title=rustc-dev-guide+subtree+update&body=r?+@ghost" - ); - - drop(josh); - Ok(()) - } - - fn start_josh() -> anyhow::Result { - // Determine cache directory. - let local_dir = { - let user_dirs = - directories::ProjectDirs::from("org", "rust-lang", "rustc-dev-guide-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.") - } -} From 13dca5e1baede8fe0df76ccba1875a14dda10269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 4 Jul 2025 11:44:58 +0200 Subject: [PATCH 049/363] Update CI workflow to use rustc-josh-sync --- src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml index 1e430d8b4e65..7190fc733db0 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml @@ -24,11 +24,10 @@ jobs: run: rustup update stable - uses: Swatinem/rust-cache@v2 with: - workspaces: "josh-sync" # Cache the josh directory with checked out rustc - cache-directories: "/home/runner/.cache/rustc-dev-guide-josh" - - name: Install josh - run: RUSTFLAGS="--cap-lints warn" cargo install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04 + cache-directories: "/home/runner/.cache/rustc-josh" + - name: Install rustc-josh-sync + run: cargo install --locked --git https://github.com/rust-lang/josh-sync - name: Setup bot git name and email run: | git config --global user.name 'The rustc-dev-guide Cronjob Bot' @@ -38,7 +37,7 @@ jobs: # Turn off -e to disable early exit shell: bash {0} run: | - cargo run --manifest-path josh-sync/Cargo.toml -- rustc-pull + rustc-josh-sync pull exitcode=$? # If no pull was performed, we want to mark this job as successful, From 9d83749cdd02531b000eead51cd0de40ec9a59e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 4 Jul 2025 13:14:23 +0200 Subject: [PATCH 050/363] Document `rustc-josh-sync` --- src/doc/rustc-dev-guide/README.md | 20 +----- src/doc/rustc-dev-guide/src/external-repos.md | 62 +++++++++++++++---- 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/src/doc/rustc-dev-guide/README.md b/src/doc/rustc-dev-guide/README.md index f11290e44d8f..5932da467ab2 100644 --- a/src/doc/rustc-dev-guide/README.md +++ b/src/doc/rustc-dev-guide/README.md @@ -74,22 +74,4 @@ including the `` marker at the place where you want the TOC. This repository is linked to `rust-lang/rust` as a [josh](https://josh-project.github.io/josh/intro.html) subtree. You can use the [rustc-josh-sync](https://github.com/rust-lang/josh-sync) tool to perform synchronization. -You can install the tool using `cargo install --locked --git https://github.com/rust-lang/josh-sync`. - -### Pull changes from `rust-lang/rust` into this repository - -1) Checkout a new branch that will be used to create a PR into `rust-lang/rustc-dev-guide` -2) Run the pull command - ``` - rustc-josh-sync pull - ``` -3) Push the branch to your fork and create a PR into `rustc-dev-guide` - - If you have `gh` CLI installed, `rustc-josh-sync` can create the PR for you. - -### Push changes from this repository into `rust-lang/rust` - -1) Run the push command to create a branch named `` in a `rustc` fork under the `` account - ``` - rustc-josh-sync push - ``` -2) Create a PR from `` into `rust-lang/rust` +You can find a guide on how to perform the synchronization [here](./src/external-repos.md#synchronizing-a-josh-subtree). diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index f3170c9222d8..a19b1116de82 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -9,7 +9,7 @@ There are three main ways we use dependencies: As a general rule: - Use crates.io for libraries that could be useful for others in the ecosystem - Use subtrees for tools that depend on compiler internals and need to be updated if there are breaking -changes + changes - Use submodules for tools that are independent of the compiler ## External Dependencies (subtrees) @@ -23,6 +23,8 @@ The following external projects are managed using some form of a `subtree`: * [rust-analyzer](https://github.com/rust-lang/rust-analyzer) * [rustc_codegen_cranelift](https://github.com/rust-lang/rustc_codegen_cranelift) * [rustc-dev-guide](https://github.com/rust-lang/rustc-dev-guide) +* [compiler-builtins](https://github.com/rust-lang/compiler-builtins) +* [stdarch](https://github.com/rust-lang/stdarch) In contrast to `submodule` dependencies (see below for those), the `subtree` dependencies are just regular files and directories which can @@ -34,20 +36,57 @@ implement a new tool feature or test, that should happen in one collective rustc `subtree` dependencies are currently managed by two distinct approaches: * Using `git subtree` - * `clippy` ([sync guide](https://doc.rust-lang.org/nightly/clippy/development/infrastructure/sync.html#performing-the-sync-from-rust-langrust-to-clippy)) - * `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)) + * `clippy` ([sync guide](https://doc.rust-lang.org/nightly/clippy/development/infrastructure/sync.html#performing-the-sync-from-rust-langrust-to-clippy)) + * `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` ([sync guide](https://github.com/rust-lang/rustc-dev-guide#synchronizing-josh-subtree-with-rustc)) + * `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` + * `compiler-builtins` + * `stdarch` -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. If you want to migrate a repository dependency from `git subtree` or `git submodule` to josh, you can check out [this guide](https://hackmd.io/7pOuxnkdQDaL1Y1FQr65xg). +### Josh subtrees -Below you can find a guide on how to perform push and pull synchronization with the main rustc repo using `git subtree`, although these instructions might differ repo from repo. +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, it is described [below](#synchronizing-a-josh-subtree). -### Synchronizing a 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: + +- rustc-dev-guide + +To use the tool, first install it with `cargo install --locked --git https://github. +com/rust-lang/josh-sync`. + +Both pulls (synchronize changes from rust-lang/rust into the subtree) and pushes (synchronize +changes from the subtree to rust-lang/rust) are performed from the subtree repository (so first +switch to its repository checkout directory in your terminal). + +#### Performing pull +1) Checkout a new branch that will be used to create a PR into the subtree +2) Run the pull command + ``` + rustc-josh-sync pull + ``` +3) Push the branch to your fork and create a PR into the subtree repository + - If you have `gh` CLI installed, `rustc-josh-sync` can create the PR for you. + +#### Performing push + +1) Run the push command to create a branch named `` in a `rustc` fork under the `` account + ``` + rustc-josh-sync push + ``` +2) Create a PR from `` into `rust-lang/rust` + +### Creating a new Josh subtree dependency + +If you want to migrate a repository dependency from `git subtree` or `git submodule` to josh, you can check out [this guide](https://hackmd.io/7pOuxnkdQDaL1Y1FQr65xg). + +### Synchronizing a git subtree Periodically the changes made to subtree based dependencies need to be synchronized between this repository and the upstream tool repositories. @@ -129,3 +168,4 @@ the week leading up to the beta cut. [toolstate website]: https://rust-lang-nursery.github.io/rust-toolstate/ [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 From f167f9b49ec85dae8756c21f5183cdb1f43c6d4d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Fri, 4 Jul 2025 14:13:15 +0200 Subject: [PATCH 051/363] external-repos.md: small fixes --- src/doc/rustc-dev-guide/src/external-repos.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index a19b1116de82..fc40b5d2bfa5 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -49,7 +49,7 @@ implement a new tool feature or test, that should happen in one collective rustc ### 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, it is 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; 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). ### Synchronizing a Josh subtree @@ -58,8 +58,7 @@ Currently, we are migrating Josh repositories to it. So far, it is used in: - rustc-dev-guide -To use the tool, first install it with `cargo install --locked --git https://github. -com/rust-lang/josh-sync`. +To use the tool, first install it with `cargo install --locked --git https://github.com/rust-lang/josh-sync`. Both pulls (synchronize changes from rust-lang/rust into the subtree) and pushes (synchronize changes from the subtree to rust-lang/rust) are performed from the subtree repository (so first From 2111525850863ec2f4c14c964ae37a761de64f63 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 4 Jul 2025 20:54:45 +0800 Subject: [PATCH 052/363] Add test false-sealed-traits-note.rs Signed-off-by: xizheyin --- .../sealed-traits/false-sealed-traits-note.rs | 13 ++++++++++++ .../false-sealed-traits-note.stderr | 21 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs create mode 100644 tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr diff --git a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs new file mode 100644 index 000000000000..75bc11b06787 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs @@ -0,0 +1,13 @@ +// when we impl TraitA for Struct, it can compile, we should not emit sealed traits note, see issue #143392 + +mod inner { + pub trait TraitA {} + + pub trait TraitB: TraitA {} +} + +struct Struct; + +impl inner::TraitB for Struct {} //~ ERROR the trait bound `Struct: TraitA` is not satisfied [E0277] + +fn main(){} \ No newline at end of file diff --git a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr new file mode 100644 index 000000000000..385551602856 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr @@ -0,0 +1,21 @@ +error[E0277]: the trait bound `Struct: TraitA` is not satisfied + --> $DIR/false-sealed-traits-note.rs:11: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 + | +LL | pub trait TraitA {} + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `TraitB` + --> $DIR/false-sealed-traits-note.rs:6:23 + | +LL | pub trait TraitB: TraitA {} + | ^^^^^^ required by this bound in `TraitB` + = note: `TraitB` is a "sealed trait", because to implement it you also need to implement `inner::TraitA`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 312dcd77796d59743aab30720d8df897504284e6 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 4 Jul 2025 09:47:14 -0400 Subject: [PATCH 053/363] Update to nightly-2025-07-04 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index bccbc6cd2c5c..2fe8ec4647fa 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-06-28" +channel = "nightly-2025-07-04" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] From 148a220e38f0b2ba4ec8014d0c1e83ca6d52d47e Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Fri, 4 Jul 2025 13:10:34 +0200 Subject: [PATCH 054/363] remote-test-client: Exit code `128 + ` instead of `3` If the remote process is terminated by a signal, make `remote-test-client` exit with the code `128 + ` instead of always `3`. This follows common practice among tools such as bash [^1]: > When a command terminates on a fatal signal whose number is N, Bash uses the > value 128+N as the exit status. It also allows us to differentiate between `run-pass` and `run-crash` ui tests without special case code in compiletest for that when `remote-test-client` is used. [^1]: https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html --- src/tools/remote-test-client/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index bda08423487b..b9741431b503 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -335,7 +335,9 @@ fn run(support_lib_count: usize, exe: String, all_args: Vec) { std::process::exit(code); } else { println!("died due to signal {}", code); - std::process::exit(3); + // Behave like bash and other tools and exit with 128 + the signal + // number. That way we can avoid special case code in other places. + std::process::exit(128 + code); } } From 4a261a15131e5eec10252d5131c8a3c3f89edbf7 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 4 Jul 2025 21:38:46 +0800 Subject: [PATCH 055/363] Use relative visibility when noting sealed trait to reduce false positive Signed-off-by: xizheyin --- .../src/error_reporting/traits/suggestions.rs | 20 ++++++++++++++----- .../sealed-traits/false-sealed-traits-note.rs | 4 ++-- .../false-sealed-traits-note.stderr | 1 - 3 files changed, 17 insertions(+), 8 deletions(-) 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 362052e9fdbd..dda517074f41 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -22,6 +22,7 @@ use rustc_hir::{ expr_needs_parens, is_range_literal, }; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_middle::middle::privacy::Level; use rustc_middle::traits::IsConstable; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::{ @@ -2775,11 +2776,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty::ClauseKind::Trait(trait_pred) => { let def_id = trait_pred.def_id(); let visible_item = if let Some(local) = def_id.as_local() { - // Check for local traits being reachable. - let vis = &tcx.resolutions(()).effective_visibilities; - // Account for non-`pub` traits in the root of the local crate. - let is_locally_reachable = tcx.parent(def_id).is_crate_root(); - vis.is_reachable(local) || is_locally_reachable + let ty = trait_pred.self_ty(); + // when `TraitA: TraitB` and `S` only impl TraitA, + // we check if `TraitB` can be reachable from `S` + // to determine whether to note `TraitA` is sealed trait. + if let ty::Adt(adt, _) = ty.kind() { + let visibilities = tcx.effective_visibilities(()); + visibilities.effective_vis(local).is_none_or(|v| { + v.at_level(Level::Reexported) + .is_accessible_from(adt.did(), tcx) + }) + } else { + // FIXME(xizheyin): if the type is not ADT, we should not suggest it + true + } } else { // Check for foreign traits being reachable. tcx.visible_parent_map(()).get(&def_id).is_some() 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 75bc11b06787..13f3065e442e 100644 --- a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs +++ b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs @@ -1,4 +1,4 @@ -// when we impl TraitA for Struct, it can compile, we should not emit sealed traits note, see issue #143392 +// We should not emit sealed traits note, see issue #143392 mod inner { pub trait TraitA {} @@ -10,4 +10,4 @@ struct Struct; impl inner::TraitB for Struct {} //~ ERROR the trait bound `Struct: TraitA` is not satisfied [E0277] -fn main(){} \ No newline at end of file +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 385551602856..f80d985ad6e6 100644 --- a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr +++ b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr @@ -14,7 +14,6 @@ note: required by a bound in `TraitB` | LL | pub trait TraitB: TraitA {} | ^^^^^^ required by this bound in `TraitB` - = note: `TraitB` is a "sealed trait", because to implement it you also need to implement `inner::TraitA`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it error: aborting due to 1 previous error From 43506591e8996fda9617c26d489497c50379abea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Jul 2025 10:32:16 +0200 Subject: [PATCH 056/363] miri-script: set msrv so clippy doesn't suggest too-new features --- src/tools/miri/miri-script/Cargo.toml | 1 + src/tools/miri/miri-script/src/commands.rs | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml index 462a9cc62bff..9240788d6bce 100644 --- a/src/tools/miri/miri-script/Cargo.toml +++ b/src/tools/miri/miri-script/Cargo.toml @@ -7,6 +7,7 @@ repository = "https://github.com/rust-lang/miri" version = "0.1.0" default-run = "miri-script" edition = "2024" +rust-version = "1.85" [workspace] # We make this a workspace root so that cargo does not go looking in ../Cargo.toml for the workspace root. diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index e948beef0044..e6ebdf54e385 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -702,7 +702,6 @@ impl Command { let mut early_flags = Vec::::new(); // In `dep` mode, the target is already passed via `MIRI_TEST_TARGET` - #[expect(clippy::collapsible_if)] // we need to wait until this is stable if !dep { if let Some(target) = &target { early_flags.push("--target".into()); @@ -735,7 +734,6 @@ impl Command { // Add Miri flags let mut cmd = cmd.args(&miri_flags).args(&early_flags).args(&flags); // For `--dep` we also need to set the target in the env var. - #[expect(clippy::collapsible_if)] // we need to wait until this is stable if dep { if let Some(target) = &target { cmd = cmd.env("MIRI_TEST_TARGET", target); From d87984e12934cc2f1cf64461f2416a82d76383fe Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 5 Jul 2025 05:06:18 +0100 Subject: [PATCH 057/363] shims::fs adding more fields to FileMetadata addressing, partially at least, FIXME comment and targetting unixes, adding device, user and group ids. --- src/tools/miri/src/shims/unix/fs.rs | 31 +++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 0f7d453b296c..073072a883d6 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -128,16 +128,19 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> { let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); let mode = metadata.mode.to_uint(this.libc_ty_layout("mode_t").size)?; + let dev = metadata.dev; + let uid = metadata.uid; + let gid = metadata.gid; let buf = this.deref_pointer_as(buf_op, this.libc_ty_layout("stat"))?; this.write_int_fields_named( &[ - ("st_dev", 0), + ("st_dev", dev.into()), ("st_mode", mode.try_into().unwrap()), ("st_nlink", 0), ("st_ino", 0), - ("st_uid", 0), - ("st_gid", 0), + ("st_uid", uid.into()), + ("st_gid", gid.into()), ("st_rdev", 0), ("st_atime", access_sec.into()), ("st_mtime", modified_sec.into()), @@ -1544,6 +1547,9 @@ struct FileMetadata { created: Option<(u64, u32)>, accessed: Option<(u64, u32)>, modified: Option<(u64, u32)>, + dev: u64, + uid: u32, + gid: u32, } impl FileMetadata { @@ -1575,6 +1581,9 @@ impl FileMetadata { ecx: &mut MiriInterpCx<'tcx>, metadata: Result, ) -> InterpResult<'tcx, Result> { + #[cfg(unix)] + use std::os::unix::fs::MetadataExt; + let metadata = match metadata { Ok(metadata) => metadata, Err(e) => { @@ -1601,6 +1610,20 @@ impl FileMetadata { let modified = extract_sec_and_nsec(metadata.modified())?; // FIXME: Provide more fields using platform specific methods. - interp_ok(Ok(FileMetadata { mode, size, created, accessed, modified })) + + cfg_select! { + unix => { + let dev = metadata.dev(); + let uid = metadata.uid(); + let gid = metadata.gid(); + } + _ => { + let dev = 0; + let uid = 0; + let gid = 0; + } + } + + interp_ok(Ok(FileMetadata { mode, size, created, accessed, modified, dev, uid, gid })) } } From ef0490c8685ad6ef76e2777934571fc913abd1a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Jul 2025 11:40:37 +0200 Subject: [PATCH 058/363] minor cleanup --- src/tools/miri/src/shims/unix/fs.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 073072a883d6..0f2878ad26c8 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -128,19 +128,16 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> { let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); let mode = metadata.mode.to_uint(this.libc_ty_layout("mode_t").size)?; - let dev = metadata.dev; - let uid = metadata.uid; - let gid = metadata.gid; let buf = this.deref_pointer_as(buf_op, this.libc_ty_layout("stat"))?; this.write_int_fields_named( &[ - ("st_dev", dev.into()), + ("st_dev", metadata.dev.into()), ("st_mode", mode.try_into().unwrap()), ("st_nlink", 0), ("st_ino", 0), - ("st_uid", uid.into()), - ("st_gid", gid.into()), + ("st_uid", metadata.uid.into()), + ("st_gid", metadata.gid.into()), ("st_rdev", 0), ("st_atime", access_sec.into()), ("st_mtime", modified_sec.into()), @@ -1581,9 +1578,6 @@ impl FileMetadata { ecx: &mut MiriInterpCx<'tcx>, metadata: Result, ) -> InterpResult<'tcx, Result> { - #[cfg(unix)] - use std::os::unix::fs::MetadataExt; - let metadata = match metadata { Ok(metadata) => metadata, Err(e) => { @@ -1613,6 +1607,7 @@ impl FileMetadata { cfg_select! { unix => { + use std::os::unix::fs::MetadataExt; let dev = metadata.dev(); let uid = metadata.uid(); let gid = metadata.gid(); From e40f8b26ada6f517235fd5813231adbb79e58ced Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Jul 2025 16:51:14 +0200 Subject: [PATCH 059/363] =?UTF-8?q?rename=20panic=5Fpaylods=20=E2=86=92=20?= =?UTF-8?q?unwind=5Fpayloads?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tools/miri/src/concurrency/thread.rs | 10 +++++----- src/tools/miri/src/shims/panic.rs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 56c197948546..ec65ea685e1f 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -186,15 +186,15 @@ pub struct Thread<'tcx> { /// The join status. join_status: ThreadJoinStatus, - /// Stack of active panic payloads for the current thread. Used for storing - /// the argument of the call to `miri_start_unwind` (the panic payload) when unwinding. + /// Stack of active unwind payloads for the current thread. Used for storing + /// the argument of the call to `miri_start_unwind` (the payload) when unwinding. /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. /// /// In real unwinding, the payload gets passed as an argument to the landing pad, /// which then forwards it to 'Resume'. However this argument is implicit in MIR, /// so we have to store it out-of-band. When there are multiple active unwinds, /// the innermost one is always caught first, so we can store them as a stack. - pub(crate) panic_payloads: Vec>, + pub(crate) unwind_payloads: Vec>, /// Last OS error location in memory. It is a 32-bit integer. pub(crate) last_error: Option>, @@ -282,7 +282,7 @@ impl<'tcx> Thread<'tcx> { stack: Vec::new(), top_user_relevant_frame: None, join_status: ThreadJoinStatus::Joinable, - panic_payloads: Vec::new(), + unwind_payloads: Vec::new(), last_error: None, on_stack_empty, } @@ -292,7 +292,7 @@ impl<'tcx> Thread<'tcx> { impl VisitProvenance for Thread<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let Thread { - panic_payloads: panic_payload, + unwind_payloads: panic_payload, last_error, stack, top_user_relevant_frame: _, diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index a6bce8301491..b3b7b6ae7187 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -51,7 +51,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let payload = this.read_immediate(payload)?; let thread = this.active_thread_mut(); - thread.panic_payloads.push(payload); + thread.unwind_payloads.push(payload); interp_ok(()) } @@ -132,7 +132,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // The Thread's `panic_payload` holds what was passed to `miri_start_unwind`. // This is exactly the second argument we need to pass to `catch_fn`. - let payload = this.active_thread_mut().panic_payloads.pop().unwrap(); + let payload = this.active_thread_mut().unwind_payloads.pop().unwrap(); // Push the `catch_fn` stackframe. let f_instance = this.get_ptr_fn(catch_unwind.catch_fn)?.as_instance()?; From 59af8f36e31165dc2fa5968941a2edad3e1c0025 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Mon, 7 Jul 2025 04:58:18 +0000 Subject: [PATCH 060/363] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 0130cf13a45f..7ca7acb3fd70 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -733b47ea4b1b86216f14ef56e49440c33933f230 +ca98d4d4b3114116203699c2734805547df86f9a From ae3b9765f4510362b3e7ce7e1a62841b2cf5887d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Jul 2025 08:18:32 +0200 Subject: [PATCH 061/363] split unwinding logic from panic logic --- src/tools/miri/src/lib.rs | 3 +- src/tools/miri/src/shims/mod.rs | 1 + src/tools/miri/src/shims/panic.rs | 152 +-------------------------- src/tools/miri/src/shims/unwind.rs | 160 +++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 152 deletions(-) create mode 100644 src/tools/miri/src/shims/unwind.rs diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index c86e33e51859..ca99d69b32d0 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -154,9 +154,10 @@ pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _}; pub use crate::shims::io_error::{EvalContextExt as _, IoError, LibcError}; pub use crate::shims::os_str::EvalContextExt as _; -pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; +pub use crate::shims::panic::EvalContextExt as _; pub use crate::shims::time::EvalContextExt as _; pub use crate::shims::tls::TlsData; +pub use crate::shims::unwind::{CatchUnwindData, EvalContextExt as _}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index f09fc546b3eb..60c0e289292b 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -19,6 +19,7 @@ pub mod os_str; pub mod panic; pub mod time; pub mod tls; +pub mod unwind; pub use self::files::FdTable; //#[cfg(target_os = "linux")] diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index b3b7b6ae7187..5fcb783d6886 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -1,162 +1,12 @@ -//! Panic runtime for Miri. -//! -//! The core pieces of the runtime are: -//! - An implementation of `__rust_maybe_catch_panic` that pushes the invoked stack frame with -//! some extra metadata derived from the panic-catching arguments of `__rust_maybe_catch_panic`. -//! - A hack in `libpanic_unwind` that calls the `miri_start_unwind` intrinsic instead of the -//! target-native panic runtime. (This lives in the rustc repo.) -//! - An implementation of `miri_start_unwind` that stores its argument (the panic payload), and then -//! immediately returns, but on the *unwind* edge (not the normal return edge), thus initiating unwinding. -//! - A hook executed each time a frame is popped, such that if the frame pushed by `__rust_maybe_catch_panic` -//! gets popped *during unwinding*, we take the panic payload and store it according to the extra -//! metadata we remembered when pushing said frame. +//! Helper functions for causing panics. use rustc_abi::ExternAbi; use rustc_middle::{mir, ty}; -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. -#[derive(Debug)] -pub struct CatchUnwindData<'tcx> { - /// The `catch_fn` callback to call in case of a panic. - catch_fn: Pointer, - /// The `data` argument for that callback. - data: ImmTy<'tcx>, - /// The return place from the original call to `try`. - dest: MPlaceTy<'tcx>, - /// The return block from the original call to `try`. - ret: Option, -} - -impl VisitProvenance for CatchUnwindData<'_> { - fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let CatchUnwindData { catch_fn, data, dest, ret: _ } = self; - catch_fn.visit_provenance(visit); - data.visit_provenance(visit); - dest.visit_provenance(visit); - } -} - impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - /// Handles the special `miri_start_unwind` intrinsic, which is called - /// by libpanic_unwind to delegate the actual unwinding process to Miri. - fn handle_miri_start_unwind(&mut self, payload: &OpTy<'tcx>) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - trace!("miri_start_unwind: {:?}", this.frame().instance()); - - let payload = this.read_immediate(payload)?; - let thread = this.active_thread_mut(); - thread.unwind_payloads.push(payload); - - interp_ok(()) - } - - /// Handles the `catch_unwind` intrinsic. - fn handle_catch_unwind( - &mut self, - args: &[OpTy<'tcx>], - dest: &MPlaceTy<'tcx>, - ret: Option, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - // Signature: - // fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32 - // Calls `try_fn` with `data` as argument. If that executes normally, returns 0. - // If that unwinds, calls `catch_fn` with the first argument being `data` and - // then second argument being a target-dependent `payload` (i.e. it is up to us to define - // what that is), and returns 1. - // The `payload` is passed (by libstd) to `__rust_panic_cleanup`, which is then expected to - // return a `Box`. - // In Miri, `miri_start_unwind` is passed exactly that type, so we make the `payload` simply - // a pointer to `Box`. - - // 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)?; - - // Now we make a function call, and pass `data` as first and only argument. - let f_instance = this.get_ptr_fn(try_fn)?.as_instance()?; - trace!("try_fn: {:?}", f_instance); - #[allow(clippy::cloned_ref_to_slice_refs)] // the code is clearer as-is - this.call_function( - f_instance, - ExternAbi::Rust, - &[data.clone()], - None, - // Directly return to caller. - StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Continue }, - )?; - - // We ourselves will return `0`, eventually (will be overwritten if we catch a panic). - this.write_null(dest)?; - - // In unwind mode, we tag this frame with the extra data needed to catch unwinding. - // This lets `handle_stack_pop` (below) know that we should stop unwinding - // when we pop this frame. - if this.tcx.sess.panic_strategy() == PanicStrategy::Unwind { - this.frame_mut().extra.catch_unwind = - Some(CatchUnwindData { catch_fn, data, dest: dest.clone(), ret }); - } - - interp_ok(()) - } - - fn handle_stack_pop_unwind( - &mut self, - mut extra: FrameExtra<'tcx>, - unwinding: bool, - ) -> InterpResult<'tcx, ReturnAction> { - let this = self.eval_context_mut(); - trace!("handle_stack_pop_unwind(extra = {:?}, unwinding = {})", extra, unwinding); - - // We only care about `catch_panic` if we're unwinding - if we're doing a normal - // return, then we don't need to do anything special. - if let (true, Some(catch_unwind)) = (unwinding, extra.catch_unwind.take()) { - // We've just popped a frame that was pushed by `catch_unwind`, - // and we are unwinding, so we should catch that. - trace!( - "unwinding: found catch_panic frame during unwinding: {:?}", - this.frame().instance() - ); - - // We set the return value of `catch_unwind` to 1, since there was a panic. - this.write_scalar(Scalar::from_i32(1), &catch_unwind.dest)?; - - // The Thread's `panic_payload` holds what was passed to `miri_start_unwind`. - // This is exactly the second argument we need to pass to `catch_fn`. - let payload = this.active_thread_mut().unwind_payloads.pop().unwrap(); - - // Push the `catch_fn` stackframe. - let f_instance = this.get_ptr_fn(catch_unwind.catch_fn)?.as_instance()?; - trace!("catch_fn: {:?}", f_instance); - this.call_function( - f_instance, - ExternAbi::Rust, - &[catch_unwind.data, payload], - None, - // Directly return to caller of `catch_unwind`. - StackPopCleanup::Goto { - ret: catch_unwind.ret, - // `catch_fn` must not unwind. - unwind: mir::UnwindAction::Unreachable, - }, - )?; - - // We pushed a new stack frame, the engine should not do any jumping now! - interp_ok(ReturnAction::NoJump) - } else { - interp_ok(ReturnAction::Normal) - } - } - /// Start a panic in the interpreter with the given message as payload. fn start_panic(&mut self, msg: &str, unwind: mir::UnwindAction) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/unwind.rs b/src/tools/miri/src/shims/unwind.rs new file mode 100644 index 000000000000..7cbbbb7f4d71 --- /dev/null +++ b/src/tools/miri/src/shims/unwind.rs @@ -0,0 +1,160 @@ +//! Unwinding runtime for Miri. +//! +//! The core pieces of the runtime are: +//! - An implementation of `catch_unwind` that pushes the invoked stack frame with +//! some extra metadata derived from the panic-catching arguments of `catch_unwind`. +//! - A hack in `libpanic_unwind` that calls the `miri_start_unwind` intrinsic instead of the +//! target-native panic runtime. (This lives in the rustc repo.) +//! - An implementation of `miri_start_unwind` that stores its argument (the panic payload), and +//! then immediately returns, but on the *unwind* edge (not the normal return edge), thus +//! initiating unwinding. +//! - A hook executed each time a frame is popped, such that if the frame pushed by `catch_unwind` +//! gets popped *during unwinding*, we take the panic payload and store it according to the extra +//! metadata we remembered when pushing said frame. + +use rustc_abi::ExternAbi; +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. +#[derive(Debug)] +pub struct CatchUnwindData<'tcx> { + /// The `catch_fn` callback to call in case of a panic. + catch_fn: Pointer, + /// The `data` argument for that callback. + data: ImmTy<'tcx>, + /// The return place from the original call to `try`. + dest: MPlaceTy<'tcx>, + /// The return block from the original call to `try`. + ret: Option, +} + +impl VisitProvenance for CatchUnwindData<'_> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + let CatchUnwindData { catch_fn, data, dest, ret: _ } = self; + catch_fn.visit_provenance(visit); + data.visit_provenance(visit); + dest.visit_provenance(visit); + } +} + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + /// Handles the special `miri_start_unwind` intrinsic, which is called + /// by libpanic_unwind to delegate the actual unwinding process to Miri. + fn handle_miri_start_unwind(&mut self, payload: &OpTy<'tcx>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + trace!("miri_start_unwind: {:?}", this.frame().instance()); + + let payload = this.read_immediate(payload)?; + let thread = this.active_thread_mut(); + thread.unwind_payloads.push(payload); + + interp_ok(()) + } + + /// Handles the `catch_unwind` intrinsic. + fn handle_catch_unwind( + &mut self, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, + ret: Option, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + // Signature: + // fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32 + // Calls `try_fn` with `data` as argument. If that executes normally, returns 0. + // If that unwinds, calls `catch_fn` with the first argument being `data` and + // then second argument being a target-dependent `payload` (i.e. it is up to us to define + // what that is), and returns 1. + // The `payload` is passed (by libstd) to `__rust_panic_cleanup`, which is then expected to + // return a `Box`. + // In Miri, `miri_start_unwind` is passed exactly that type, so we make the `payload` simply + // a pointer to `Box`. + + // 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)?; + + // Now we make a function call, and pass `data` as first and only argument. + let f_instance = this.get_ptr_fn(try_fn)?.as_instance()?; + trace!("try_fn: {:?}", f_instance); + #[allow(clippy::cloned_ref_to_slice_refs)] // the code is clearer as-is + this.call_function( + f_instance, + ExternAbi::Rust, + &[data.clone()], + None, + // Directly return to caller. + StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Continue }, + )?; + + // We ourselves will return `0`, eventually (will be overwritten if we catch a panic). + this.write_null(dest)?; + + // In unwind mode, we tag this frame with the extra data needed to catch unwinding. + // This lets `handle_stack_pop` (below) know that we should stop unwinding + // when we pop this frame. + if this.tcx.sess.panic_strategy() == PanicStrategy::Unwind { + this.frame_mut().extra.catch_unwind = + Some(CatchUnwindData { catch_fn, data, dest: dest.clone(), ret }); + } + + interp_ok(()) + } + + fn handle_stack_pop_unwind( + &mut self, + mut extra: FrameExtra<'tcx>, + unwinding: bool, + ) -> InterpResult<'tcx, ReturnAction> { + let this = self.eval_context_mut(); + trace!("handle_stack_pop_unwind(extra = {:?}, unwinding = {})", extra, unwinding); + + // We only care about `catch_panic` if we're unwinding - if we're doing a normal + // return, then we don't need to do anything special. + if let (true, Some(catch_unwind)) = (unwinding, extra.catch_unwind.take()) { + // We've just popped a frame that was pushed by `catch_unwind`, + // and we are unwinding, so we should catch that. + trace!( + "unwinding: found catch_panic frame during unwinding: {:?}", + this.frame().instance() + ); + + // We set the return value of `catch_unwind` to 1, since there was a panic. + this.write_scalar(Scalar::from_i32(1), &catch_unwind.dest)?; + + // The Thread's `panic_payload` holds what was passed to `miri_start_unwind`. + // This is exactly the second argument we need to pass to `catch_fn`. + let payload = this.active_thread_mut().unwind_payloads.pop().unwrap(); + + // Push the `catch_fn` stackframe. + let f_instance = this.get_ptr_fn(catch_unwind.catch_fn)?.as_instance()?; + trace!("catch_fn: {:?}", f_instance); + this.call_function( + f_instance, + ExternAbi::Rust, + &[catch_unwind.data, payload], + None, + // Directly return to caller of `catch_unwind`. + StackPopCleanup::Goto { + ret: catch_unwind.ret, + // `catch_fn` must not unwind. + unwind: mir::UnwindAction::Unreachable, + }, + )?; + + // We pushed a new stack frame, the engine should not do any jumping now! + interp_ok(ReturnAction::NoJump) + } else { + interp_ok(ReturnAction::Normal) + } + } +} From 229be21d0d5297a66e7fe6b56606d0549bfccd5f Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 24 Jun 2025 16:09:42 +0800 Subject: [PATCH 062/363] Add ui test unnessary-error-issue-138401.rs Signed-off-by: xizheyin --- .../issues/unnessary-error-issue-138401.rs | 7 +++++++ .../unnessary-error-issue-138401.stderr | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/ui/parser/issues/unnessary-error-issue-138401.rs create mode 100644 tests/ui/parser/issues/unnessary-error-issue-138401.stderr diff --git a/tests/ui/parser/issues/unnessary-error-issue-138401.rs b/tests/ui/parser/issues/unnessary-error-issue-138401.rs new file mode 100644 index 000000000000..e5e5f1ee4e9c --- /dev/null +++ b/tests/ui/parser/issues/unnessary-error-issue-138401.rs @@ -0,0 +1,7 @@ +pub fn foo(x: i64) -> i64 { + x.abs) + //~^ ERROR mismatched closing delimiter +} +//~^ ERROR unexpected closing delimiter: `}` + +fn main() {} diff --git a/tests/ui/parser/issues/unnessary-error-issue-138401.stderr b/tests/ui/parser/issues/unnessary-error-issue-138401.stderr new file mode 100644 index 000000000000..b50f77f1247c --- /dev/null +++ b/tests/ui/parser/issues/unnessary-error-issue-138401.stderr @@ -0,0 +1,19 @@ +error: mismatched closing delimiter: `)` + --> $DIR/unnessary-error-issue-138401.rs:1:27 + | +LL | pub fn foo(x: i64) -> i64 { + | ^ unclosed delimiter +LL | x.abs) + | ^ mismatched closing delimiter + +error: unexpected closing delimiter: `}` + --> $DIR/unnessary-error-issue-138401.rs:4:1 + | +LL | x.abs) + | - missing open `(` for this delimiter +LL | +LL | } + | ^ unexpected closing delimiter + +error: aborting due to 2 previous errors + From 2412f8921ce39b986664e27c71b07f0ae24ac100 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 7 Jul 2025 15:39:31 +0000 Subject: [PATCH 063/363] UWP: link ntdll functions using raw-dylib --- library/std/src/sys/pal/windows/c.rs | 69 ++++------------------------ library/windows_targets/src/lib.rs | 23 +++++++++- 2 files changed, 30 insertions(+), 62 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index eee169d410a9..edac5262a4e9 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -197,7 +197,7 @@ compat_fn_optional! { pub fn WakeByAddressSingle(address: *const c_void); } -#[cfg(any(target_vendor = "win7", target_vendor = "uwp"))] +#[cfg(any(target_vendor = "win7"))] compat_fn_with_fallback! { pub static NTDLL: &CStr = c"ntdll"; @@ -228,65 +228,14 @@ compat_fn_with_fallback! { ) -> NTSTATUS { panic!("keyed events not available") } +} - // These functions are available on UWP when lazily loaded. They will fail WACK if loaded statically. - #[cfg(target_vendor = "uwp")] - pub fn NtCreateFile( - filehandle: *mut HANDLE, - desiredaccess: FILE_ACCESS_RIGHTS, - objectattributes: *const OBJECT_ATTRIBUTES, - iostatusblock: *mut IO_STATUS_BLOCK, - allocationsize: *const i64, - fileattributes: FILE_FLAGS_AND_ATTRIBUTES, - shareaccess: FILE_SHARE_MODE, - createdisposition: NTCREATEFILE_CREATE_DISPOSITION, - createoptions: NTCREATEFILE_CREATE_OPTIONS, - eabuffer: *const c_void, - ealength: u32 - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - #[cfg(target_vendor = "uwp")] - pub fn NtOpenFile( - filehandle: *mut HANDLE, - desiredaccess: u32, - objectattributes: *const OBJECT_ATTRIBUTES, - iostatusblock: *mut IO_STATUS_BLOCK, - shareaccess: u32, - openoptions: u32 - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - #[cfg(target_vendor = "uwp")] - pub fn NtReadFile( - filehandle: HANDLE, - event: HANDLE, - apcroutine: PIO_APC_ROUTINE, - apccontext: *const c_void, - iostatusblock: *mut IO_STATUS_BLOCK, - buffer: *mut c_void, - length: u32, - byteoffset: *const i64, - key: *const u32 - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - #[cfg(target_vendor = "uwp")] - pub fn NtWriteFile( - filehandle: HANDLE, - event: HANDLE, - apcroutine: PIO_APC_ROUTINE, - apccontext: *const c_void, - iostatusblock: *mut IO_STATUS_BLOCK, - buffer: *const c_void, - length: u32, - byteoffset: *const i64, - key: *const u32 - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - #[cfg(target_vendor = "uwp")] - pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> u32 { - Status as u32 +cfg_if::cfg_if! { + if #[cfg(target_vendor = "uwp")] { + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS); + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS); + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32); } } diff --git a/library/windows_targets/src/lib.rs b/library/windows_targets/src/lib.rs index bce54c5ffcef..9e82e6a72000 100644 --- a/library/windows_targets/src/lib.rs +++ b/library/windows_targets/src/lib.rs @@ -7,8 +7,7 @@ #![feature(decl_macro)] #![feature(no_core)] -#[cfg(feature = "windows_raw_dylib")] -pub macro link { +pub macro link_raw_dylib { ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( #[cfg_attr(not(target_arch = "x86"), link(name = $library, kind = "raw-dylib", modifiers = "+verbatim"))] #[cfg_attr(target_arch = "x86", link(name = $library, kind = "raw-dylib", modifiers = "+verbatim", import_name_type = "undecorated"))] @@ -18,6 +17,26 @@ pub macro link { } ) } + +pub macro link_dylib { + ($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)*; + } + ) +} + +#[cfg(feature = "windows_raw_dylib")] +pub macro link($($tt: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)*) => ( From e296e6bdfed270453e5423e68cb9f3b7ca49fec3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Jul 2025 17:53:23 +0200 Subject: [PATCH 064/363] move our data structures into a central location --- .../src/borrow_tracker/stacked_borrows/mod.rs | 4 ++-- .../src/borrow_tracker/tree_borrows/mod.rs | 2 +- .../src/borrow_tracker/tree_borrows/tree.rs | 6 ++--- src/tools/miri/src/concurrency/data_race.rs | 4 ++-- src/tools/miri/src/concurrency/mod.rs | 1 - src/tools/miri/src/concurrency/weak_memory.rs | 2 +- .../dedup_range_map.rs} | 22 +++++++++---------- src/tools/miri/src/data_structures/mod.rs | 3 +++ .../{ => data_structures}/mono_hash_map.rs | 0 .../range_object_map.rs | 0 src/tools/miri/src/lib.rs | 7 +++--- 11 files changed, 26 insertions(+), 25 deletions(-) rename src/tools/miri/src/{range_map.rs => data_structures/dedup_range_map.rs} (95%) create mode 100644 src/tools/miri/src/data_structures/mod.rs rename src/tools/miri/src/{ => data_structures}/mono_hash_map.rs (100%) rename src/tools/miri/src/{concurrency => data_structures}/range_object_map.rs (100%) diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index b8bcacf7c994..834a4b41f224 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -30,7 +30,7 @@ pub type AllocState = Stacks; #[derive(Clone, Debug)] pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. - stacks: RangeMap, + stacks: DedupRangeMap, /// Stores past operations on this allocation history: AllocHistory, /// The set of tags that have been exposed inside this allocation. @@ -468,7 +468,7 @@ impl<'tcx> Stacks { let stack = Stack::new(item); Stacks { - stacks: RangeMap::new(size, stack), + stacks: DedupRangeMap::new(size, stack), history: AllocHistory::new(id, item, machine), exposed_tags: FxHashSet::default(), } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index a0761cb07a1d..c157c69d7c84 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -314,7 +314,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let span = this.machine.current_span(); // Store initial permissions and their corresponding range. - let mut perms_map: RangeMap = RangeMap::new( + let mut perms_map: DedupRangeMap = DedupRangeMap::new( ptr_size, LocationState::new_accessed(Permission::new_disabled(), IdempotentForeignAccess::None), // this will be overwritten ); diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 48e4a19e263f..1f29bcfc2b03 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -247,7 +247,7 @@ pub struct Tree { /// `unwrap` any `perm.get(key)`. /// /// We do uphold the fact that `keys(perms)` is a subset of `keys(nodes)` - pub(super) rperms: RangeMap>, + pub(super) rperms: DedupRangeMap>, /// The index of the root node. pub(super) root: UniIndex, } @@ -609,7 +609,7 @@ impl Tree { IdempotentForeignAccess::None, ), ); - RangeMap::new(size, perms) + DedupRangeMap::new(size, perms) }; Self { root: root_idx, nodes, rperms, tag_mapping } } @@ -631,7 +631,7 @@ impl<'tcx> Tree { base_offset: Size, parent_tag: BorTag, new_tag: BorTag, - initial_perms: RangeMap, + initial_perms: DedupRangeMap, default_perm: Permission, protected: bool, span: Span, diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index b5e7e9d0ac0d..38d76f5cf73b 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -997,7 +997,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { #[derive(Debug, Clone)] pub struct VClockAlloc { /// Assigning each byte a MemoryCellClocks. - alloc_ranges: RefCell>, + alloc_ranges: RefCell>, } impl VisitProvenance for VClockAlloc { @@ -1045,7 +1045,7 @@ impl VClockAlloc { (VTimestamp::ZERO, global.thread_index(ThreadId::MAIN_THREAD)), }; VClockAlloc { - alloc_ranges: RefCell::new(RangeMap::new( + alloc_ranges: RefCell::new(DedupRangeMap::new( len, MemoryCellClocks::new(alloc_timestamp, alloc_index), )), diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs index 49bcc0d30b50..c2ea8a00decd 100644 --- a/src/tools/miri/src/concurrency/mod.rs +++ b/src/tools/miri/src/concurrency/mod.rs @@ -2,7 +2,6 @@ pub mod cpu_affinity; pub mod data_race; mod data_race_handler; pub mod init_once; -mod range_object_map; pub mod sync; pub mod thread; mod vector_clock; diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 95c010be2fd2..a752ef7e4548 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -90,9 +90,9 @@ use rustc_data_structures::fx::FxHashMap; use super::AllocDataRaceHandler; use super::data_race::{GlobalState as DataRaceState, ThreadClockSet}; -use super::range_object_map::{AccessType, RangeObjectMap}; use super::vector_clock::{VClock, VTimestamp, VectorIdx}; use crate::concurrency::GlobalDataRaceHandler; +use crate::data_structures::range_object_map::{AccessType, RangeObjectMap}; use crate::*; pub type AllocState = StoreBufferAlloc; diff --git a/src/tools/miri/src/range_map.rs b/src/tools/miri/src/data_structures/dedup_range_map.rs similarity index 95% rename from src/tools/miri/src/range_map.rs rename to src/tools/miri/src/data_structures/dedup_range_map.rs index 29a5a8537a41..56e9883b1caa 100644 --- a/src/tools/miri/src/range_map.rs +++ b/src/tools/miri/src/data_structures/dedup_range_map.rs @@ -17,18 +17,18 @@ struct Elem { data: T, } #[derive(Clone, Debug)] -pub struct RangeMap { +pub struct DedupRangeMap { v: Vec>, } -impl RangeMap { +impl DedupRangeMap { /// Creates a new `RangeMap` for the given size, and with the given initial value used for /// the entire range. #[inline(always)] - pub fn new(size: Size, init: T) -> RangeMap { + pub fn new(size: Size, init: T) -> DedupRangeMap { let size = size.bytes(); let v = if size > 0 { vec![Elem { range: 0..size, data: init }] } else { Vec::new() }; - RangeMap { v } + DedupRangeMap { v } } pub fn size(&self) -> Size { @@ -246,7 +246,7 @@ mod tests { use super::*; /// Query the map at every offset in the range and collect the results. - fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { + fn to_vec(map: &DedupRangeMap, offset: u64, len: u64) -> Vec { (offset..offset + len) .map(|i| { map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|(_, &t)| t).unwrap() @@ -256,7 +256,7 @@ mod tests { #[test] fn basic_insert() { - let mut map = RangeMap::::new(Size::from_bytes(20), -1); + let mut map = DedupRangeMap::::new(Size::from_bytes(20), -1); // Insert. for (_, x) in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) { *x = 42; @@ -278,7 +278,7 @@ mod tests { #[test] fn gaps() { - let mut map = RangeMap::::new(Size::from_bytes(20), -1); + let mut map = DedupRangeMap::::new(Size::from_bytes(20), -1); for (_, x) in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) { *x = 42; } @@ -319,26 +319,26 @@ mod tests { #[test] #[should_panic] fn out_of_range_iter_mut() { - let mut map = RangeMap::::new(Size::from_bytes(20), -1); + let mut map = DedupRangeMap::::new(Size::from_bytes(20), -1); let _ = map.iter_mut(Size::from_bytes(11), Size::from_bytes(11)); } #[test] #[should_panic] fn out_of_range_iter() { - let map = RangeMap::::new(Size::from_bytes(20), -1); + let map = DedupRangeMap::::new(Size::from_bytes(20), -1); let _ = map.iter(Size::from_bytes(11), Size::from_bytes(11)); } #[test] fn empty_map_iter() { - let map = RangeMap::::new(Size::from_bytes(0), -1); + let map = DedupRangeMap::::new(Size::from_bytes(0), -1); let _ = map.iter(Size::from_bytes(0), Size::from_bytes(0)); } #[test] fn empty_map_iter_mut() { - let mut map = RangeMap::::new(Size::from_bytes(0), -1); + let mut map = DedupRangeMap::::new(Size::from_bytes(0), -1); let _ = map.iter_mut(Size::from_bytes(0), Size::from_bytes(0)); } } diff --git a/src/tools/miri/src/data_structures/mod.rs b/src/tools/miri/src/data_structures/mod.rs new file mode 100644 index 000000000000..d4468bc57eae --- /dev/null +++ b/src/tools/miri/src/data_structures/mod.rs @@ -0,0 +1,3 @@ +pub mod dedup_range_map; +pub mod mono_hash_map; +pub mod range_object_map; diff --git a/src/tools/miri/src/mono_hash_map.rs b/src/tools/miri/src/data_structures/mono_hash_map.rs similarity index 100% rename from src/tools/miri/src/mono_hash_map.rs rename to src/tools/miri/src/data_structures/mono_hash_map.rs diff --git a/src/tools/miri/src/concurrency/range_object_map.rs b/src/tools/miri/src/data_structures/range_object_map.rs similarity index 100% rename from src/tools/miri/src/concurrency/range_object_map.rs rename to src/tools/miri/src/data_structures/range_object_map.rs diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index ca99d69b32d0..642b7ee98401 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -75,16 +75,15 @@ mod alloc_addresses; mod borrow_tracker; mod clock; mod concurrency; +mod data_structures; mod diagnostics; mod eval; mod helpers; mod intrinsics; mod machine; mod math; -mod mono_hash_map; mod operator; mod provenance_gc; -mod range_map; mod shims; // Establish a "crate-wide prelude": we often import `crate::*`. @@ -132,6 +131,8 @@ pub use crate::concurrency::thread::{ ThreadManager, TimeoutAnchor, TimeoutClock, UnblockKind, }; pub use crate::concurrency::{GenmcConfig, GenmcCtx}; +pub use crate::data_structures::dedup_range_map::DedupRangeMap; +pub use crate::data_structures::mono_hash_map::MonoHashMap; pub use crate::diagnostics::{ EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error, }; @@ -145,10 +146,8 @@ pub use crate::machine::{ AllocExtra, DynMachineCallback, FrameExtra, MachineCallback, MemoryKind, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind, PrimitiveLayouts, Provenance, ProvenanceExtra, }; -pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as _; pub use crate::provenance_gc::{EvalContextExt as _, LiveAllocs, VisitProvenance, VisitWith}; -pub use crate::range_map::RangeMap; pub use crate::shims::EmulateItemResult; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _}; From 0d306dd7f43574eede5bfdd883c298a07da0b2cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Jul 2025 08:22:53 +0200 Subject: [PATCH 065/363] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 7ca7acb3fd70..a9394819541f 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -ca98d4d4b3114116203699c2734805547df86f9a +688ea65df6a47866d0f72a00f1e18b47a7edf83b From 922ee88762e36dea38113f84ca3898b2e59531ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 8 Jul 2025 08:57:05 +0200 Subject: [PATCH 066/363] Mention that stdarch is managed by josh-sync --- src/doc/rustc-dev-guide/src/external-repos.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index fc40b5d2bfa5..0f7322357b9d 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -43,9 +43,9 @@ implement a new tool feature or test, that should happen in one collective rustc * 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` + * `rustc-dev-guide` ([josh sync](#synchronizing-a-josh-subtree)) * `compiler-builtins` - * `stdarch` + * `stdarch` ([josh sync](#synchronizing-a-josh-subtree)) ### Josh subtrees @@ -57,6 +57,7 @@ We use a dedicated tool called [`rustc-josh-sync`][josh-sync] for performing Jos Currently, we are migrating Josh repositories to it. So far, it is used in: - rustc-dev-guide +- stdarch To use the tool, first install it with `cargo install --locked --git https://github.com/rust-lang/josh-sync`. From 24a25dbb88bc6a6dafe7bad2337948f0a2b37c0f Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 10 Jun 2025 23:46:39 +0800 Subject: [PATCH 067/363] Revert `tests/run-make/mte-ffi` changes Partially reverts commit 40311c4dcf666e8bddcec4a8059e7d9f12bbd363. --- tests/run-make/mte-ffi/bar.h | 2 -- tests/run-make/mte-ffi/bar_float.c | 4 ++-- tests/run-make/mte-ffi/bar_int.c | 2 +- tests/run-make/mte-ffi/bar_string.c | 3 +-- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/run-make/mte-ffi/bar.h b/tests/run-make/mte-ffi/bar.h index 9b030c618d18..a2292ae02a30 100644 --- a/tests/run-make/mte-ffi/bar.h +++ b/tests/run-make/mte-ffi/bar.h @@ -1,5 +1,3 @@ -// FIXME(#141600) the mte-ffi test doesn't fail in aarch64-gnu - #ifndef __BAR_H #define __BAR_H diff --git a/tests/run-make/mte-ffi/bar_float.c b/tests/run-make/mte-ffi/bar_float.c index acc2f5d9266d..a1590f62765a 100644 --- a/tests/run-make/mte-ffi/bar_float.c +++ b/tests/run-make/mte-ffi/bar_float.c @@ -3,9 +3,9 @@ #include #include "bar.h" -extern void foo(float*); +extern void foo(char*); -void bar(float *ptr) { +void bar(char *ptr) { if (((uintptr_t)ptr >> 56) != 0x1f) { fprintf(stderr, "Top byte corrupted on Rust -> C FFI boundary!\n"); exit(1); diff --git a/tests/run-make/mte-ffi/bar_int.c b/tests/run-make/mte-ffi/bar_int.c index c92e765302c1..d1c79e95dc9c 100644 --- a/tests/run-make/mte-ffi/bar_int.c +++ b/tests/run-make/mte-ffi/bar_int.c @@ -5,7 +5,7 @@ extern void foo(unsigned int *); -void bar(unsigned int *ptr) { +void bar(char *ptr) { if (((uintptr_t)ptr >> 56) != 0x1f) { fprintf(stderr, "Top byte corrupted on Rust -> C FFI boundary!\n"); exit(1); diff --git a/tests/run-make/mte-ffi/bar_string.c b/tests/run-make/mte-ffi/bar_string.c index 8e1202f6fd15..5669ffd6695e 100644 --- a/tests/run-make/mte-ffi/bar_string.c +++ b/tests/run-make/mte-ffi/bar_string.c @@ -1,7 +1,6 @@ #include #include #include -#include #include "bar.h" extern void foo(char*); @@ -33,7 +32,7 @@ int main(void) // Store an arbitrary tag in bits 56-59 of the pointer (where an MTE tag may be), // and a different value in the ignored top 4 bits. - ptr = (char *)((uintptr_t)ptr | 0x1fl << 56); + ptr = (unsigned int *)((uintptr_t)ptr | 0x1fl << 56); if (mte_enabled()) { set_tag(ptr); From 37136dd9748736d68c050d2dc132045b8b57ce3e Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 8 Jul 2025 16:39:03 +0800 Subject: [PATCH 068/363] Disable `tests/run-make/mte-ffi` See RUST-141600: this test is broken in two ways: 1. This test triggers `-Wincompatible-pointer-types` on GCC 14. 2. This test requires ARMv8.5+ w/ MTE extensions enabled, but GHA CI runner hardware do not have this enabled. --- tests/run-make/mte-ffi/rmake.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/run-make/mte-ffi/rmake.rs b/tests/run-make/mte-ffi/rmake.rs index a8da0dc0ee03..71d8318d9465 100644 --- a/tests/run-make/mte-ffi/rmake.rs +++ b/tests/run-make/mte-ffi/rmake.rs @@ -2,6 +2,13 @@ //! FFI boundaries (C <-> Rust). This test does not require MTE: whilst the test will use MTE if //! available, if it is not, arbitrary tag bits are set using TBI. +//@ ignore-test (FIXME #141600) +// +// FIXME(#141600): this test is broken in two ways: +// 1. This test triggers `-Wincompatible-pointer-types` on GCC 14. +// 2. This test requires ARMv8.5+ w/ MTE extensions enabled, but GHA CI runner hardware do not have +// this enabled. + //@ only-aarch64-unknown-linux-gnu // Reason: this test is only valid for AArch64 with `gcc`. The linker must be explicitly specified // when cross-compiling, so it is limited to `aarch64-unknown-linux-gnu`. From d44dcd451326d32516c22ee5f998304afaf19c4d Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Tue, 8 Jul 2025 10:16:44 +0000 Subject: [PATCH 069/363] update to literal-escaper-0.0.5 --- Cargo.lock | 4 ++-- compiler/rustc_ast/Cargo.toml | 2 +- compiler/rustc_ast/src/util/literal.rs | 6 +++--- compiler/rustc_parse/Cargo.toml | 2 +- compiler/rustc_parse_format/Cargo.toml | 2 +- compiler/rustc_proc_macro/Cargo.toml | 2 +- library/Cargo.lock | 4 ++-- library/proc_macro/Cargo.toml | 2 +- library/proc_macro/src/lib.rs | 6 +++--- src/tools/lint-docs/Cargo.toml | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6d823c5b5a59..bc34a8dc777b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3260,9 +3260,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-literal-escaper" -version = "0.0.4" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b" +checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b" [[package]] name = "rustc-main" diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 5de2e69072fa..155e14a3796e 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start bitflags = "2.4.1" memchr = "2.7.4" -rustc-literal-escaper = "0.0.4" +rustc-literal-escaper = "0.0.5" rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index fa7878873e56..2dfd695d8802 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -126,11 +126,11 @@ impl LitKind { token::CStr => { let s = symbol.as_str(); let mut buf = Vec::with_capacity(s.len()); - unescape_c_str(s, |_span, c| match c { + unescape_c_str(s, |_span, res| match res { Ok(MixedUnit::Char(c)) => { - buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) + buf.extend_from_slice(c.get().encode_utf8(&mut [0; 4]).as_bytes()) } - Ok(MixedUnit::HighByte(b)) => buf.push(b), + Ok(MixedUnit::HighByte(b)) => buf.push(b.get()), Err(err) => { assert!(!err.is_fatal(), "failed to unescape C string literal") } diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index c4a0ae2ce9dd..a92012f83292 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -rustc-literal-escaper = "0.0.4" +rustc-literal-escaper = "0.0.5" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index 0666ae294092..d178fcda1fb9 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-literal-escaper = "0.0.4" +rustc-literal-escaper = "0.0.5" rustc_lexer = { path = "../rustc_lexer" } # tidy-alphabetical-end diff --git a/compiler/rustc_proc_macro/Cargo.toml b/compiler/rustc_proc_macro/Cargo.toml index 748fa944e286..762acf9a1eb4 100644 --- a/compiler/rustc_proc_macro/Cargo.toml +++ b/compiler/rustc_proc_macro/Cargo.toml @@ -15,7 +15,7 @@ test = false doctest = false [dependencies] -rustc-literal-escaper = "0.0.4" +rustc-literal-escaper = "0.0.5" [features] rustc-dep-of-std = [] diff --git a/library/Cargo.lock b/library/Cargo.lock index c681c5935df5..8b5275e5065e 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -271,9 +271,9 @@ dependencies = [ [[package]] name = "rustc-literal-escaper" -version = "0.0.4" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b" +checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b" dependencies = [ "rustc-std-workspace-core", "rustc-std-workspace-std", diff --git a/library/proc_macro/Cargo.toml b/library/proc_macro/Cargo.toml index 8ea92088a84a..0042a6e8ece5 100644 --- a/library/proc_macro/Cargo.toml +++ b/library/proc_macro/Cargo.toml @@ -9,7 +9,7 @@ std = { path = "../std" } # `core` when resolving doc links. Without this line a different `core` will be # loaded from sysroot causing duplicate lang items and other similar errors. core = { path = "../core" } -rustc-literal-escaper = { version = "0.0.4", features = ["rustc-dep-of-std"] } +rustc-literal-escaper = { version = "0.0.5", features = ["rustc-dep-of-std"] } [features] default = ["rustc-dep-of-std"] diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index ff326342989b..162b4fdcc8ae 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1471,11 +1471,11 @@ impl Literal { let mut error = None; let mut buf = Vec::with_capacity(symbol.len()); - unescape_c_str(symbol, |_span, c| match c { + unescape_c_str(symbol, |_span, res| match res { Ok(MixedUnit::Char(c)) => { - buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) + buf.extend_from_slice(c.get().encode_utf8(&mut [0; 4]).as_bytes()) } - Ok(MixedUnit::HighByte(b)) => buf.push(b), + Ok(MixedUnit::HighByte(b)) => buf.push(b.get()), Err(err) => { if err.is_fatal() { error = Some(ConversionErrorKind::FailedToUnescape(err)); diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml index e914a2df2bad..6e1ab84ed18d 100644 --- a/src/tools/lint-docs/Cargo.toml +++ b/src/tools/lint-docs/Cargo.toml @@ -7,7 +7,7 @@ description = "A script to extract the lint documentation for the rustc book." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustc-literal-escaper = "0.0.4" +rustc-literal-escaper = "0.0.5" serde_json = "1.0.57" tempfile = "3.1.0" walkdir = "2.3.1" From 004478a829c7b4b7aa608f0f2d4d58a97c7836af Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 2 Jul 2025 13:19:41 +0000 Subject: [PATCH 070/363] int_log10.rs: change top level doc comments to outer --- library/core/src/num/int_log10.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/int_log10.rs b/library/core/src/num/int_log10.rs index 28a3f5d880ad..649a736b6e7b 100644 --- a/library/core/src/num/int_log10.rs +++ b/library/core/src/num/int_log10.rs @@ -1,5 +1,5 @@ -/// These functions compute the integer logarithm of their type, assuming -/// that someone has already checked that the value is strictly positive. +//! These functions compute the integer logarithm of their type, assuming +//! that someone has already checked that the value is strictly positive. // 0 < val <= u8::MAX #[inline] From f96d5d960256557a0c2434a308fd32c98e94aa7f Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 2 Jul 2025 13:29:16 +0000 Subject: [PATCH 071/363] collect.rs: remove empty line after doc comment --- library/core/src/fmt/mod.rs | 1 - library/core/src/iter/traits/collect.rs | 1 - library/core/src/lib.rs | 6 +++--- library/core/src/net/ip_addr.rs | 1 - library/core/src/primitive_docs.rs | 1 - library/core/src/str/mod.rs | 1 - 6 files changed, 3 insertions(+), 8 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 5e50eacec6ee..77ab1c4201cd 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -854,7 +854,6 @@ impl Display for Arguments<'_> { /// }"; /// assert_eq!(format!("The origin is: {origin:#?}"), expected); /// ``` - #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 3bc9cff8072b..ab2765006798 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -436,7 +436,6 @@ pub trait Extend { /// **For implementors:** For a collection to unsafely rely on this method's safety precondition (that is, /// invoke UB if they are violated), it must implement `extend_reserve` correctly. In other words, /// callers may assume that if they `extend_reserve`ed enough space they can call this method. - // This method is for internal usage only. It is only on the trait because of specialization's limitations. #[unstable(feature = "extend_one_unchecked", issue = "none")] #[doc(hidden)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 2f701171505c..de5174bcbf6f 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -39,9 +39,9 @@ //! return. You should mark your implementation using `#[panic_handler]`. //! //! * `rust_eh_personality` - is used by the failure mechanisms of the -//! compiler. This is often mapped to GCC's personality function, but crates -//! which do not trigger a panic can be assured that this function is never -//! called. The `lang` attribute is called `eh_personality`. +//! compiler. This is often mapped to GCC's personality function, but crates +//! which do not trigger a panic can be assured that this function is never +//! called. The `lang` attribute is called `eh_personality`. #![stable(feature = "core", since = "1.6.0")] #![doc( diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index aaa68e8d7d1a..49a7ae5de5c8 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -787,7 +787,6 @@ impl Ipv4Addr { /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml /// [unspecified address]: Ipv4Addr::UNSPECIFIED /// [broadcast address]: Ipv4Addr::BROADCAST - /// /// # Examples /// diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 2c77c55745b4..28124ac5aa8b 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1365,7 +1365,6 @@ mod prim_f16 {} /// x = a + b + c + d; // As written /// x = (a + c) + (b + d); // Reordered to shorten critical path and enable vectorization /// ``` - #[stable(feature = "rust1", since = "1.0.0")] mod prim_f32 {} diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index fe64132ff227..98b5e29009c4 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2648,7 +2648,6 @@ impl str { /// you're trying to parse into. /// /// `parse` can parse into any type that implements the [`FromStr`] trait. - /// /// # Errors /// From ca4a712b59b9ed216e8bb6e24140b08d7020c68c Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Thu, 3 Jul 2025 12:41:05 +0000 Subject: [PATCH 072/363] clippy fix: markdown indentation for indented items after line break --- library/core/src/async_iter/async_iter.rs | 10 +++++----- library/core/src/mem/mod.rs | 2 +- library/core/src/ptr/docs/as_uninit_slice.md | 20 ++++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs index 069c50c2531b..c21c08320bef 100644 --- a/library/core/src/async_iter/async_iter.rs +++ b/library/core/src/async_iter/async_iter.rs @@ -28,15 +28,15 @@ pub trait AsyncIterator { /// async iterator state: /// /// - `Poll::Pending` means that this async iterator's next value is not ready - /// yet. Implementations will ensure that the current task will be notified - /// when the next value may be ready. + /// yet. Implementations will ensure that the current task will be notified + /// when the next value may be ready. /// /// - `Poll::Ready(Some(val))` means that the async iterator has successfully - /// produced a value, `val`, and may produce further values on subsequent - /// `poll_next` calls. + /// produced a value, `val`, and may produce further values on subsequent + /// `poll_next` calls. /// /// - `Poll::Ready(None)` means that the async iterator has terminated, and - /// `poll_next` should not be invoked again. + /// `poll_next` should not be invoked again. /// /// # Panics /// diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index c00585de0649..8db52a38014e 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -36,7 +36,7 @@ pub use crate::intrinsics::transmute; /// * If you want to leak memory, see [`Box::leak`]. /// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`]. /// * If you want to dispose of a value properly, running its destructor, see -/// [`mem::drop`]. +/// [`mem::drop`]. /// /// # Safety /// diff --git a/library/core/src/ptr/docs/as_uninit_slice.md b/library/core/src/ptr/docs/as_uninit_slice.md index c80c04058838..1113f4748c2d 100644 --- a/library/core/src/ptr/docs/as_uninit_slice.md +++ b/library/core/src/ptr/docs/as_uninit_slice.md @@ -10,24 +10,24 @@ When calling this method, you have to ensure that *either* the pointer is null * all of the following is true: * The pointer must be [valid] for reads for `ptr.len() * size_of::()` many bytes, -and it must be properly aligned. This means in particular: + and it must be properly aligned. This means in particular: * The entire memory range of this slice must be contained within a single [allocation]! -Slices can never span across multiple allocations. + Slices can never span across multiple allocations. * The pointer must be aligned even for zero-length slices. One -reason for this is that enum layout optimizations may rely on references -(including slices of any length) being aligned and non-null to distinguish -them from other data. You can obtain a pointer that is usable as `data` -for zero-length slices using [`NonNull::dangling()`]. + reason for this is that enum layout optimizations may rely on references + (including slices of any length) being aligned and non-null to distinguish + them from other data. You can obtain a pointer that is usable as `data` + for zero-length slices using [`NonNull::dangling()`]. * The total size `ptr.len() * size_of::()` of the slice must be no larger than `isize::MAX`. -See the safety documentation of [`pointer::offset`]. + See the safety documentation of [`pointer::offset`]. * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is -arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. -In particular, while this reference exists, the memory the pointer points to must -not get mutated (except inside `UnsafeCell`). + arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. + In particular, while this reference exists, the memory the pointer points to must + not get mutated (except inside `UnsafeCell`). This applies even if the result of this method is unused! From 6b8bc68a503e0b27828404270759ab3523b1c91a Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 9 Jul 2025 07:13:44 +0200 Subject: [PATCH 073/363] use a consistent (and recommended) invocation ./x is recommended over running ./x.py directly, and is the more commonly-used invocation of bootstrap in the guide --- src/doc/rustc-dev-guide/src/autodiff/installation.md | 10 +++++----- src/doc/rustc-dev-guide/src/offload/installation.md | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md index c9b28dc43a6d..92e79b2f3831 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/installation.md +++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md @@ -13,7 +13,7 @@ cd rust Afterwards you can build rustc using: ```bash -./x.py build --stage 1 library +./x build --stage 1 library ``` Afterwards rustc toolchain link will allow you to use it through cargo: @@ -25,10 +25,10 @@ rustup toolchain install nightly # enables -Z unstable-options You can then run our test cases: ```bash -./x.py test --stage 1 tests/codegen/autodiff -./x.py test --stage 1 tests/pretty/autodiff -./x.py test --stage 1 tests/ui/autodiff -./x.py test --stage 1 tests/ui/feature-gates/feature-gate-autodiff.rs +./x test --stage 1 tests/codegen/autodiff +./x test --stage 1 tests/pretty/autodiff +./x test --stage 1 tests/ui/autodiff +./x test --stage 1 tests/ui/feature-gates/feature-gate-autodiff.rs ``` Autodiff is still experimental, so if you want to use it in your own projects, you will need to add `lto="fat"` to your Cargo.toml diff --git a/src/doc/rustc-dev-guide/src/offload/installation.md b/src/doc/rustc-dev-guide/src/offload/installation.md index 2536af09a236..8cfec44ec8e7 100644 --- a/src/doc/rustc-dev-guide/src/offload/installation.md +++ b/src/doc/rustc-dev-guide/src/offload/installation.md @@ -13,7 +13,7 @@ cd rust Afterwards you can build rustc using: ```bash -./x.py build --stage 1 library +./x build --stage 1 library ``` Afterwards rustc toolchain link will allow you to use it through cargo: @@ -40,7 +40,7 @@ This gives you a working LLVM build. ## Testing run ``` -./x.py test --stage 1 tests/codegen/gpu_offload +./x test --stage 1 tests/codegen/gpu_offload ``` ## Usage From 7b394d2650472866162adb1e3e775d7c43ed8854 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 9 Jul 2025 07:28:16 +0200 Subject: [PATCH 074/363] tweak some git clone commands - --depth=1 is more useful for once-off uses, like on ci - .git postfix on github repo url is not needed --- src/doc/rustc-dev-guide/src/autodiff/installation.md | 8 ++++---- src/doc/rustc-dev-guide/src/offload/installation.md | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md index 92e79b2f3831..a550f6d233eb 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/installation.md +++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md @@ -6,7 +6,7 @@ In the near future, `std::autodiff` should become available in nightly builds fo First you need to clone and configure the Rust repository: ```bash -git clone --depth=1 git@github.com:rust-lang/rust.git +git clone git@github.com:rust-lang/rust cd rust ./configure --enable-llvm-link-shared --enable-llvm-plugins --enable-llvm-enzyme --release-channel=nightly --enable-llvm-assertions --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs ``` @@ -45,7 +45,7 @@ apt install wget vim python3 git curl libssl-dev pkg-config lld ninja-build cmak ``` Then build rustc in a slightly altered way: ```bash -git clone --depth=1 https://github.com/rust-lang/rust.git +git clone https://github.com/rust-lang/rust cd rust ./configure --enable-llvm-link-shared --enable-llvm-plugins --enable-llvm-enzyme --release-channel=nightly --enable-llvm-assertions --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs ./x dist @@ -66,7 +66,7 @@ We recommend that approach, if you just want to use any of them and have no expe However, if you prefer to just build Enzyme without Rust, then these instructions might help. ```bash -git clone --depth=1 git@github.com:llvm/llvm-project.git +git clone git@github.com:llvm/llvm-project cd llvm-project mkdir build cd build @@ -77,7 +77,7 @@ ninja install This gives you a working LLVM build, now we can continue with building Enzyme. Leave the `llvm-project` folder, and execute the following commands: ```bash -git clone git@github.com:EnzymeAD/Enzyme.git +git clone git@github.com:EnzymeAD/Enzyme cd Enzyme/enzyme mkdir build cd build diff --git a/src/doc/rustc-dev-guide/src/offload/installation.md b/src/doc/rustc-dev-guide/src/offload/installation.md index 8cfec44ec8e7..1962314c70ac 100644 --- a/src/doc/rustc-dev-guide/src/offload/installation.md +++ b/src/doc/rustc-dev-guide/src/offload/installation.md @@ -6,7 +6,7 @@ In the future, `std::offload` should become available in nightly builds for user First you need to clone and configure the Rust repository: ```bash -git clone --depth=1 git@github.com:rust-lang/rust.git +git clone git@github.com:rust-lang/rust cd rust ./configure --enable-llvm-link-shared --release-channel=nightly --enable-llvm-assertions --enable-offload --enable-enzyme --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs ``` @@ -26,7 +26,7 @@ rustup toolchain install nightly # enables -Z unstable-options ## Build instruction for LLVM itself ```bash -git clone --depth=1 git@github.com:llvm/llvm-project.git +git clone git@github.com:llvm/llvm-project cd llvm-project mkdir build cd build From 3bd0b8909ca743f8089d256d3a4443787f966315 Mon Sep 17 00:00:00 2001 From: Nia Espera Date: Wed, 2 Jul 2025 02:55:41 +0200 Subject: [PATCH 075/363] various native-lib-trace-related fixups Co-Authored-By: Ralf Jung --- src/tools/miri/src/alloc/isolated_alloc.rs | 21 +- src/tools/miri/src/bin/miri.rs | 30 +- src/tools/miri/src/lib.rs | 8 +- src/tools/miri/src/shims/mod.rs | 4 +- src/tools/miri/src/shims/native_lib/mod.rs | 96 +++--- .../miri/src/shims/native_lib/trace/child.rs | 104 +++--- .../src/shims/native_lib/trace/messages.rs | 47 +-- .../miri/src/shims/native_lib/trace/mod.rs | 2 + .../miri/src/shims/native_lib/trace/parent.rs | 304 ++++++++---------- .../miri/src/shims/native_lib/trace/stub.rs | 34 ++ 10 files changed, 312 insertions(+), 338 deletions(-) create mode 100644 src/tools/miri/src/shims/native_lib/trace/stub.rs diff --git a/src/tools/miri/src/alloc/isolated_alloc.rs b/src/tools/miri/src/alloc/isolated_alloc.rs index a7bb9b4da758..7b2f1a3eebf3 100644 --- a/src/tools/miri/src/alloc/isolated_alloc.rs +++ b/src/tools/miri/src/alloc/isolated_alloc.rs @@ -302,23 +302,20 @@ impl IsolatedAlloc { } } - /// Returns a vector of page addresses managed by the allocator. - pub fn pages(&self) -> Vec { - let mut pages: Vec = - self.page_ptrs.iter().map(|p| p.expose_provenance().get()).collect(); - for (ptr, size) in self.huge_ptrs.iter() { - for i in 0..size / self.page_size { - pages.push(ptr.expose_provenance().get().strict_add(i * self.page_size)); - } - } - pages + /// Returns a list of page addresses managed by the allocator. + pub fn pages(&self) -> impl Iterator { + let pages = self.page_ptrs.iter().map(|p| p.expose_provenance().get()); + pages.chain(self.huge_ptrs.iter().flat_map(|(ptr, size)| { + (0..size / self.page_size) + .map(|i| ptr.expose_provenance().get().strict_add(i * self.page_size)) + })) } /// Protects all owned memory as `PROT_NONE`, preventing accesses. /// /// SAFETY: Accessing memory after this point will result in a segfault /// unless it is first unprotected. - pub unsafe fn prepare_ffi(&mut self) -> Result<(), nix::errno::Errno> { + pub unsafe fn start_ffi(&mut self) -> Result<(), nix::errno::Errno> { let prot = mman::ProtFlags::PROT_NONE; unsafe { self.mprotect(prot) } } @@ -326,7 +323,7 @@ impl IsolatedAlloc { /// Deprotects all owned memory by setting it to RW. Erroring here is very /// likely unrecoverable, so it may panic if applying those permissions /// fails. - pub fn unprep_ffi(&mut self) { + pub fn end_ffi(&mut self) { let prot = mman::ProtFlags::PROT_READ | mman::ProtFlags::PROT_WRITE; unsafe { self.mprotect(prot).unwrap(); diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index e3b579a4ac61..61cebedf0810 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -233,8 +233,6 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } else { let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, &config, None) .unwrap_or_else(|| { - //#[cfg(target_os = "linux")] - //miri::native_lib::register_retcode_sv(rustc_driver::EXIT_FAILURE); tcx.dcx().abort_if_errors(); rustc_driver::EXIT_FAILURE }); @@ -337,6 +335,9 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { fn exit(exit_code: i32) -> ! { // Drop the tracing guard before exiting, so tracing calls are flushed correctly. deinit_loggers(); + // Make sure the supervisor knows about the code code. + #[cfg(target_os = "linux")] + miri::native_lib::register_retcode_sv(exit_code); std::process::exit(exit_code); } @@ -355,6 +356,11 @@ fn run_compiler_and_exit( args: &[String], callbacks: &mut (dyn rustc_driver::Callbacks + Send), ) -> ! { + // Install the ctrlc handler that sets `rustc_const_eval::CTRL_C_RECEIVED`, even if + // MIRI_BE_RUSTC is set. We do this late so that when `native_lib::init_sv` is called, + // there are no other threads. + rustc_driver::install_ctrlc_handler(); + // Invoke compiler, catch any unwinding panics and handle return code. let exit_code = rustc_driver::catch_with_exit_code(move || rustc_driver::run_compiler(args, callbacks)); @@ -439,10 +445,6 @@ fn main() { let args = rustc_driver::catch_fatal_errors(|| rustc_driver::args::raw_args(&early_dcx)) .unwrap_or_else(|_| std::process::exit(rustc_driver::EXIT_FAILURE)); - // Install the ctrlc handler that sets `rustc_const_eval::CTRL_C_RECEIVED`, even if - // MIRI_BE_RUSTC is set. - rustc_driver::install_ctrlc_handler(); - // If the environment asks us to actually be rustc, then do that. if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") { // Earliest rustc setup. @@ -750,15 +752,15 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("crate arguments: {:?}", miri_config.args); - #[cfg(target_os = "linux")] if !miri_config.native_lib.is_empty() && miri_config.native_lib_enable_tracing { - // FIXME: This should display a diagnostic / warning on error - // SAFETY: If any other threads exist at this point (namely for the ctrlc - // handler), they will not interact with anything on the main rustc/Miri - // thread in an async-signal-unsafe way such as by accessing shared - // semaphores, etc.; the handler only calls `sleep()` and `exit()`, which - // are async-signal-safe, as is accessing atomics - //let _ = unsafe { miri::native_lib::init_sv() }; + // SAFETY: No other threads are running + #[cfg(target_os = "linux")] + if unsafe { miri::native_lib::init_sv() }.is_err() { + eprintln!( + "warning: The native-lib tracer could not be started. Is this an x86 Linux system, and does Miri have permissions to ptrace?\n\ + Falling back to non-tracing native-lib mode." + ); + } } run_compiler_and_exit( &rustc_args, diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 642b7ee98401..374f63a16604 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -96,10 +96,10 @@ pub use rustc_const_eval::interpret::{self, AllocMap, Provenance as _}; use rustc_middle::{bug, span_bug}; use tracing::{info, trace}; -//#[cfg(target_os = "linux")] -//pub mod native_lib { -// pub use crate::shims::{init_sv, register_retcode_sv}; -//} +#[cfg(target_os = "linux")] +pub mod native_lib { + pub use crate::shims::{init_sv, register_retcode_sv}; +} // Type aliases that set the provenance parameter. pub type Pointer = interpret::Pointer>; diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 60c0e289292b..b08ab101e947 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -22,8 +22,8 @@ pub mod tls; pub mod unwind; pub use self::files::FdTable; -//#[cfg(target_os = "linux")] -//pub use self::native_lib::trace::{init_sv, register_retcode_sv}; +#[cfg(target_os = "linux")] +pub use self::native_lib::trace::{init_sv, register_retcode_sv}; pub use self::unix::{DirTable, EpollInterestTable}; /// What needs to be done after emulating an item (a shim or an intrinsic) is done. diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 9b30d8ce78bf..d7432a7300e4 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -1,9 +1,5 @@ //! Implements calling functions from a native library. -// FIXME: disabled since it fails to build on many targets. -//#[cfg(target_os = "linux")] -//pub mod trace; - use std::ops::Deref; use libffi::high::call as ffi; @@ -13,14 +9,55 @@ use rustc_middle::mir::interpret::Pointer; use rustc_middle::ty::{self as ty, IntTy, UintTy}; use rustc_span::Symbol; -//#[cfg(target_os = "linux")] -//use self::trace::Supervisor; +#[cfg_attr( + not(all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "x86", target_arch = "x86_64") + )), + path = "trace/stub.rs" +)] +pub mod trace; + use crate::*; -//#[cfg(target_os = "linux")] -//type CallResult<'tcx> = InterpResult<'tcx, (ImmTy<'tcx>, Option)>; -//#[cfg(not(target_os = "linux"))] -type CallResult<'tcx> = InterpResult<'tcx, (ImmTy<'tcx>, Option)>; +/// The final results of an FFI trace, containing every relevant event detected +/// by the tracer. +#[allow(dead_code)] +#[cfg_attr(target_os = "linux", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug)] +pub struct MemEvents { + /// An list of memory accesses that occurred, in the order they occurred in. + pub acc_events: Vec, +} + +/// A single memory access. +#[allow(dead_code)] +#[cfg_attr(target_os = "linux", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug)] +pub enum AccessEvent { + /// A read may have occurred on this memory range. + /// Some instructions *may* read memory without *always* doing that, + /// so this can be an over-approximation. + /// The range info, however, is reliable if the access did happen. + Read(AccessRange), + /// A read may have occurred on this memory range. + /// Some instructions *may* write memory without *always* doing that, + /// so this can be an over-approximation. + /// The range info, however, is reliable if the access did happen. + Write(AccessRange), +} + +/// The memory touched by a given access. +#[allow(dead_code)] +#[cfg_attr(target_os = "linux", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug)] +pub struct AccessRange { + /// The base address in memory where an access occurred. + pub addr: usize, + /// The number of bytes affected from the base. + pub size: usize, +} impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { @@ -31,18 +68,17 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { dest: &MPlaceTy<'tcx>, ptr: CodePtr, libffi_args: Vec>, - ) -> CallResult<'tcx> { + ) -> InterpResult<'tcx, (crate::ImmTy<'tcx>, Option)> { let this = self.eval_context_mut(); - //#[cfg(target_os = "linux")] - //let alloc = this.machine.allocator.as_ref().unwrap(); + #[cfg(target_os = "linux")] + let alloc = this.machine.allocator.as_ref().unwrap(); + #[cfg(not(target_os = "linux"))] + // Placeholder value. + let alloc = (); - // SAFETY: We don't touch the machine memory past this point. - //#[cfg(target_os = "linux")] - //let (guard, stack_ptr) = unsafe { Supervisor::start_ffi(alloc) }; - - // Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value - // as the specified primitive integer type - let res = 'res: { + trace::Supervisor::do_ffi(alloc, || { + // Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value + // as the specified primitive integer type let scalar = match dest.layout.ty.kind() { // ints ty::Int(IntTy::I8) => { @@ -93,7 +129,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // have the output_type `Tuple([])`. ty::Tuple(t_list) if (*t_list).deref().is_empty() => { unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) }; - break 'res interp_ok(ImmTy::uninit(dest.layout)); + return interp_ok(ImmTy::uninit(dest.layout)); } ty::RawPtr(..) => { let x = unsafe { ffi::call::<*const ()>(ptr, libffi_args.as_slice()) }; @@ -101,23 +137,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { Scalar::from_pointer(ptr, this) } _ => - break 'res Err(err_unsup_format!( + return Err(err_unsup_format!( "unsupported return type for native call: {:?}", link_name )) .into(), }; interp_ok(ImmTy::from_scalar(scalar, dest.layout)) - }; - - // SAFETY: We got the guard and stack pointer from start_ffi, and - // the allocator is the same - //#[cfg(target_os = "linux")] - //let events = unsafe { Supervisor::end_ffi(alloc, guard, stack_ptr) }; - //#[cfg(not(target_os = "linux"))] - let events = None; - - interp_ok((res?, events)) + }) } /// Get the pointer to the function of the specified name in the shared object file, @@ -214,10 +241,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if !this.machine.native_call_mem_warned.replace(true) { // Newly set, so first time we get here. this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem { - //#[cfg(target_os = "linux")] - //tracing: self::trace::Supervisor::is_enabled(), - //#[cfg(not(target_os = "linux"))] - tracing: false, + tracing: self::trace::Supervisor::is_enabled(), }); } diff --git a/src/tools/miri/src/shims/native_lib/trace/child.rs b/src/tools/miri/src/shims/native_lib/trace/child.rs index 4961e875c775..de26cb0fe557 100644 --- a/src/tools/miri/src/shims/native_lib/trace/child.rs +++ b/src/tools/miri/src/shims/native_lib/trace/child.rs @@ -4,12 +4,22 @@ use std::rc::Rc; use ipc_channel::ipc; use nix::sys::{ptrace, signal}; use nix::unistd; +use rustc_const_eval::interpret::InterpResult; use super::CALLBACK_STACK_SIZE; -use super::messages::{Confirmation, MemEvents, StartFfiInfo, TraceRequest}; +use super::messages::{Confirmation, StartFfiInfo, TraceRequest}; use super::parent::{ChildListener, sv_loop}; use crate::alloc::isolated_alloc::IsolatedAlloc; +use crate::shims::native_lib::MemEvents; +/// A handle to the single, shared supervisor process across all `MiriMachine`s. +/// Since it would be very difficult to trace multiple FFI calls in parallel, we +/// need to ensure that either (a) only one `MiriMachine` is performing an FFI call +/// at any given time, or (b) there are distinct supervisor and child processes for +/// each machine. The former was chosen here. +/// +/// This should only contain a `None` if the supervisor has not (yet) been initialised; +/// otherwise, if `init_sv` was called and did not error, this will always be nonempty. static SUPERVISOR: std::sync::Mutex> = std::sync::Mutex::new(None); /// The main means of communication between the child and parent process, @@ -34,32 +44,23 @@ impl Supervisor { SUPERVISOR.lock().unwrap().is_some() } - /// Begins preparations for doing an FFI call. This should be called at - /// the last possible moment before entering said call. `alloc` points to - /// the allocator which handed out the memory used for this machine. - /// + /// Performs an arbitrary FFI call, enabling tracing from the supervisor. /// As this locks the supervisor via a mutex, no other threads may enter FFI - /// until this one returns and its guard is dropped via `end_ffi`. The - /// pointer returned should be passed to `end_ffi` to avoid a memory leak. - /// - /// SAFETY: The resulting guard must be dropped *via `end_ffi`* immediately - /// after the desired call has concluded. - pub unsafe fn start_ffi( + /// until this function returns. + pub fn do_ffi<'tcx>( alloc: &Rc>, - ) -> (std::sync::MutexGuard<'static, Option>, Option<*mut [u8; CALLBACK_STACK_SIZE]>) - { + f: impl FnOnce() -> InterpResult<'tcx, crate::ImmTy<'tcx>>, + ) -> InterpResult<'tcx, (crate::ImmTy<'tcx>, Option)> { let mut sv_guard = SUPERVISOR.lock().unwrap(); - // If the supervisor is not initialised for whatever reason, fast-fail. - // This might be desired behaviour, as even on platforms where ptracing - // is not implemented it enables us to enforce that only one FFI call + // If the supervisor is not initialised for whatever reason, fast-return. + // As a side-effect, even on platforms where ptracing + // is not implemented, we enforce that only one FFI call // happens at a time. - let Some(sv) = sv_guard.take() else { - return (sv_guard, None); - }; + let Some(sv) = sv_guard.as_mut() else { return f().map(|v| (v, None)) }; // Get pointers to all the pages the supervisor must allow accesses in // and prepare the callback stack. - let page_ptrs = alloc.borrow().pages(); + let page_ptrs = alloc.borrow().pages().collect(); let raw_stack_ptr: *mut [u8; CALLBACK_STACK_SIZE] = Box::leak(Box::new([0u8; CALLBACK_STACK_SIZE])).as_mut_ptr().cast(); let stack_ptr = raw_stack_ptr.expose_provenance(); @@ -68,9 +69,9 @@ impl Supervisor { // SAFETY: We do not access machine memory past this point until the // supervisor is ready to allow it. unsafe { - if alloc.borrow_mut().prepare_ffi().is_err() { + if alloc.borrow_mut().start_ffi().is_err() { // Don't mess up unwinding by maybe leaving the memory partly protected - alloc.borrow_mut().unprep_ffi(); + alloc.borrow_mut().end_ffi(); panic!("Cannot protect memory for FFI call!"); } } @@ -82,27 +83,13 @@ impl Supervisor { // enforce an ordering for these events. sv.message_tx.send(TraceRequest::StartFfi(start_info)).unwrap(); sv.confirm_rx.recv().unwrap(); - *sv_guard = Some(sv); // We need to be stopped for the supervisor to be able to make certain // modifications to our memory - simply waiting on the recv() doesn't // count. signal::raise(signal::SIGSTOP).unwrap(); - (sv_guard, Some(raw_stack_ptr)) - } - /// Undoes FFI-related preparations, allowing Miri to continue as normal, then - /// gets the memory accesses and changes performed during the FFI call. Note - /// that this may include some spurious accesses done by `libffi` itself in - /// the process of executing the function call. - /// - /// SAFETY: The `sv_guard` and `raw_stack_ptr` passed must be the same ones - /// received by a prior call to `start_ffi`, and the allocator must be the - /// one passed to it also. - pub unsafe fn end_ffi( - alloc: &Rc>, - mut sv_guard: std::sync::MutexGuard<'static, Option>, - raw_stack_ptr: Option<*mut [u8; CALLBACK_STACK_SIZE]>, - ) -> Option { + let res = f(); + // We can't use IPC channels here to signal that FFI mode has ended, // since they might allocate memory which could get us stuck in a SIGTRAP // with no easy way out! While this could be worked around, it is much @@ -113,42 +100,40 @@ impl Supervisor { signal::raise(signal::SIGUSR1).unwrap(); // This is safe! It just sets memory to normal expected permissions. - alloc.borrow_mut().unprep_ffi(); + alloc.borrow_mut().end_ffi(); - // If this is `None`, then `raw_stack_ptr` is None and does not need to - // be deallocated (and there's no need to worry about the guard, since - // it contains nothing). - let sv = sv_guard.take()?; // SAFETY: Caller upholds that this pointer was allocated as a box with // this type. unsafe { - drop(Box::from_raw(raw_stack_ptr.unwrap())); + drop(Box::from_raw(raw_stack_ptr)); } // On the off-chance something really weird happens, don't block forever. - let ret = sv + let events = sv .event_rx .try_recv_timeout(std::time::Duration::from_secs(5)) .map_err(|e| { match e { ipc::TryRecvError::IpcError(_) => (), ipc::TryRecvError::Empty => - eprintln!("Waiting for accesses from supervisor timed out!"), + panic!("Waiting for accesses from supervisor timed out!"), } }) .ok(); - // Do *not* leave the supervisor empty, or else we might get another fork... - *sv_guard = Some(sv); - ret + + res.map(|v| (v, events)) } } /// Initialises the supervisor process. If this function errors, then the /// supervisor process could not be created successfully; else, the caller -/// is now the child process and can communicate via `start_ffi`/`end_ffi`, -/// receiving back events through `get_events`. +/// is now the child process and can communicate via `do_ffi`, receiving back +/// events at the end. /// /// # Safety -/// The invariants for `fork()` must be upheld by the caller. +/// The invariants for `fork()` must be upheld by the caller, namely either: +/// - Other threads do not exist, or; +/// - If they do exist, either those threads or the resulting child process +/// only ever act in [async-signal-safe](https://www.man7.org/linux/man-pages/man7/signal-safety.7.html) ways. pub unsafe fn init_sv() -> Result<(), SvInitError> { // FIXME: Much of this could be reimplemented via the mitosis crate if we upstream the // relevant missing bits. @@ -191,8 +176,7 @@ pub unsafe fn init_sv() -> Result<(), SvInitError> { // The child process is free to unwind, so we won't to avoid doubly freeing // system resources. let init = std::panic::catch_unwind(|| { - let listener = - ChildListener { message_rx, attached: false, override_retcode: None }; + let listener = ChildListener::new(message_rx, confirm_tx.clone()); // Trace as many things as possible, to be able to handle them as needed. let options = ptrace::Options::PTRACE_O_TRACESYSGOOD | ptrace::Options::PTRACE_O_TRACECLONE @@ -218,7 +202,9 @@ pub unsafe fn init_sv() -> Result<(), SvInitError> { // The "Ok" case means that we couldn't ptrace. Ok(e) => return Err(e), Err(p) => { - eprintln!("Supervisor process panicked!\n{p:?}"); + eprintln!( + "Supervisor process panicked!\n{p:?}\n\nTry running again without using the native-lib tracer." + ); std::process::exit(1); } } @@ -239,13 +225,11 @@ pub unsafe fn init_sv() -> Result<(), SvInitError> { } /// Instruct the supervisor process to return a particular code. Useful if for -/// whatever reason this code fails to be intercepted normally. In the case of -/// `abort_if_errors()` used in `bin/miri.rs`, the return code is erroneously -/// given as a 0 if this is not used. +/// whatever reason this code fails to be intercepted normally. pub fn register_retcode_sv(code: i32) { let mut sv_guard = SUPERVISOR.lock().unwrap(); - if let Some(sv) = sv_guard.take() { + if let Some(sv) = sv_guard.as_mut() { sv.message_tx.send(TraceRequest::OverrideRetcode(code)).unwrap(); - *sv_guard = Some(sv); + sv.confirm_rx.recv().unwrap(); } } diff --git a/src/tools/miri/src/shims/native_lib/trace/messages.rs b/src/tools/miri/src/shims/native_lib/trace/messages.rs index 8a83dab5c09d..1f9df556b577 100644 --- a/src/tools/miri/src/shims/native_lib/trace/messages.rs +++ b/src/tools/miri/src/shims/native_lib/trace/messages.rs @@ -1,25 +1,28 @@ //! Houses the types that are directly sent across the IPC channels. //! -//! The overall structure of a traced FFI call, from the child process's POV, is -//! as follows: +//! When forking to initialise the supervisor during `init_sv`, the child raises +//! a `SIGSTOP`; if the parent successfully ptraces the child, it will allow it +//! to resume. Else, the child will be killed by the parent. +//! +//! After initialisation is done, the overall structure of a traced FFI call from +//! the child process's POV is as follows: //! ``` //! message_tx.send(TraceRequest::StartFfi); -//! confirm_rx.recv(); +//! confirm_rx.recv(); // receives a `Confirmation` //! raise(SIGSTOP); //! /* do ffi call */ //! raise(SIGUSR1); // morally equivalent to some kind of "TraceRequest::EndFfi" -//! let events = event_rx.recv(); +//! let events = event_rx.recv(); // receives a `MemEvents` //! ``` //! `TraceRequest::OverrideRetcode` can be sent at any point in the above, including -//! before or after all of them. +//! before or after all of them. `confirm_rx.recv()` is to be called after, to ensure +//! that the child does not exit before the supervisor has registered the return code. //! //! NB: sending these events out of order, skipping steps, etc. will result in //! unspecified behaviour from the supervisor process, so use the abstractions -//! in `super::child` (namely `start_ffi()` and `end_ffi()`) to handle this. It is +//! in `super::child` (namely `do_ffi()`) to handle this. It is //! trivially easy to cause a deadlock or crash by messing this up! -use std::ops::Range; - /// An IPC request sent by the child process to the parent. /// /// The sender for this channel should live on the child process. @@ -34,6 +37,8 @@ pub enum TraceRequest { StartFfi(StartFfiInfo), /// Manually overrides the code that the supervisor will return upon exiting. /// Once set, it is permanent. This can be called again to change the value. + /// + /// After sending this, the child must wait to receive a `Confirmation`. OverrideRetcode(i32), } @@ -41,7 +46,7 @@ pub enum TraceRequest { #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct StartFfiInfo { /// A vector of page addresses. These should have been automatically obtained - /// with `IsolatedAlloc::pages` and prepared with `IsolatedAlloc::prepare_ffi`. + /// with `IsolatedAlloc::pages` and prepared with `IsolatedAlloc::start_ffi`. pub page_ptrs: Vec, /// The address of an allocation that can serve as a temporary stack. /// This should be a leaked `Box<[u8; CALLBACK_STACK_SIZE]>` cast to an int. @@ -54,27 +59,3 @@ pub struct StartFfiInfo { /// The sender for this channel should live on the parent process. #[derive(serde::Serialize, serde::Deserialize, Debug)] pub struct Confirmation; - -/// The final results of an FFI trace, containing every relevant event detected -/// by the tracer. Sent by the supervisor after receiving a `SIGUSR1` signal. -/// -/// The sender for this channel should live on the parent process. -#[derive(serde::Serialize, serde::Deserialize, Debug)] -pub struct MemEvents { - /// An ordered list of memory accesses that occurred. These should be assumed - /// to be overcautious; that is, if the size of an access is uncertain it is - /// pessimistically rounded up, and if the type (read/write/both) is uncertain - /// it is reported as whatever would be safest to assume; i.e. a read + maybe-write - /// becomes a read + write, etc. - pub acc_events: Vec, -} - -/// A single memory access, conservatively overestimated -/// in case of ambiguity. -#[derive(serde::Serialize, serde::Deserialize, Debug)] -pub enum AccessEvent { - /// A read may have occurred on no more than the specified address range. - Read(Range), - /// A write may have occurred on no more than the specified address range. - Write(Range), -} diff --git a/src/tools/miri/src/shims/native_lib/trace/mod.rs b/src/tools/miri/src/shims/native_lib/trace/mod.rs index 174b06b3ac56..c8abacfb5e22 100644 --- a/src/tools/miri/src/shims/native_lib/trace/mod.rs +++ b/src/tools/miri/src/shims/native_lib/trace/mod.rs @@ -5,4 +5,6 @@ mod parent; pub use self::child::{Supervisor, init_sv, register_retcode_sv}; /// The size of the temporary stack we use for callbacks that the server executes in the client. +/// This should be big enough that `mempr_on` and `mempr_off` can safely be jumped into with the +/// stack pointer pointing to a "stack" of this size without overflowing it. const CALLBACK_STACK_SIZE: usize = 1024; diff --git a/src/tools/miri/src/shims/native_lib/trace/parent.rs b/src/tools/miri/src/shims/native_lib/trace/parent.rs index dfb0b35da699..fc4047eec51d 100644 --- a/src/tools/miri/src/shims/native_lib/trace/parent.rs +++ b/src/tools/miri/src/shims/native_lib/trace/parent.rs @@ -5,26 +5,17 @@ use nix::sys::{ptrace, signal, wait}; use nix::unistd; use super::CALLBACK_STACK_SIZE; -use super::messages::{AccessEvent, Confirmation, MemEvents, StartFfiInfo, TraceRequest}; +use super::messages::{Confirmation, StartFfiInfo, TraceRequest}; +use crate::shims::native_lib::{AccessEvent, AccessRange, MemEvents}; /// The flags to use when calling `waitid()`. -/// Since bitwise or on the nix version of these flags is implemented as a trait, -/// this cannot be const directly so we do it this way. const WAIT_FLAGS: wait::WaitPidFlag = - wait::WaitPidFlag::from_bits_truncate(libc::WUNTRACED | libc::WEXITED); - -/// Arch-specific maximum size a single access might perform. x86 value is set -/// assuming nothing bigger than AVX-512 is available. -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -const ARCH_MAX_ACCESS_SIZE: usize = 64; -/// The largest arm64 simd instruction operates on 16 bytes. -#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] -const ARCH_MAX_ACCESS_SIZE: usize = 16; + wait::WaitPidFlag::WUNTRACED.union(wait::WaitPidFlag::WEXITED); /// The default word size on a given platform, in bytes. -#[cfg(any(target_arch = "x86", target_arch = "arm"))] +#[cfg(target_arch = "x86")] const ARCH_WORD_SIZE: usize = 4; -#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] +#[cfg(target_arch = "x86_64")] const ARCH_WORD_SIZE: usize = 8; /// The address of the page set to be edited, initialised to a sentinel null @@ -53,39 +44,25 @@ trait ArchIndependentRegs { // It's fine / desirable behaviour for values to wrap here, we care about just // preserving the bit pattern. #[cfg(target_arch = "x86_64")] -#[expect(clippy::as_conversions)] #[rustfmt::skip] impl ArchIndependentRegs for libc::user_regs_struct { #[inline] - fn ip(&self) -> usize { self.rip as _ } + fn ip(&self) -> usize { self.rip.try_into().unwrap() } #[inline] - fn set_ip(&mut self, ip: usize) { self.rip = ip as _ } + fn set_ip(&mut self, ip: usize) { self.rip = ip.try_into().unwrap() } #[inline] - fn set_sp(&mut self, sp: usize) { self.rsp = sp as _ } + fn set_sp(&mut self, sp: usize) { self.rsp = sp.try_into().unwrap() } } #[cfg(target_arch = "x86")] -#[expect(clippy::as_conversions)] #[rustfmt::skip] impl ArchIndependentRegs for libc::user_regs_struct { #[inline] - fn ip(&self) -> usize { self.eip as _ } + fn ip(&self) -> usize { self.eip.try_into().unwrap() } #[inline] - fn set_ip(&mut self, ip: usize) { self.eip = ip as _ } + fn set_ip(&mut self, ip: usize) { self.eip = ip.try_into().unwrap() } #[inline] - fn set_sp(&mut self, sp: usize) { self.esp = sp as _ } -} - -#[cfg(target_arch = "aarch64")] -#[expect(clippy::as_conversions)] -#[rustfmt::skip] -impl ArchIndependentRegs for libc::user_regs_struct { - #[inline] - fn ip(&self) -> usize { self.pc as _ } - #[inline] - fn set_ip(&mut self, ip: usize) { self.pc = ip as _ } - #[inline] - fn set_sp(&mut self, sp: usize) { self.sp = sp as _ } + fn set_sp(&mut self, sp: usize) { self.esp = sp.try_into().unwrap() } } /// A unified event representing something happening on the child process. Wraps @@ -109,11 +86,24 @@ pub enum ExecEvent { /// A listener for the FFI start info channel along with relevant state. pub struct ChildListener { /// The matching channel for the child's `Supervisor` struct. - pub message_rx: ipc::IpcReceiver, + message_rx: ipc::IpcReceiver, + /// ... + confirm_tx: ipc::IpcSender, /// Whether an FFI call is currently ongoing. - pub attached: bool, + attached: bool, /// If `Some`, overrides the return code with the given value. - pub override_retcode: Option, + override_retcode: Option, + /// Last code obtained from a child exiting. + last_code: Option, +} + +impl ChildListener { + pub fn new( + message_rx: ipc::IpcReceiver, + confirm_tx: ipc::IpcSender, + ) -> Self { + Self { message_rx, confirm_tx, attached: false, override_retcode: None, last_code: None } + } } impl Iterator for ChildListener { @@ -133,16 +123,10 @@ impl Iterator for ChildListener { Ok(stat) => match stat { // Child exited normally with a specific code set. - wait::WaitStatus::Exited(_, code) => { - let code = self.override_retcode.unwrap_or(code); - return Some(ExecEvent::Died(Some(code))); - } + wait::WaitStatus::Exited(_, code) => self.last_code = Some(code), // Child was killed by a signal, without giving a code. - wait::WaitStatus::Signaled(_, _, _) => - return Some(ExecEvent::Died(self.override_retcode)), - // Child entered a syscall. Since we're always technically - // tracing, only pass this along if we're actively - // monitoring the child. + wait::WaitStatus::Signaled(_, _, _) => self.last_code = None, + // Child entered or exited a syscall. wait::WaitStatus::PtraceSyscall(pid) => if self.attached { return Some(ExecEvent::Syscall(pid)); @@ -179,10 +163,8 @@ impl Iterator for ChildListener { }, _ => (), }, - // This case should only trigger if all children died and we - // somehow missed that, but it's best we not allow any room - // for deadlocks. - Err(_) => return Some(ExecEvent::Died(None)), + // This case should only trigger when all children died. + Err(_) => return Some(ExecEvent::Died(self.override_retcode.or(self.last_code))), } // Similarly, do a non-blocking poll of the IPC channel. @@ -196,7 +178,10 @@ impl Iterator for ChildListener { self.attached = true; return Some(ExecEvent::Start(info)); }, - TraceRequest::OverrideRetcode(code) => self.override_retcode = Some(code), + TraceRequest::OverrideRetcode(code) => { + self.override_retcode = Some(code); + self.confirm_tx.send(Confirmation).unwrap(); + } } } @@ -211,6 +196,12 @@ impl Iterator for ChildListener { #[derive(Debug)] pub struct ExecEnd(pub Option); +/// Whether to call `ptrace::cont()` immediately. Used exclusively by `wait_for_signal`. +enum InitialCont { + Yes, + No, +} + /// This is the main loop of the supervisor process. It runs in a separate /// process from the rest of Miri (but because we fork, addresses for anything /// created before the fork - like statics - are the same). @@ -239,12 +230,12 @@ pub fn sv_loop( let mut curr_pid = init_pid; // There's an initial sigstop we need to deal with. - wait_for_signal(Some(curr_pid), signal::SIGSTOP, false)?; + wait_for_signal(Some(curr_pid), signal::SIGSTOP, InitialCont::No)?; ptrace::cont(curr_pid, None).unwrap(); for evt in listener { match evt { - // start_ffi was called by the child, so prep memory. + // Child started ffi, so prep memory. ExecEvent::Start(ch_info) => { // All the pages that the child process is "allowed to" access. ch_pages = ch_info.page_ptrs; @@ -252,17 +243,17 @@ pub fn sv_loop( ch_stack = Some(ch_info.stack_ptr); // We received the signal and are no longer in the main listener loop, - // so we can let the child move on to the end of start_ffi where it will + // so we can let the child move on to the end of the ffi prep where it will // raise a SIGSTOP. We need it to be signal-stopped *and waited for* in // order to do most ptrace operations! confirm_tx.send(Confirmation).unwrap(); // We can't trust simply calling `Pid::this()` in the child process to give the right // PID for us, so we get it this way. - curr_pid = wait_for_signal(None, signal::SIGSTOP, false).unwrap(); + curr_pid = wait_for_signal(None, signal::SIGSTOP, InitialCont::No).unwrap(); ptrace::syscall(curr_pid, None).unwrap(); } - // end_ffi was called by the child. + // Child wants to end tracing. ExecEvent::End => { // Hand over the access info we traced. event_tx.send(MemEvents { acc_events }).unwrap(); @@ -322,10 +313,6 @@ fn get_disasm() -> capstone::Capstone { {cs_pre.x86().mode(arch::x86::ArchMode::Mode64)} #[cfg(target_arch = "x86")] {cs_pre.x86().mode(arch::x86::ArchMode::Mode32)} - #[cfg(target_arch = "aarch64")] - {cs_pre.arm64().mode(arch::arm64::ArchMode::Arm)} - #[cfg(target_arch = "arm")] - {cs_pre.arm().mode(arch::arm::ArchMode::Arm)} } .detail(true) .build() @@ -339,9 +326,9 @@ fn get_disasm() -> capstone::Capstone { fn wait_for_signal( pid: Option, wait_signal: signal::Signal, - init_cont: bool, + init_cont: InitialCont, ) -> Result { - if init_cont { + if matches!(init_cont, InitialCont::Yes) { ptrace::cont(pid.unwrap(), None).unwrap(); } // Repeatedly call `waitid` until we get the signal we want, or the process dies. @@ -374,6 +361,74 @@ fn wait_for_signal( } } +/// Add the memory events from `op` being executed while there is a memory access at `addr` to +/// `acc_events`. Return whether this was a memory operand. +fn capstone_find_events( + addr: usize, + op: &capstone::arch::ArchOperand, + acc_events: &mut Vec, +) -> bool { + use capstone::prelude::*; + match op { + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + arch::ArchOperand::X86Operand(x86_operand) => { + match x86_operand.op_type { + // We only care about memory accesses + arch::x86::X86OperandType::Mem(_) => { + let push = AccessRange { addr, size: x86_operand.size.into() }; + // It's called a "RegAccessType" but it also applies to memory + let acc_ty = x86_operand.access.unwrap(); + // The same instruction might do both reads and writes, so potentially add both. + // We do not know the order in which they happened, but writing and then reading + // makes little sense so we put the read first. That is also the more + // conservative choice. + if acc_ty.is_readable() { + acc_events.push(AccessEvent::Read(push.clone())); + } + if acc_ty.is_writable() { + acc_events.push(AccessEvent::Write(push)); + } + + return true; + } + _ => (), + } + } + // FIXME: arm64 + _ => unimplemented!(), + } + + false +} + +/// Extract the events from the given instruction. +fn capstone_disassemble( + instr: &[u8], + addr: usize, + cs: &capstone::Capstone, + acc_events: &mut Vec, +) -> capstone::CsResult<()> { + // The arch_detail is what we care about, but it relies on these temporaries + // that we can't drop. 0x1000 is the default base address for Captsone, and + // we're expecting 1 instruction. + let insns = cs.disasm_count(instr, 0x1000, 1)?; + let ins_detail = cs.insn_detail(&insns[0])?; + let arch_detail = ins_detail.arch_detail(); + + let mut found_mem_op = false; + + for op in arch_detail.operands() { + if capstone_find_events(addr, &op, acc_events) { + if found_mem_op { + panic!("more than one memory operand found; we don't know which one accessed what"); + } + found_mem_op = true; + } + } + + Ok(()) +} + /// Grabs the access that caused a segfault and logs it down if it's to our memory, /// or kills the child and returns the appropriate error otherwise. fn handle_segfault( @@ -384,111 +439,6 @@ fn handle_segfault( cs: &capstone::Capstone, acc_events: &mut Vec, ) -> Result<(), ExecEnd> { - /// This is just here to not pollute the main namespace with `capstone::prelude::*`. - #[inline] - fn capstone_disassemble( - instr: &[u8], - addr: usize, - cs: &capstone::Capstone, - acc_events: &mut Vec, - ) -> capstone::CsResult<()> { - use capstone::prelude::*; - - // The arch_detail is what we care about, but it relies on these temporaries - // that we can't drop. 0x1000 is the default base address for Captsone, and - // we're expecting 1 instruction. - let insns = cs.disasm_count(instr, 0x1000, 1)?; - let ins_detail = cs.insn_detail(&insns[0])?; - let arch_detail = ins_detail.arch_detail(); - - for op in arch_detail.operands() { - match op { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - arch::ArchOperand::X86Operand(x86_operand) => { - match x86_operand.op_type { - // We only care about memory accesses - arch::x86::X86OperandType::Mem(_) => { - let push = addr..addr.strict_add(usize::from(x86_operand.size)); - // It's called a "RegAccessType" but it also applies to memory - let acc_ty = x86_operand.access.unwrap(); - if acc_ty.is_readable() { - acc_events.push(AccessEvent::Read(push.clone())); - } - if acc_ty.is_writable() { - acc_events.push(AccessEvent::Write(push)); - } - } - _ => (), - } - } - #[cfg(target_arch = "aarch64")] - arch::ArchOperand::Arm64Operand(arm64_operand) => { - // Annoyingly, we don't always get the size here, so just be pessimistic for now. - match arm64_operand.op_type { - arch::arm64::Arm64OperandType::Mem(_) => { - // B = 1 byte, H = 2 bytes, S = 4 bytes, D = 8 bytes, Q = 16 bytes. - let size = match arm64_operand.vas { - // Not an fp/simd instruction. - arch::arm64::Arm64Vas::ARM64_VAS_INVALID => ARCH_WORD_SIZE, - // 1 byte. - arch::arm64::Arm64Vas::ARM64_VAS_1B => 1, - // 2 bytes. - arch::arm64::Arm64Vas::ARM64_VAS_1H => 2, - // 4 bytes. - arch::arm64::Arm64Vas::ARM64_VAS_4B - | arch::arm64::Arm64Vas::ARM64_VAS_2H - | arch::arm64::Arm64Vas::ARM64_VAS_1S => 4, - // 8 bytes. - arch::arm64::Arm64Vas::ARM64_VAS_8B - | arch::arm64::Arm64Vas::ARM64_VAS_4H - | arch::arm64::Arm64Vas::ARM64_VAS_2S - | arch::arm64::Arm64Vas::ARM64_VAS_1D => 8, - // 16 bytes. - arch::arm64::Arm64Vas::ARM64_VAS_16B - | arch::arm64::Arm64Vas::ARM64_VAS_8H - | arch::arm64::Arm64Vas::ARM64_VAS_4S - | arch::arm64::Arm64Vas::ARM64_VAS_2D - | arch::arm64::Arm64Vas::ARM64_VAS_1Q => 16, - }; - let push = addr..addr.strict_add(size); - // FIXME: This now has access type info in the latest - // git version of capstone because this pissed me off - // and I added it. Change this when it updates. - acc_events.push(AccessEvent::Read(push.clone())); - acc_events.push(AccessEvent::Write(push)); - } - _ => (), - } - } - #[cfg(target_arch = "arm")] - arch::ArchOperand::ArmOperand(arm_operand) => - match arm_operand.op_type { - arch::arm::ArmOperandType::Mem(_) => { - // We don't get info on the size of the access, but - // we're at least told if it's a vector instruction. - let size = if arm_operand.vector_index.is_some() { - ARCH_MAX_ACCESS_SIZE - } else { - ARCH_WORD_SIZE - }; - let push = addr..addr.strict_add(size); - let acc_ty = arm_operand.access.unwrap(); - if acc_ty.is_readable() { - acc_events.push(AccessEvent::Read(push.clone())); - } - if acc_ty.is_writable() { - acc_events.push(AccessEvent::Write(push)); - } - } - _ => (), - }, - _ => unimplemented!(), - } - } - - Ok(()) - } - // Get information on what caused the segfault. This contains the address // that triggered it. let siginfo = ptrace::getsiginfo(pid).unwrap(); @@ -515,7 +465,7 @@ fn handle_segfault( // global atomic variables. This is what we use the temporary callback stack for. // - Step 1 instruction // - Parse executed code to estimate size & type of access - // - Reprotect the memory by executing `mempr_on` in the child. + // - Reprotect the memory by executing `mempr_on` in the child, using the callback stack again. // - Continue // Ensure the stack is properly zeroed out! @@ -552,7 +502,7 @@ fn handle_segfault( ptrace::setregs(pid, new_regs).unwrap(); // Our mempr_* functions end with a raise(SIGSTOP). - wait_for_signal(Some(pid), signal::SIGSTOP, true)?; + wait_for_signal(Some(pid), signal::SIGSTOP, InitialCont::Yes)?; // Step 1 instruction. ptrace::setregs(pid, regs_bak).unwrap(); @@ -573,6 +523,12 @@ fn handle_segfault( let regs_bak = ptrace::getregs(pid).unwrap(); new_regs = regs_bak; let ip_poststep = regs_bak.ip(); + + // Ensure that we've actually gone forwards. + assert!(ip_poststep > ip_prestep); + // But not by too much. 64 bytes should be "big enough" on ~any architecture. + assert!(ip_prestep.strict_add(64) > ip_poststep); + // We need to do reads/writes in word-sized chunks. let diff = (ip_poststep.strict_sub(ip_prestep)).div_ceil(ARCH_WORD_SIZE); let instr = (ip_prestep..ip_prestep.strict_add(diff)).fold(vec![], |mut ret, ip| { @@ -587,20 +543,14 @@ fn handle_segfault( }); // Now figure out the size + type of access and log it down. - // This will mark down e.g. the same area being read multiple times, - // since it's more efficient to compress the accesses at the end. - if capstone_disassemble(&instr, addr, cs, acc_events).is_err() { - // Read goes first because we need to be pessimistic. - acc_events.push(AccessEvent::Read(addr..addr.strict_add(ARCH_MAX_ACCESS_SIZE))); - acc_events.push(AccessEvent::Write(addr..addr.strict_add(ARCH_MAX_ACCESS_SIZE))); - } + capstone_disassemble(&instr, addr, cs, acc_events).expect("Failed to disassemble instruction"); // Reprotect everything and continue. #[expect(clippy::as_conversions)] new_regs.set_ip(mempr_on as usize); new_regs.set_sp(stack_ptr); ptrace::setregs(pid, new_regs).unwrap(); - wait_for_signal(Some(pid), signal::SIGSTOP, true)?; + wait_for_signal(Some(pid), signal::SIGSTOP, InitialCont::Yes)?; ptrace::setregs(pid, regs_bak).unwrap(); ptrace::syscall(pid, None).unwrap(); diff --git a/src/tools/miri/src/shims/native_lib/trace/stub.rs b/src/tools/miri/src/shims/native_lib/trace/stub.rs new file mode 100644 index 000000000000..22787a6f6fa7 --- /dev/null +++ b/src/tools/miri/src/shims/native_lib/trace/stub.rs @@ -0,0 +1,34 @@ +use rustc_const_eval::interpret::InterpResult; + +static SUPERVISOR: std::sync::Mutex<()> = std::sync::Mutex::new(()); + +pub struct Supervisor; + +#[derive(Debug)] +pub struct SvInitError; + +impl Supervisor { + #[inline(always)] + pub fn is_enabled() -> bool { + false + } + + pub fn do_ffi<'tcx, T>( + _: T, + f: impl FnOnce() -> InterpResult<'tcx, crate::ImmTy<'tcx>>, + ) -> InterpResult<'tcx, (crate::ImmTy<'tcx>, Option)> { + // We acquire the lock to ensure that no two FFI calls run concurrently. + let _g = SUPERVISOR.lock().unwrap(); + f().map(|v| (v, None)) + } +} + +#[inline(always)] +#[allow(dead_code, clippy::missing_safety_doc)] +pub unsafe fn init_sv() -> Result { + Err(SvInitError) +} + +#[inline(always)] +#[allow(dead_code)] +pub fn register_retcode_sv(_: T) {} From 86c6197b1acad00f68b7a135d297c4d2f208cc73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 18 Jun 2025 16:46:57 +0200 Subject: [PATCH 076/363] Rename `compiler` to `build_compiler` --- src/bootstrap/src/core/build_steps/tool.rs | 61 +++++++++++----------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 5de1b472d794..beb7e3810c09 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -41,7 +41,8 @@ pub enum ToolArtifactKind { #[derive(Debug, Clone, Hash, PartialEq, Eq)] struct ToolBuild { - compiler: Compiler, + /// Compiler that will build this tool. + build_compiler: Compiler, target: TargetSelection, tool: &'static str, path: &'static str, @@ -111,25 +112,25 @@ impl Step for ToolBuild { let mut tool = self.tool; let path = self.path; - let target_compiler = self.compiler; - self.compiler = if self.mode == Mode::ToolRustc { - get_tool_rustc_compiler(builder, self.compiler) + let target_compiler = self.build_compiler; + self.build_compiler = if self.mode == Mode::ToolRustc { + get_tool_rustc_compiler(builder, self.build_compiler) } else { - self.compiler + self.build_compiler }; match self.mode { Mode::ToolRustc => { // If compiler was forced, its artifacts should have been prepared earlier. - if !self.compiler.is_forced_compiler() { - builder.std(self.compiler, self.compiler.host); - builder.ensure(compile::Rustc::new(self.compiler, target)); + if !self.build_compiler.is_forced_compiler() { + builder.std(self.build_compiler, self.build_compiler.host); + builder.ensure(compile::Rustc::new(self.build_compiler, target)); } } Mode::ToolStd => { // If compiler was forced, its artifacts should have been prepared earlier. - if !self.compiler.is_forced_compiler() { - builder.std(self.compiler, target) + if !self.build_compiler.is_forced_compiler() { + builder.std(self.build_compiler, target); } } Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs @@ -151,7 +152,7 @@ impl Step for ToolBuild { let mut cargo = prepare_tool_cargo( builder, - self.compiler, + self.build_compiler, self.mode, target, Kind::Build, @@ -173,7 +174,7 @@ impl Step for ToolBuild { // Rustc tools (miri, clippy, cargo, rustfmt, rust-analyzer) // could use the additional optimizations. - if self.mode == Mode::ToolRustc && is_lto_stage(&self.compiler) { + if self.mode == Mode::ToolRustc && is_lto_stage(&self.build_compiler) { let lto = match builder.config.rust_lto { RustcLto::Off => Some("off"), RustcLto::Thin => Some("thin"), @@ -195,8 +196,8 @@ impl Step for ToolBuild { Kind::Build, self.mode, self.tool, - self.compiler.stage, - &self.compiler.host, + self.build_compiler.stage, + &self.build_compiler.host, &self.target, ); @@ -219,14 +220,14 @@ impl Step for ToolBuild { } let tool_path = match self.artifact_kind { ToolArtifactKind::Binary => { - copy_link_tool_bin(builder, self.compiler, self.target, self.mode, tool) + copy_link_tool_bin(builder, self.build_compiler, self.target, self.mode, tool) } ToolArtifactKind::Library => builder - .cargo_out(self.compiler, self.mode, self.target) + .cargo_out(self.build_compiler, self.mode, self.target) .join(format!("lib{tool}.rlib")), }; - ToolBuildResult { tool_path, build_compiler: self.compiler, target_compiler } + ToolBuildResult { tool_path, build_compiler: self.build_compiler, target_compiler } } } } @@ -450,7 +451,7 @@ macro_rules! bootstrap_tool { let compiletest_wants_stage0 = $tool_name == "compiletest" && builder.config.compiletest_use_stage0_libtest; builder.ensure(ToolBuild { - compiler: self.compiler, + build_compiler: self.compiler, target: self.target, tool: $tool_name, mode: if is_unstable && !compiletest_wants_stage0 { @@ -560,7 +561,7 @@ impl Step for RustcPerf { builder.require_submodule("src/tools/rustc-perf", None); let tool = ToolBuild { - compiler: self.compiler, + build_compiler: self.compiler, target: self.target, tool: "collector", mode: Mode::ToolBootstrap, @@ -576,7 +577,7 @@ impl Step for RustcPerf { let res = builder.ensure(tool.clone()); // We also need to symlink the `rustc-fake` binary to the corresponding directory, // because `collector` expects it in the same directory. - copy_link_tool_bin(builder, tool.compiler, tool.target, tool.mode, "rustc-fake"); + copy_link_tool_bin(builder, tool.build_compiler, tool.target, tool.mode, "rustc-fake"); res } @@ -620,7 +621,7 @@ impl Step for ErrorIndex { fn run(self, builder: &Builder<'_>) -> ToolBuildResult { builder.ensure(ToolBuild { - compiler: self.compiler, + build_compiler: self.compiler, target: self.compiler.host, tool: "error_index_generator", mode: Mode::ToolRustc, @@ -656,7 +657,7 @@ impl Step for RemoteTestServer { fn run(self, builder: &Builder<'_>) -> ToolBuildResult { builder.ensure(ToolBuild { - compiler: self.compiler, + build_compiler: self.compiler, target: self.target, tool: "remote-test-server", mode: Mode::ToolStd, @@ -757,7 +758,7 @@ impl Step for Rustdoc { let ToolBuildResult { tool_path, build_compiler, target_compiler } = builder.ensure(ToolBuild { - compiler: target_compiler, + build_compiler: target_compiler, target, // Cargo adds a number of paths to the dylib search path on windows, which results in // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" @@ -825,7 +826,7 @@ impl Step for Cargo { builder.build.require_submodule("src/tools/cargo", None); builder.ensure(ToolBuild { - compiler: self.compiler, + build_compiler: self.compiler, target: self.target, tool: "cargo", mode: Mode::ToolRustc, @@ -873,7 +874,7 @@ impl Step for LldWrapper { let target = self.target_compiler.host; let tool_result = builder.ensure(ToolBuild { - compiler: self.build_compiler, + build_compiler: self.build_compiler, target, tool: "lld-wrapper", mode: Mode::ToolStd, @@ -948,7 +949,7 @@ impl Step for RustAnalyzer { fn run(self, builder: &Builder<'_>) -> ToolBuildResult { builder.ensure(ToolBuild { - compiler: self.compiler, + build_compiler: self.compiler, target: self.target, tool: "rust-analyzer", mode: Mode::ToolRustc, @@ -993,7 +994,7 @@ impl Step for RustAnalyzerProcMacroSrv { fn run(self, builder: &Builder<'_>) -> Option { let tool_result = builder.ensure(ToolBuild { - compiler: self.compiler, + build_compiler: self.compiler, target: self.target, tool: "rust-analyzer-proc-macro-srv", mode: Mode::ToolRustc, @@ -1051,7 +1052,7 @@ impl Step for LlvmBitcodeLinker { )] fn run(self, builder: &Builder<'_>) -> ToolBuildResult { builder.ensure(ToolBuild { - compiler: self.build_compiler, + build_compiler: self.build_compiler, target: self.target, tool: "llvm-bitcode-linker", mode: Mode::ToolRustc, @@ -1235,7 +1236,7 @@ fn run_tool_build_step( let ToolBuildResult { tool_path, build_compiler, target_compiler } = builder.ensure(ToolBuild { - compiler, + build_compiler: compiler, target, tool: tool_name, mode: Mode::ToolRustc, @@ -1332,7 +1333,7 @@ impl Step for TestFloatParse { let compiler = builder.compiler(builder.top_stage, bootstrap_host); builder.ensure(ToolBuild { - compiler, + build_compiler: compiler, target: bootstrap_host, tool: "test-float-parse", mode: Mode::ToolStd, From 2fbc6427d3adbc883b2fce153586af76569c099b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 8 Jul 2025 16:57:38 +0200 Subject: [PATCH 077/363] Add `Mode::ToolTarget` --- src/bootstrap/README.md | 2 +- src/bootstrap/src/core/build_steps/check.rs | 6 +- src/bootstrap/src/core/build_steps/tool.rs | 11 ++++ src/bootstrap/src/core/builder/cargo.rs | 53 ++++++++-------- src/bootstrap/src/core/builder/mod.rs | 1 + src/bootstrap/src/lib.rs | 68 +++++++++++++++++---- 6 files changed, 103 insertions(+), 38 deletions(-) diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 6ce4c6d62fa5..2965174b45bc 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -105,7 +105,7 @@ build/ debuginfo/ ... - # Bootstrap host tools (which are always compiled with the stage0 compiler) + # Host tools (which are always compiled with the stage0 compiler) # are stored here. bootstrap-tools/ diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 0497bae86a1c..bdaf8917dd97 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -4,7 +4,9 @@ use crate::core::build_steps::compile::{ add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make, }; use crate::core::build_steps::tool; -use crate::core::build_steps::tool::{COMPILETEST_ALLOW_FEATURES, SourceType, prepare_tool_cargo}; +use crate::core::build_steps::tool::{ + COMPILETEST_ALLOW_FEATURES, SourceType, get_tool_target_compiler, prepare_tool_cargo, +}; use crate::core::builder::{ self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description, }; @@ -247,8 +249,10 @@ fn prepare_compiler_for_check( mode: Mode, ) -> Compiler { let host = builder.host_target; + match mode { Mode::ToolBootstrap => builder.compiler(0, host), + Mode::ToolTarget => get_tool_target_compiler(builder, target), Mode::ToolStd => { // These tools require the local standard library to be checked let build_compiler = builder.compiler(builder.top_stage, host); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index beb7e3810c09..9fac8df4ae8a 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -365,6 +365,17 @@ pub(crate) fn get_tool_rustc_compiler( builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.host_target) } +/// Returns a compiler that is able to compile a `ToolTarget` tool for the given `target`. +pub(crate) fn get_tool_target_compiler(builder: &Builder<'_>, target: TargetSelection) -> Compiler { + todo!("FIX"); + if builder.host_target == target { + builder.compiler(0, builder.host_target) + } else { + // FIXME: should this be builder.top_stage to avoid rebuilds? + builder.compiler(1, target) + } +} + /// Links a built tool binary with the given `name` from the build directory to the /// tools directory. fn copy_link_tool_bin( diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 065d7e45e0f0..c6f3c876a6f8 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -537,7 +537,7 @@ impl Builder<'_> { } } - let stage = if compiler.stage == 0 && self.local_rebuild { + let build_compiler_stage = if compiler.stage == 0 && self.local_rebuild { // Assume the local-rebuild rustc already has stage1 features. 1 } else { @@ -545,15 +545,17 @@ impl Builder<'_> { }; // We synthetically interpret a stage0 compiler used to build tools as a - // "raw" compiler in that it's the exact snapshot we download. Normally - // the stage0 build means it uses libraries build by the stage0 - // compiler, but for tools we just use the precompiled libraries that - // we've downloaded - let use_snapshot = mode == Mode::ToolBootstrap; - assert!(!use_snapshot || stage == 0 || self.local_rebuild); + // "raw" compiler in that it's the exact snapshot we download. For things like + // ToolRustc, we would have to use the artificial stage0-sysroot compiler instead. + let use_snapshot = + mode == Mode::ToolBootstrap || (mode == Mode::ToolTarget && build_compiler_stage == 0); + assert!(!use_snapshot || build_compiler_stage == 0 || self.local_rebuild); - let maybe_sysroot = self.sysroot(compiler); - let sysroot = if use_snapshot { self.rustc_snapshot_sysroot() } else { &maybe_sysroot }; + let sysroot = if use_snapshot { + self.rustc_snapshot_sysroot().to_path_buf() + } else { + self.sysroot(compiler) + }; let libdir = self.rustc_libdir(compiler); let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8"); @@ -562,7 +564,7 @@ impl Builder<'_> { } let mut rustflags = Rustflags::new(target); - if stage != 0 { + if build_compiler_stage != 0 { if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") { cargo.args(s.split_whitespace()); } @@ -604,7 +606,7 @@ impl Builder<'_> { // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native // library unnecessary. This can be removed when windows-rs enables raw-dylib // unconditionally. - if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap = mode { + if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap | Mode::ToolTarget = mode { rustflags.arg("--cfg=windows_raw_dylib"); } @@ -657,7 +659,7 @@ impl Builder<'_> { // FIXME(rust-lang/cargo#5754) we shouldn't be using special command arguments // to the host invocation here, but rather Cargo should know what flags to pass rustc // itself. - if stage == 0 { + if build_compiler_stage == 0 { hostflags.arg("--cfg=bootstrap"); } @@ -666,7 +668,7 @@ impl Builder<'_> { // #71458. let mut rustdocflags = rustflags.clone(); rustdocflags.propagate_cargo_env("RUSTDOCFLAGS"); - if stage == 0 { + if build_compiler_stage == 0 { rustdocflags.env("RUSTDOCFLAGS_BOOTSTRAP"); } else { rustdocflags.env("RUSTDOCFLAGS_NOT_BOOTSTRAP"); @@ -677,7 +679,7 @@ impl Builder<'_> { } match mode { - Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {} + Mode::Std | Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTarget => {} Mode::Rustc | Mode::Codegen | Mode::ToolRustc => { // Build proc macros both for the host and the target unless proc-macros are not // supported by the target. @@ -719,7 +721,7 @@ impl Builder<'_> { // feature on the rustc side. cargo.arg("-Zbinary-dep-depinfo"); let allow_features = match mode { - Mode::ToolBootstrap | Mode::ToolStd => { + Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTarget => { // Restrict the allowed features so we don't depend on nightly // accidentally. // @@ -827,7 +829,7 @@ impl Builder<'_> { cargo .env("RUSTBUILD_NATIVE_DIR", self.native_dir(target)) .env("RUSTC_REAL", self.rustc(compiler)) - .env("RUSTC_STAGE", stage.to_string()) + .env("RUSTC_STAGE", build_compiler_stage.to_string()) .env("RUSTC_SYSROOT", sysroot) .env("RUSTC_LIBDIR", libdir) .env("RUSTDOC", self.bootstrap_out.join("rustdoc")) @@ -872,7 +874,7 @@ impl Builder<'_> { let debuginfo_level = match mode { Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc, Mode::Std => self.config.rust_debuginfo_level_std, - Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc => { + Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc | Mode::ToolTarget => { self.config.rust_debuginfo_level_tools } }; @@ -884,11 +886,10 @@ impl Builder<'_> { profile_var("DEBUG_ASSERTIONS"), match mode { Mode::Std => self.config.std_debug_assertions, - Mode::Rustc => self.config.rustc_debug_assertions, - Mode::Codegen => self.config.rustc_debug_assertions, - Mode::ToolBootstrap => self.config.tools_debug_assertions, - Mode::ToolStd => self.config.tools_debug_assertions, - Mode::ToolRustc => self.config.tools_debug_assertions, + Mode::Rustc | Mode::Codegen => self.config.rustc_debug_assertions, + Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc | Mode::ToolTarget => { + self.config.tools_debug_assertions + } } .to_string(), ); @@ -959,7 +960,11 @@ impl Builder<'_> { cargo.env("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR", map_to); } } - Mode::Std | Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd => { + Mode::Std + | Mode::ToolBootstrap + | Mode::ToolRustc + | Mode::ToolStd + | Mode::ToolTarget => { if let Some(ref map_to) = self.build.debuginfo_map_to(GitRepo::Rustc, RemapScheme::NonCompiler) { @@ -1274,7 +1279,7 @@ impl Builder<'_> { }; if let Some(limit) = limit - && (stage == 0 + && (build_compiler_stage == 0 || self.config.default_codegen_backend(target).unwrap_or_default() == "llvm") { rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}")); diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 7464327fde98..e538c12df6d9 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -959,6 +959,7 @@ impl<'a> Builder<'a> { tool::RemoteTestServer, tool::RemoteTestClient, tool::RustInstaller, + tool::FeaturesStatusDump, tool::Cargo, tool::RustAnalyzer, tool::RustAnalyzerProcMacroSrv, diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index ef5c28272b8e..4ec0b089bacf 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -253,12 +253,24 @@ pub enum Mode { /// These tools are intended to be only executed on the host system that /// invokes bootstrap, and they thus cannot be cross-compiled. /// - /// They are always built using the stage0 compiler, and typically they + /// They are always built using the stage0 compiler, and they /// can be compiled with stable Rust. /// /// These tools also essentially do not participate in staging. ToolBootstrap, + /// Build a cross-compilable helper tool. These tools do not depend on unstable features or + /// compiler internals, but they might be cross-compilable (so we cannot build them using the + /// stage0 compiler, unlike `ToolBootstrap`). + /// + /// Some of these tools are also shipped in our `dist` archives. + /// While we could compile them using the stage0 compiler when not cross-compiling, we instead + /// use the in-tree compiler (and std) to build them, so that we can ship e.g. std security + /// fixes and avoid depending fully on stage0 for the artifacts that we ship. + /// + /// This mode is used e.g. for linkers and linker tools invoked by rustc on its host target. + ToolTarget, + /// Build a tool which uses the locally built std, placing output in the /// "stageN-tools" directory. Its usage is quite rare, mainly used by /// compiletest which needs libtest. @@ -273,11 +285,21 @@ pub enum Mode { impl Mode { pub fn is_tool(&self) -> bool { - matches!(self, Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd) + match self { + Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd | Mode::ToolTarget => true, + Mode::Std | Mode::Codegen | Mode::Rustc => false, + } } pub fn must_support_dlopen(&self) -> bool { - matches!(self, Mode::Std | Mode::Codegen) + match self { + Mode::Std | Mode::Codegen => true, + Mode::ToolBootstrap + | Mode::ToolRustc + | Mode::ToolStd + | Mode::ToolTarget + | Mode::Rustc => false, + } } } @@ -804,17 +826,39 @@ impl Build { /// stage when running with a particular host compiler. /// /// The mode indicates what the root directory is for. - fn stage_out(&self, compiler: Compiler, mode: Mode) -> PathBuf { - let suffix = match mode { - Mode::Std => "-std", - Mode::Rustc => "-rustc", - Mode::Codegen => "-codegen", - Mode::ToolBootstrap => { - return self.out.join(compiler.host).join("bootstrap-tools"); + fn stage_out(&self, build_compiler: Compiler, mode: Mode) -> PathBuf { + use std::fmt::Write; + + fn bootstrap_tool() -> (Option, &'static str) { + (None, "bootstrap-tools") + } + fn staged_tool(build_compiler: Compiler) -> (Option, &'static str) { + (Some(build_compiler.stage), "tools") + } + + let (stage, suffix) = match mode { + Mode::Std => (Some(build_compiler.stage), "std"), + Mode::Rustc => (Some(build_compiler.stage), "rustc"), + Mode::Codegen => (Some(build_compiler.stage), "codegen"), + Mode::ToolBootstrap => bootstrap_tool(), + Mode::ToolStd | Mode::ToolRustc => (Some(build_compiler.stage), "tools"), + Mode::ToolTarget => { + // If we're not cross-compiling (the common case), share the target directory with + // bootstrap tools to reuse the build cache. + if build_compiler.stage == 0 { + bootstrap_tool() + } else { + staged_tool(build_compiler) + } } - Mode::ToolStd | Mode::ToolRustc => "-tools", }; - self.out.join(compiler.host).join(format!("stage{}{}", compiler.stage, suffix)) + let path = self.out.join(build_compiler.host); + let mut dir_name = String::new(); + if let Some(stage) = stage { + write!(dir_name, "stage{stage}-").unwrap(); + } + dir_name.push_str(suffix); + path.join(dir_name) } /// Returns the root output directory for all Cargo output in a given stage, From 6511ece1e37a975aa6e060ca56fdf31af8c04fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 8 Jul 2025 17:00:41 +0200 Subject: [PATCH 078/363] Port `RemoteTestServer` to `ToolTarget` --- src/bootstrap/src/core/build_steps/check.rs | 4 +-- src/bootstrap/src/core/build_steps/test.rs | 3 ++- src/bootstrap/src/core/build_steps/tool.rs | 30 ++++++++++++--------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index bdaf8917dd97..2ba4c37d9a71 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -5,7 +5,7 @@ use crate::core::build_steps::compile::{ }; use crate::core::build_steps::tool; use crate::core::build_steps::tool::{ - COMPILETEST_ALLOW_FEATURES, SourceType, get_tool_target_compiler, prepare_tool_cargo, + COMPILETEST_ALLOW_FEATURES, SourceType, get_compiler_for_target, prepare_tool_cargo, }; use crate::core::builder::{ self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description, @@ -252,7 +252,7 @@ fn prepare_compiler_for_check( match mode { Mode::ToolBootstrap => builder.compiler(0, host), - Mode::ToolTarget => get_tool_target_compiler(builder, target), + Mode::ToolTarget => get_compiler_for_target(builder, target), Mode::ToolStd => { // These tools require the local standard library to be checked let build_compiler = builder.compiler(builder.top_stage, host); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 716bef3f38c4..4acc609626e8 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2941,7 +2941,8 @@ impl Step for RemoteCopyLibs { builder.info(&format!("REMOTE copy libs to emulator ({target})")); - let remote_test_server = builder.ensure(tool::RemoteTestServer { compiler, target }); + let remote_test_server = + builder.ensure(tool::RemoteTestServer { build_compiler: compiler, target }); // Spawn the emulator and wait for it to come online let tool = builder.tool_exe(Tool::RemoteTestClient); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 9fac8df4ae8a..631d04385274 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -133,7 +133,7 @@ impl Step for ToolBuild { builder.std(self.build_compiler, target); } } - Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs + Mode::ToolBootstrap | Mode::ToolTarget => {} // uses downloaded stage0 compiler libs _ => panic!("unexpected Mode for tool build"), } @@ -196,7 +196,7 @@ impl Step for ToolBuild { Kind::Build, self.mode, self.tool, - self.build_compiler.stage, + self.build_compiler.stage + 1, &self.build_compiler.host, &self.target, ); @@ -365,15 +365,15 @@ pub(crate) fn get_tool_rustc_compiler( builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.host_target) } -/// Returns a compiler that is able to compile a `ToolTarget` tool for the given `target`. -pub(crate) fn get_tool_target_compiler(builder: &Builder<'_>, target: TargetSelection) -> Compiler { - todo!("FIX"); - if builder.host_target == target { +/// Returns the smallest stage compiler that is able to compile code for the given `target`. +pub(crate) fn get_compiler_for_target(builder: &Builder<'_>, target: TargetSelection) -> Compiler { + let compiler = if builder.host_target == target { builder.compiler(0, builder.host_target) } else { - // FIXME: should this be builder.top_stage to avoid rebuilds? - builder.compiler(1, target) - } + builder.compiler(1, builder.host_target) + }; + builder.std(compiler, target); + compiler } /// Links a built tool binary with the given `name` from the build directory to the @@ -648,7 +648,7 @@ impl Step for ErrorIndex { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RemoteTestServer { - pub compiler: Compiler, + pub build_compiler: Compiler, pub target: TargetSelection, } @@ -661,17 +661,17 @@ impl Step for RemoteTestServer { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RemoteTestServer { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), + build_compiler: get_compiler_for_target(run.builder, run.target), target: run.target, }); } fn run(self, builder: &Builder<'_>) -> ToolBuildResult { builder.ensure(ToolBuild { - build_compiler: self.compiler, + build_compiler: self.build_compiler, target: self.target, tool: "remote-test-server", - mode: Mode::ToolStd, + mode: Mode::ToolTarget, path: "src/tools/remote-test-server", source_type: SourceType::InTree, extra_features: Vec::new(), @@ -680,6 +680,10 @@ impl Step for RemoteTestServer { artifact_kind: ToolArtifactKind::Binary, }) } + + fn metadata(&self) -> Option { + Some(StepMetadata::build("remote-test-server", self.target).built_by(self.build_compiler)) + } } #[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] From 89370e0240adf25216427e787787780bcb90156e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 8 Jul 2025 17:16:14 +0200 Subject: [PATCH 079/363] Make `WasmComponentLd` a `ToolTarget` tool --- src/bootstrap/src/core/build_steps/check.rs | 5 +- src/bootstrap/src/core/build_steps/compile.rs | 14 +-- src/bootstrap/src/core/build_steps/tool.rs | 107 +++++++++++++++++- src/bootstrap/src/core/builder/mod.rs | 1 + 4 files changed, 111 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 2ba4c37d9a71..d4d3b7a7babe 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -5,7 +5,8 @@ use crate::core::build_steps::compile::{ }; use crate::core::build_steps::tool; use crate::core::build_steps::tool::{ - COMPILETEST_ALLOW_FEATURES, SourceType, get_compiler_for_target, prepare_tool_cargo, + COMPILETEST_ALLOW_FEATURES, SourceType, ToolTargetBuildMode, get_tool_target_compiler, + prepare_tool_cargo, }; use crate::core::builder::{ self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description, @@ -252,7 +253,7 @@ fn prepare_compiler_for_check( match mode { Mode::ToolBootstrap => builder.compiler(0, host), - Mode::ToolTarget => get_compiler_for_target(builder, target), + Mode::ToolTarget => get_tool_target_compiler(builder, ToolTargetBuildMode::Build(target)), Mode::ToolStd => { // These tools require the local standard library to be checked let build_compiler = builder.compiler(builder.top_stage, host); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 0587d21ecc28..60618942c820 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2286,15 +2286,13 @@ impl Step for Assemble { } // In addition to `rust-lld` also install `wasm-component-ld` when - // LLD is enabled. This is a relatively small binary that primarily - // delegates to the `rust-lld` binary for linking and then runs - // logic to create the final binary. This is used by the - // `wasm32-wasip2` target of Rust. + // is enabled. This is used by the `wasm32-wasip2` target of Rust. if builder.tool_enabled("wasm-component-ld") { - let wasm_component = builder.ensure(crate::core::build_steps::tool::WasmComponentLd { - compiler: build_compiler, - target: target_compiler.host, - }); + let wasm_component = + builder.ensure(crate::core::build_steps::tool::WasmComponentLd::for_compiler( + builder, + target_compiler, + )); builder.copy_link( &wasm_component.tool_path, &libdir_bin.join(wasm_component.tool_path.file_name().unwrap()), diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 631d04385274..2d3187274f2a 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -365,12 +365,36 @@ pub(crate) fn get_tool_rustc_compiler( builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.host_target) } -/// Returns the smallest stage compiler that is able to compile code for the given `target`. -pub(crate) fn get_compiler_for_target(builder: &Builder<'_>, target: TargetSelection) -> Compiler { +/// Determines how to build a `ToolTarget`, i.e. which compiler should be used to compile it. +/// The compiler stage is automatically auto-bumped if we need to cross-compile a stage 1 tool. +pub enum ToolTargetBuildMode { + /// Build the tool using rustc that corresponds to the selected CLI stage. + Build(TargetSelection), + /// Build the tool so that it can be attached to the sysroot of the passed compiler. + /// Since we always dist stage 2+, the compiler that builds the tool in this case has to be + /// stage 1+. + Dist(Compiler), +} + +/// Returns compiler that is able to compile a `ToolTarget` tool with the given `mode`. +pub(crate) fn get_tool_target_compiler( + builder: &Builder<'_>, + mode: ToolTargetBuildMode, +) -> Compiler { + let (target, min_build_compiler_stage) = match mode { + ToolTargetBuildMode::Build(target) => { + assert!(builder.top_stage > 0); + (target, builder.top_stage - 1) + } + ToolTargetBuildMode::Dist(target_compiler) => { + assert!(target_compiler.stage > 0); + (target_compiler.host, target_compiler.stage - 1) + } + }; let compiler = if builder.host_target == target { - builder.compiler(0, builder.host_target) + builder.compiler(min_build_compiler_stage, builder.host_target) } else { - builder.compiler(1, builder.host_target) + builder.compiler(min_build_compiler_stage.max(1), builder.host_target) }; builder.std(compiler, target); compiler @@ -533,7 +557,6 @@ bootstrap_tool!( // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features. RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES; CoverageDump, "src/tools/coverage-dump", "coverage-dump"; - WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization"; UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator"; FeaturesStatusDump, "src/tools/features-status-dump", "features-status-dump"; OptimizedDist, "src/tools/opt-dist", "opt-dist", submodules = &["src/tools/rustc-perf"]; @@ -661,7 +684,10 @@ impl Step for RemoteTestServer { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RemoteTestServer { - build_compiler: get_compiler_for_target(run.builder, run.target), + build_compiler: get_tool_target_compiler( + run.builder, + ToolTargetBuildMode::Build(run.target), + ), target: run.target, }); } @@ -935,6 +961,75 @@ impl Step for LldWrapper { } } +/// Builds the `wasm-component-ld` linker wrapper, which is shipped with rustc to be executed on the +/// host platform where rustc runs. +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct WasmComponentLd { + build_compiler: Compiler, + target: TargetSelection, +} + +impl WasmComponentLd { + /// Returns `WasmComponentLd` that should be **used** by the passed compiler. + pub fn for_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self { + Self { + build_compiler: get_tool_target_compiler( + builder, + ToolTargetBuildMode::Dist(target_compiler), + ), + target: target_compiler.host, + } + } +} + +impl Step for WasmComponentLd { + type Output = ToolBuildResult; + + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/wasm-component-ld") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(WasmComponentLd { + build_compiler: get_tool_target_compiler( + run.builder, + ToolTargetBuildMode::Build(run.target), + ), + target: run.target, + }); + } + + #[cfg_attr( + feature = "tracing", + instrument( + level = "debug", + name = "WasmComponentLd::run", + skip_all, + fields(build_compiler = ?self.build_compiler), + ), + )] + fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + builder.ensure(ToolBuild { + build_compiler: self.build_compiler, + target: self.target, + tool: "wasm-component-ld", + mode: Mode::ToolTarget, + path: "src/tools/wasm-component-ld", + source_type: SourceType::InTree, + extra_features: vec![], + allow_features: "min-specialization", + cargo_args: vec![], + artifact_kind: ToolArtifactKind::Binary, + }) + } + + fn metadata(&self) -> Option { + Some(StepMetadata::build("WasmComponentLd", self.target).built_by(self.build_compiler)) + } +} + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustAnalyzer { pub compiler: Compiler, diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index e538c12df6d9..65e9c3850e79 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -981,6 +981,7 @@ impl<'a> Builder<'a> { tool::CoverageDump, tool::LlvmBitcodeLinker, tool::RustcPerf, + tool::WasmComponentLd ), Kind::Clippy => describe!( clippy::Std, From c571b97778e554d5e01302016cb709a41362d34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 8 Jul 2025 17:19:38 +0200 Subject: [PATCH 080/363] Make `LldWrapper` a `ToolTarget` tool --- src/bootstrap/src/core/build_steps/compile.rs | 10 +- src/bootstrap/src/core/build_steps/tool.rs | 121 +++++++++++------- src/bootstrap/src/core/builder/mod.rs | 3 +- 3 files changed, 81 insertions(+), 53 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 60618942c820..9e60a04e69fb 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -19,7 +19,7 @@ use serde_derive::Deserialize; use tracing::{instrument, span}; use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags}; -use crate::core::build_steps::tool::SourceType; +use crate::core::build_steps::tool::{SourceType, copy_lld_artifacts}; use crate::core::build_steps::{dist, llvm}; use crate::core::builder; use crate::core::builder::{ @@ -2258,10 +2258,10 @@ impl Step for Assemble { copy_codegen_backends_to_sysroot(builder, build_compiler, target_compiler); if builder.config.lld_enabled { - builder.ensure(crate::core::build_steps::tool::LldWrapper { - build_compiler, - target_compiler, - }); + let lld_wrapper = builder.ensure( + crate::core::build_steps::tool::LldWrapper::for_compiler(builder, target_compiler), + ); + copy_lld_artifacts(builder, lld_wrapper, target_compiler); } if builder.config.llvm_enabled(target_compiler.host) && builder.config.llvm_tools_enabled { diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 2d3187274f2a..fc7e0f81ad9a 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -881,17 +881,50 @@ impl Step for Cargo { } } +/// Represents a built LldWrapper, the `lld-wrapper` tool itself, and a directory +/// containing a build of LLD. +#[derive(Clone)] +pub struct BuiltLldWrapper { + tool: ToolBuildResult, + lld_dir: PathBuf, +} + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct LldWrapper { pub build_compiler: Compiler, - pub target_compiler: Compiler, + pub target: TargetSelection, +} + +impl LldWrapper { + /// Returns `LldWrapper` that should be **used** by the passed compiler. + pub fn for_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self { + Self { + build_compiler: get_tool_target_compiler( + builder, + ToolTargetBuildMode::Dist(target_compiler), + ), + target: target_compiler.host, + } + } } impl Step for LldWrapper { - type Output = ToolBuildResult; + type Output = BuiltLldWrapper; + + const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.never() + run.path("src/tools/lld-wrapper") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(LldWrapper { + build_compiler: get_tool_target_compiler( + run.builder, + ToolTargetBuildMode::Build(run.target), + ), + target: run.target, + }); } #[cfg_attr( @@ -900,25 +933,16 @@ impl Step for LldWrapper { level = "debug", name = "LldWrapper::run", skip_all, - fields(build_compiler = ?self.build_compiler, target_compiler = ?self.target_compiler), + fields(build_compiler = ?self.build_compiler), ), )] - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { - if builder.config.dry_run() { - return ToolBuildResult { - tool_path: Default::default(), - build_compiler: self.build_compiler, - target_compiler: self.target_compiler, - }; - } - - let target = self.target_compiler.host; - - let tool_result = builder.ensure(ToolBuild { + fn run(self, builder: &Builder<'_>) -> Self::Output { + let lld_dir = builder.ensure(llvm::Lld { target: self.target }); + let tool = builder.ensure(ToolBuild { build_compiler: self.build_compiler, - target, + target: self.target, tool: "lld-wrapper", - mode: Mode::ToolStd, + mode: Mode::ToolTarget, path: "src/tools/lld-wrapper", source_type: SourceType::InTree, extra_features: Vec::new(), @@ -926,38 +950,41 @@ impl Step for LldWrapper { cargo_args: Vec::new(), artifact_kind: ToolArtifactKind::Binary, }); - - let libdir_bin = builder.sysroot_target_bindir(self.target_compiler, target); - t!(fs::create_dir_all(&libdir_bin)); - - let lld_install = builder.ensure(llvm::Lld { target }); - let src_exe = exe("lld", target); - let dst_exe = exe("rust-lld", target); - - builder.copy_link( - &lld_install.join("bin").join(src_exe), - &libdir_bin.join(dst_exe), - FileType::Executable, - ); - let self_contained_lld_dir = libdir_bin.join("gcc-ld"); - t!(fs::create_dir_all(&self_contained_lld_dir)); - - for name in crate::LLD_FILE_NAMES { - builder.copy_link( - &tool_result.tool_path, - &self_contained_lld_dir.join(exe(name, target)), - FileType::Executable, - ); - } - - tool_result + BuiltLldWrapper { tool, lld_dir } } fn metadata(&self) -> Option { - Some( - StepMetadata::build("LldWrapper", self.target_compiler.host) - .built_by(self.build_compiler), - ) + Some(StepMetadata::build("LldWrapper", self.target).built_by(self.build_compiler)) + } +} + +pub(crate) fn copy_lld_artifacts( + builder: &Builder<'_>, + lld_wrapper: BuiltLldWrapper, + target_compiler: Compiler, +) { + let target = target_compiler.host; + + let libdir_bin = builder.sysroot_target_bindir(target_compiler, target); + t!(fs::create_dir_all(&libdir_bin)); + + let src_exe = exe("lld", target); + let dst_exe = exe("rust-lld", target); + + builder.copy_link( + &lld_wrapper.lld_dir.join("bin").join(src_exe), + &libdir_bin.join(dst_exe), + FileType::Executable, + ); + let self_contained_lld_dir = libdir_bin.join("gcc-ld"); + t!(fs::create_dir_all(&self_contained_lld_dir)); + + for name in crate::LLD_FILE_NAMES { + builder.copy_link( + &lld_wrapper.tool.tool_path, + &self_contained_lld_dir.join(exe(name, target)), + FileType::Executable, + ); } } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 65e9c3850e79..34737606020c 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -981,7 +981,8 @@ impl<'a> Builder<'a> { tool::CoverageDump, tool::LlvmBitcodeLinker, tool::RustcPerf, - tool::WasmComponentLd + tool::WasmComponentLd, + tool::LldWrapper ), Kind::Clippy => describe!( clippy::Std, From d79e98c9baa3576bacbd74a0101e740b05a70801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 8 Jul 2025 17:34:09 +0200 Subject: [PATCH 081/363] Extend dist extended tools test --- src/bootstrap/src/core/builder/tests.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index bbcb58fca14f..d095b09ac01f 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1062,18 +1062,28 @@ mod snapshot { fn dist_extended() { let ctx = TestCtx::new(); insta::assert_snapshot!( - ctx - .config("dist") - .args(&["--set", "build.extended=true"]) - .render_steps(), @r" + ctx.config("dist") + .args(&[ + "--set", + "build.extended=true", + "--set", + "rust.llvm-bitcode-linker=true", + "--set", + "rust.lld=true", + ]) + .render_steps(), @r" [build] rustc 0 -> UnstableBookGen 1 [build] rustc 0 -> Rustbook 1 [build] llvm [build] rustc 0 -> rustc 1 + [build] rustc 0 -> LldWrapper 1 [build] rustc 0 -> WasmComponentLd 1 + [build] rustc 1 -> LlvmBitcodeLinker 2 [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 + [build] rustc 1 -> LldWrapper 2 [build] rustc 1 -> WasmComponentLd 2 + [build] rustc 2 -> LlvmBitcodeLinker 3 [build] rustdoc 1 [doc] std 2 [build] rustc 2 -> std 2 @@ -1092,7 +1102,6 @@ mod snapshot { [build] rustc 0 -> cargo-clippy 1 [build] rustc 0 -> miri 1 [build] rustc 0 -> cargo-miri 1 - [build] rustc 1 -> LlvmBitcodeLinker 2 "); } From 5933053aeb65f580116065869aaf5f0eaf35988e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 8 Jul 2025 17:38:27 +0200 Subject: [PATCH 082/363] Make `LlvmBitcodeLinker` a `ToolTarget` tool --- src/bootstrap/src/core/build_steps/compile.rs | 25 +++++++++--------- src/bootstrap/src/core/build_steps/dist.rs | 18 +++++-------- src/bootstrap/src/core/build_steps/install.rs | 2 +- src/bootstrap/src/core/build_steps/tool.rs | 26 ++++++++++++++----- src/bootstrap/src/core/builder/tests.rs | 15 ++++++----- 5 files changed, 49 insertions(+), 37 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 9e60a04e69fb..6d9160236e36 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2052,19 +2052,20 @@ impl Step for Assemble { } } - let maybe_install_llvm_bitcode_linker = |compiler| { + let maybe_install_llvm_bitcode_linker = || { if builder.config.llvm_bitcode_linker_enabled { trace!("llvm-bitcode-linker enabled, installing"); - let llvm_bitcode_linker = - builder.ensure(crate::core::build_steps::tool::LlvmBitcodeLinker { - build_compiler: compiler, - target: target_compiler.host, - }); + let llvm_bitcode_linker = builder.ensure( + crate::core::build_steps::tool::LlvmBitcodeLinker::for_compiler( + builder, + target_compiler, + ), + ); // Copy the llvm-bitcode-linker to the self-contained binary directory let bindir_self_contained = builder - .sysroot(compiler) - .join(format!("lib/rustlib/{}/bin/self-contained", compiler.host)); + .sysroot(target_compiler) + .join(format!("lib/rustlib/{}/bin/self-contained", target_compiler.host)); let tool_exe = exe("llvm-bitcode-linker", target_compiler.host); t!(fs::create_dir_all(&bindir_self_contained)); @@ -2091,9 +2092,9 @@ impl Step for Assemble { builder.info(&format!("Creating a sysroot for stage{stage} compiler (use `rustup toolchain link 'name' build/host/stage{stage}`)", stage = target_compiler.stage)); } - let mut precompiled_compiler = target_compiler; - precompiled_compiler.forced_compiler(true); - maybe_install_llvm_bitcode_linker(precompiled_compiler); + // FIXME: this is incomplete, we do not copy a bunch of other stuff to the downloaded + // sysroot... + maybe_install_llvm_bitcode_linker(); return target_compiler; } @@ -2300,7 +2301,7 @@ impl Step for Assemble { ); } - maybe_install_llvm_bitcode_linker(target_compiler); + maybe_install_llvm_bitcode_linker(); // Ensure that `libLLVM.so` ends up in the newly build compiler directory, // so that it can be found when the newly built `rustc` is run. diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 8b2d65ace50a..7d8825effc86 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1575,7 +1575,10 @@ impl Step for Extended { compiler: builder.compiler(stage, target), backend: "cranelift".to_string(), }); - add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {compiler, target}); + add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker { + target_compiler: compiler, + target + }); let etc = builder.src.join("src/etc/installer"); @@ -2343,7 +2346,7 @@ impl Step for LlvmTools { #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct LlvmBitcodeLinker { - pub compiler: Compiler, + pub target_compiler: Compiler, pub target: TargetSelection, } @@ -2359,23 +2362,16 @@ impl Step for LlvmBitcodeLinker { fn make_run(run: RunConfig<'_>) { run.builder.ensure(LlvmBitcodeLinker { - compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.host_target, - run.target, - ), + target_compiler: run.builder.compiler(run.builder.top_stage, run.target), target: run.target, }); } fn run(self, builder: &Builder<'_>) -> Option { - let compiler = self.compiler; let target = self.target; - builder.ensure(compile::Rustc::new(compiler, target)); - let llbc_linker = - builder.ensure(tool::LlvmBitcodeLinker { build_compiler: compiler, target }); + builder.ensure(tool::LlvmBitcodeLinker::for_compiler(builder, self.target_compiler)); let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple); diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 4434d6658eb2..285624916d18 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -287,7 +287,7 @@ install!((self, builder, _config), } }; LlvmBitcodeLinker, alias = "llvm-bitcode-linker", Self::should_build(_config), only_hosts: true, { - if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { compiler: self.compiler, target: self.target }) { + if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { target_compiler: self.compiler, target: self.target }) { install_sh(builder, "llvm-bitcode-linker", self.compiler.stage, Some(self.target), &tarball); } else { builder.info( diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index fc7e0f81ad9a..aa71574eef8a 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1159,8 +1159,21 @@ impl Step for RustAnalyzerProcMacroSrv { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct LlvmBitcodeLinker { - pub build_compiler: Compiler, - pub target: TargetSelection, + build_compiler: Compiler, + target: TargetSelection, +} + +impl LlvmBitcodeLinker { + /// Returns `LlvmBitcodeLinker` that should be **used** by the passed compiler. + pub fn for_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self { + Self { + build_compiler: get_tool_target_compiler( + builder, + ToolTargetBuildMode::Dist(target_compiler), + ), + target: target_compiler.host, + } + } } impl Step for LlvmBitcodeLinker { @@ -1176,9 +1189,10 @@ impl Step for LlvmBitcodeLinker { fn make_run(run: RunConfig<'_>) { run.builder.ensure(LlvmBitcodeLinker { - build_compiler: run - .builder - .compiler(run.builder.top_stage, run.builder.config.host_target), + build_compiler: get_tool_target_compiler( + run.builder, + ToolTargetBuildMode::Build(run.target), + ), target: run.target, }); } @@ -1192,7 +1206,7 @@ impl Step for LlvmBitcodeLinker { build_compiler: self.build_compiler, target: self.target, tool: "llvm-bitcode-linker", - mode: Mode::ToolRustc, + mode: Mode::ToolTarget, path: "src/tools/llvm-bitcode-linker", source_type: SourceType::InTree, extra_features: vec![], diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index d095b09ac01f..4ca9ff98dee4 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -769,11 +769,11 @@ mod snapshot { [build] llvm [build] rustc 0 -> rustc 1 [build] rustc 0 -> LldWrapper 1 - [build] rustc 1 -> LlvmBitcodeLinker 2 + [build] rustc 0 -> LlvmBitcodeLinker 1 [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [build] rustc 1 -> LldWrapper 2 - [build] rustc 2 -> LlvmBitcodeLinker 3 + [build] rustc 1 -> LlvmBitcodeLinker 2 [build] rustc 2 -> std 2 [build] rustdoc 1 " @@ -793,17 +793,17 @@ mod snapshot { [build] llvm [build] rustc 0 -> rustc 1 [build] rustc 0 -> LldWrapper 1 - [build] rustc 1 -> LlvmBitcodeLinker 2 + [build] rustc 0 -> LlvmBitcodeLinker 1 [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [build] rustc 1 -> LldWrapper 2 - [build] rustc 2 -> LlvmBitcodeLinker 3 + [build] rustc 1 -> LlvmBitcodeLinker 2 [build] rustc 1 -> std 1 [build] rustc 2 -> std 2 [build] llvm [build] rustc 1 -> rustc 2 [build] rustc 1 -> LldWrapper 2 - [build] rustc 2 -> LlvmBitcodeLinker 3 + [build] rustc 1 -> LlvmBitcodeLinker 2 [build] rustdoc 1 " ); @@ -1078,12 +1078,12 @@ mod snapshot { [build] rustc 0 -> rustc 1 [build] rustc 0 -> LldWrapper 1 [build] rustc 0 -> WasmComponentLd 1 - [build] rustc 1 -> LlvmBitcodeLinker 2 + [build] rustc 0 -> LlvmBitcodeLinker 1 [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [build] rustc 1 -> LldWrapper 2 [build] rustc 1 -> WasmComponentLd 2 - [build] rustc 2 -> LlvmBitcodeLinker 3 + [build] rustc 1 -> LlvmBitcodeLinker 2 [build] rustdoc 1 [doc] std 2 [build] rustc 2 -> std 2 @@ -1293,6 +1293,7 @@ mod snapshot { [build] rustc 0 -> miri 1 [build] rustc 0 -> cargo-miri 1 [build] rustc 1 -> LlvmBitcodeLinker 2 + [build] rustc 0 -> LlvmBitcodeLinker 1 "); } From 803b4d262241b22a4dfe75fcec49eaf920e0816b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Wed, 9 Jul 2025 18:11:26 +0200 Subject: [PATCH 083/363] core: Remove `BorrowedCursor::init_ref` method This method was not really useful: at no point one would only need to read the initialized part of the cursor without mutating it. --- library/core/src/io/borrowed_buf.rs | 10 ---------- library/coretests/tests/io/borrowed_buf.rs | 4 +--- library/std/src/io/mod.rs | 6 +++--- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index 854e03cf1827..11ace0419989 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -227,16 +227,6 @@ impl<'a> BorrowedCursor<'a> { self.buf.filled - self.start } - /// Returns a shared reference to the initialized portion of the cursor. - #[inline] - pub fn init_ref(&self) -> &[u8] { - // SAFETY: We only slice the initialized part of the buffer, which is always valid - unsafe { - let buf = self.buf.buf.get_unchecked(self.buf.filled..self.buf.init); - buf.assume_init_ref() - } - } - /// Returns a mutable reference to the initialized portion of the cursor. #[inline] pub fn init_mut(&mut self) -> &mut [u8] { diff --git a/library/coretests/tests/io/borrowed_buf.rs b/library/coretests/tests/io/borrowed_buf.rs index fbd3864dcac1..fe0e26f3e9d6 100644 --- a/library/coretests/tests/io/borrowed_buf.rs +++ b/library/coretests/tests/io/borrowed_buf.rs @@ -61,7 +61,7 @@ fn clear() { assert_eq!(rbuf.filled().len(), 0); assert_eq!(rbuf.unfilled().capacity(), 16); - assert_eq!(rbuf.unfilled().init_ref(), [255; 16]); + assert_eq!(rbuf.unfilled().init_mut(), [255; 16]); } #[test] @@ -142,7 +142,6 @@ fn cursor_set_init() { } assert_eq!(rbuf.init_len(), 8); - assert_eq!(rbuf.unfilled().init_ref().len(), 8); assert_eq!(rbuf.unfilled().init_mut().len(), 8); assert_eq!(rbuf.unfilled().uninit_mut().len(), 8); assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 16); @@ -160,7 +159,6 @@ fn cursor_set_init() { } assert_eq!(rbuf.init_len(), 12); - assert_eq!(rbuf.unfilled().init_ref().len(), 8); assert_eq!(rbuf.unfilled().init_mut().len(), 8); assert_eq!(rbuf.unfilled().uninit_mut().len(), 4); assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 12); diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 17c32d7a571c..d351ee5e739d 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -489,7 +489,7 @@ pub(crate) fn default_read_to_end( } }; - let unfilled_but_initialized = cursor.init_ref().len(); + let unfilled_but_initialized = cursor.init_mut().len(); let bytes_read = cursor.written(); let was_fully_initialized = read_buf.init_len() == buf_len; @@ -3053,7 +3053,7 @@ impl Read for Take { // The condition above guarantees that `self.limit` fits in `usize`. let limit = self.limit as usize; - let extra_init = cmp::min(limit, buf.init_ref().len()); + let extra_init = cmp::min(limit, buf.init_mut().len()); // SAFETY: no uninit data is written to ibuf let ibuf = unsafe { &mut buf.as_mut()[..limit] }; @@ -3068,7 +3068,7 @@ impl Read for Take { let mut cursor = sliced_buf.unfilled(); let result = self.inner.read_buf(cursor.reborrow()); - let new_init = cursor.init_ref().len(); + let new_init = cursor.init_mut().len(); let filled = sliced_buf.len(); // cursor / sliced_buf / ibuf must drop here From 34555f1b0b49e4fd944b2cb9c298f15b6b5da144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Wed, 9 Jul 2025 18:11:26 +0200 Subject: [PATCH 084/363] core: Remove `BorrowedCursor::uninit_mut` I assume that this method was there for completeness, but there is hardly any useful use of it: the buffer it gave was not always connected to the start of the cursor and its use required `unsafe` anyway to mark the bytes as initialized. --- library/core/src/io/borrowed_buf.rs | 13 +++---------- library/coretests/tests/io/borrowed_buf.rs | 2 -- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index 11ace0419989..bd468c9ee853 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -237,15 +237,6 @@ impl<'a> BorrowedCursor<'a> { } } - /// Returns a mutable reference to the uninitialized part of the cursor. - /// - /// It is safe to uninitialize any of these bytes. - #[inline] - pub fn uninit_mut(&mut self) -> &mut [MaybeUninit] { - // SAFETY: always in bounds - unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) } - } - /// Returns a mutable reference to the whole cursor. /// /// # Safety @@ -298,7 +289,9 @@ impl<'a> BorrowedCursor<'a> { /// Initializes all bytes in the cursor. #[inline] pub fn ensure_init(&mut self) -> &mut Self { - let uninit = self.uninit_mut(); + // SAFETY: always in bounds and we never uninitialize these bytes. + let uninit = unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) }; + // SAFETY: 0 is a valid value for MaybeUninit and the length matches the allocation // since it is comes from a slice reference. unsafe { diff --git a/library/coretests/tests/io/borrowed_buf.rs b/library/coretests/tests/io/borrowed_buf.rs index fe0e26f3e9d6..60829109d50b 100644 --- a/library/coretests/tests/io/borrowed_buf.rs +++ b/library/coretests/tests/io/borrowed_buf.rs @@ -143,7 +143,6 @@ fn cursor_set_init() { assert_eq!(rbuf.init_len(), 8); assert_eq!(rbuf.unfilled().init_mut().len(), 8); - assert_eq!(rbuf.unfilled().uninit_mut().len(), 8); assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 16); rbuf.unfilled().advance(4); @@ -160,6 +159,5 @@ fn cursor_set_init() { assert_eq!(rbuf.init_len(), 12); assert_eq!(rbuf.unfilled().init_mut().len(), 8); - assert_eq!(rbuf.unfilled().uninit_mut().len(), 4); assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 12); } From 65df66831f3fdb7f20a74e843a46bb90993221eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Wed, 9 Jul 2025 18:11:27 +0200 Subject: [PATCH 085/363] core: Change `BorrowedCursor::written`'s origin This enable removing the `start` field, so `BorrowedCursor` fits in a single register. Because `written` is almost always used in difference with another call, this changes nothing else in practice. --- library/core/src/io/borrowed_buf.rs | 12 +++--------- library/coretests/tests/io/borrowed_buf.rs | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index bd468c9ee853..b2f10d93b39d 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -132,7 +132,6 @@ impl<'data> BorrowedBuf<'data> { #[inline] pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> { BorrowedCursor { - start: self.filled, // SAFETY: we never assign into `BorrowedCursor::buf`, so treating its // lifetime covariantly is safe. buf: unsafe { @@ -188,9 +187,6 @@ pub struct BorrowedCursor<'a> { // we create a `BorrowedCursor`. This is only safe if we never replace `buf` by assigning into // it, so don't do that! buf: &'a mut BorrowedBuf<'a>, - /// The length of the filled portion of the underlying buffer at the time of the cursor's - /// creation. - start: usize, } impl<'a> BorrowedCursor<'a> { @@ -208,7 +204,6 @@ impl<'a> BorrowedCursor<'a> { self.buf, ) }, - start: self.start, } } @@ -218,13 +213,12 @@ impl<'a> BorrowedCursor<'a> { self.buf.capacity() - self.buf.filled } - /// Returns the number of bytes written to this cursor since it was created from a `BorrowedBuf`. + /// Returns the number of bytes written to the `BorrowedBuf` this cursor was created from. /// - /// Note that if this cursor is a reborrowed clone of another, then the count returned is the - /// count written via either cursor, not the count since the cursor was reborrowed. + /// In particular, the count returned is shared by all reborrows of the cursor. #[inline] pub fn written(&self) -> usize { - self.buf.filled - self.start + self.buf.filled } /// Returns a mutable reference to the initialized portion of the cursor. diff --git a/library/coretests/tests/io/borrowed_buf.rs b/library/coretests/tests/io/borrowed_buf.rs index 60829109d50b..869fc31fee99 100644 --- a/library/coretests/tests/io/borrowed_buf.rs +++ b/library/coretests/tests/io/borrowed_buf.rs @@ -124,7 +124,7 @@ fn reborrow_written() { assert_eq!(cursor2.written(), 32); assert_eq!(cursor.written(), 32); - assert_eq!(buf.unfilled().written(), 0); + assert_eq!(buf.unfilled().written(), 32); assert_eq!(buf.init_len(), 32); assert_eq!(buf.filled().len(), 32); let filled = buf.filled(); From 728017ea8f14e0cc343a6ded0e955868d628cc76 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 9 Jul 2025 17:06:39 +0000 Subject: [PATCH 086/363] Make AsyncDrop check that it's being implemented on a local ADT --- compiler/rustc_hir_analysis/messages.ftl | 2 +- .../src/coherence/builtin.rs | 6 ++++- compiler/rustc_hir_analysis/src/errors.rs | 1 + .../async-drop/foreign-fundamental.rs | 21 ++++++++++++++++ .../async-drop/foreign-fundamental.stderr | 24 +++++++++++++++++++ tests/ui/error-codes/E0120.rs | 2 +- 6 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 tests/ui/async-await/async-drop/foreign-fundamental.rs create mode 100644 tests/ui/async-await/async-drop/foreign-fundamental.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 529d3578985a..0429b2904769 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -158,7 +158,7 @@ hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be imp hir_analysis_drop_impl_negative = negative `Drop` impls are not supported hir_analysis_drop_impl_on_wrong_item = - the `Drop` trait may only be implemented for local structs, enums, and unions + the `{$trait_}` trait may only be implemented for local structs, enums, and unions .label = must be a struct, enum, or union in the current crate hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 8356a0af63c3..27948f50a4ad 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -37,6 +37,7 @@ pub(super) fn check_trait<'tcx>( let lang_items = tcx.lang_items(); let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header }; checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?; + checker.check(lang_items.async_drop_trait(), visit_implementation_of_drop)?; checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?; checker.check(lang_items.const_param_ty_trait(), |checker| { visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy) @@ -83,7 +84,10 @@ fn visit_implementation_of_drop(checker: &Checker<'_>) -> Result<(), ErrorGuaran let impl_ = tcx.hir_expect_item(impl_did).expect_impl(); - Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span })) + Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem { + span: impl_.self_ty.span, + trait_: tcx.item_name(checker.impl_header.trait_ref.skip_binder().def_id), + })) } fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index c1c828392126..9e29e5f6473e 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -205,6 +205,7 @@ pub(crate) struct DropImplOnWrongItem { #[primary_span] #[label] pub span: Span, + pub trait_: Symbol, } #[derive(Diagnostic)] diff --git a/tests/ui/async-await/async-drop/foreign-fundamental.rs b/tests/ui/async-await/async-drop/foreign-fundamental.rs new file mode 100644 index 000000000000..1c192fccd9f0 --- /dev/null +++ b/tests/ui/async-await/async-drop/foreign-fundamental.rs @@ -0,0 +1,21 @@ +//@ edition: 2018 + +#![feature(async_drop)] +//~^ WARN the feature `async_drop` is incomplete + +use std::future::AsyncDrop; +use std::pin::Pin; + +struct Foo; + +impl AsyncDrop for &Foo { + //~^ ERROR the `AsyncDrop` trait may only be implemented for + async fn drop(self: Pin<&mut Self>) {} +} + +impl AsyncDrop for Pin { + //~^ ERROR the `AsyncDrop` trait may only be implemented for + async fn drop(self: Pin<&mut Self>) {} +} + +fn main() {} diff --git a/tests/ui/async-await/async-drop/foreign-fundamental.stderr b/tests/ui/async-await/async-drop/foreign-fundamental.stderr new file mode 100644 index 000000000000..7b52329ac99d --- /dev/null +++ b/tests/ui/async-await/async-drop/foreign-fundamental.stderr @@ -0,0 +1,24 @@ +warning: the feature `async_drop` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/foreign-fundamental.rs:3:12 + | +LL | #![feature(async_drop)] + | ^^^^^^^^^^ + | + = note: see issue #126482 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0120]: the `AsyncDrop` trait may only be implemented for local structs, enums, and unions + --> $DIR/foreign-fundamental.rs:11:20 + | +LL | impl AsyncDrop for &Foo { + | ^^^^ must be a struct, enum, or union in the current crate + +error[E0120]: the `AsyncDrop` trait may only be implemented for local structs, enums, and unions + --> $DIR/foreign-fundamental.rs:16:20 + | +LL | impl AsyncDrop for Pin { + | ^^^^^^^^ must be a struct, enum, or union in the current crate + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0120`. diff --git a/tests/ui/error-codes/E0120.rs b/tests/ui/error-codes/E0120.rs index 35f544fddfbf..4e5cc7d6833b 100644 --- a/tests/ui/error-codes/E0120.rs +++ b/tests/ui/error-codes/E0120.rs @@ -1,4 +1,4 @@ -trait MyTrait { fn foo() {} } +trait MyTrait { fn foo(&self) {} } impl Drop for dyn MyTrait { //~^ ERROR E0120 From 925789456aa0bb112d8ab2fe3f31f4f7317f463b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Jul 2025 18:12:31 +0200 Subject: [PATCH 087/363] miri: fix out-of-bounds error for ptrs with negative offsets --- compiler/rustc_const_eval/messages.ftl | 27 ++++++++++--------- .../out_of_bounds_read_neg_offset.rs | 6 +++++ .../out_of_bounds_read_neg_offset.stderr | 21 +++++++++++++++ .../ptr_offset_out_of_bounds_neg2.rs | 6 +++++ .../ptr_offset_out_of_bounds_neg2.stderr | 20 ++++++++++++++ tests/ui/consts/offset_ub.rs | 14 +++++----- tests/ui/consts/offset_ub.stderr | 6 ++--- 7 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs create mode 100644 src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr create mode 100644 src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs create mode 100644 src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 22a1894ee720..dd12afb28532 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -294,19 +294,22 @@ const_eval_pointer_arithmetic_overflow = overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` const_eval_pointer_out_of_bounds = - {const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$inbounds_size_is_neg -> - [false] {$alloc_size_minus_ptr_offset -> - [0] is at or beyond the end of the allocation of size {$alloc_size -> - [1] 1 byte - *[x] {$alloc_size} bytes + {const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$ptr_offset_is_neg -> + [true] points to before the beginning of the allocation + *[false] {$inbounds_size_is_neg -> + [false] {$alloc_size_minus_ptr_offset -> + [0] is at or beyond the end of the allocation of size {$alloc_size -> + [1] 1 byte + *[x] {$alloc_size} bytes + } + [1] is only 1 byte from the end of the allocation + *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation + } + *[true] {$ptr_offset_abs -> + [0] is at the beginning of the allocation + *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation } - [1] is only 1 byte from the end of the allocation - *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation - } - *[true] {$ptr_offset_abs -> - [0] is at the beginning of the allocation - *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation - } + } } const_eval_pointer_use_after_free = diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs new file mode 100644 index 000000000000..107a3db91d85 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs @@ -0,0 +1,6 @@ +fn main() { + let v: Vec = vec![1, 2]; + // This read is also misaligned. We make sure that the OOB message has priority. + let x = unsafe { *v.as_ptr().wrapping_byte_sub(5) }; //~ ERROR: before the beginning of the allocation + panic!("this should never print: {}", x); +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr new file mode 100644 index 000000000000..5c37caa1ebf0 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr @@ -0,0 +1,21 @@ +error: Undefined Behavior: memory access failed: attempting to access 2 bytes, but got ALLOC-0x5 which points to before the beginning of the allocation + --> tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC + | +LL | let x = unsafe { *v.as_ptr().wrapping_byte_sub(5) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = 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: ALLOC was allocated here: + --> tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC + | +LL | let v: Vec = vec![1, 2]; + | ^^^^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs new file mode 100644 index 000000000000..0085e2af3673 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs @@ -0,0 +1,6 @@ +fn main() { + let v = [0i8; 4]; + let x = &v as *const i8; + let x = unsafe { x.wrapping_offset(-1).offset(-1) }; //~ERROR: before the beginning of the allocation + panic!("this should never print: {:?}", x); +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr new file mode 100644 index 000000000000..495aaf8d40ee --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by -1 bytes, but got ALLOC-0x1 which points to before the beginning of the allocation + --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC + | +LL | let x = unsafe { x.wrapping_offset(-1).offset(-1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = 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: ALLOC was allocated here: + --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC + | +LL | let v = [0i8; 4]; + | ^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/tests/ui/consts/offset_ub.rs b/tests/ui/consts/offset_ub.rs index 8c52586c485f..98a50156a948 100644 --- a/tests/ui/consts/offset_ub.rs +++ b/tests/ui/consts/offset_ub.rs @@ -5,17 +5,17 @@ use std::ptr; //@ normalize-stderr: "\d+ bytes" -> "$$BYTES bytes" -pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~ ERROR -pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~ ERROR -pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~ ERROR +pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~ ERROR: is at the beginning of the allocation +pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~ ERROR: only 1 byte from the end of the allocation +pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~ ERROR: only 100 bytes from the end of the allocation -pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~ ERROR -pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~ ERROR +pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~ ERROR: does not fit in an `isize` +pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~ ERROR: does not fit in an `isize` pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; //~ ERROR pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; //~ ERROR -pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; //~ ERROR +pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; //~ ERROR: before the beginning of the allocation -pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~ ERROR +pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~ ERROR: at or beyond the end of the allocation pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; //~ ERROR // Make sure that we don't panic when computing abs(offset*size_of::()) diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr index 255583ce91c5..d92ca09223de 100644 --- a/tests/ui/consts/offset_ub.stderr +++ b/tests/ui/consts/offset_ub.stderr @@ -40,11 +40,11 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNDERFLOW_ADDRESS_SPACE` failed here -error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which is only $BYTES bytes from the beginning of the allocation +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which points to before the beginning of the allocation --> $DIR/offset_ub.rs:16:49 | -LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEGATIVE_OFFSET` failed here +LL | ...*const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEGATIVE_OFFSET` failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes --> $DIR/offset_ub.rs:18:50 From 29614643e41b6d21e9fdb5d57bfab0d6319bea5b Mon Sep 17 00:00:00 2001 From: FractalFir Date: Tue, 8 Jul 2025 21:36:05 +0200 Subject: [PATCH 088/363] Change the implementation of supports_parallel to signal tha cg_gcc is not thread safe. --- src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 45e81aea5513..790e32a4bc68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -289,6 +289,10 @@ fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> { } impl ExtraBackendMethods for GccCodegenBackend { + fn supports_parallel(&self) -> bool { + false + } + fn codegen_allocator( &self, tcx: TyCtxt<'_>, @@ -357,8 +361,7 @@ impl Deref for SyncContext { } unsafe impl Send for SyncContext {} -// FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "-Zno-parallel-llvm". -// TODO: disable it here by returning false in CodegenBackend::supports_parallel(). +// FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "CodegenBackend::supports_parallel()". unsafe impl Sync for SyncContext {} impl WriteBackendMethods for GccCodegenBackend { From 63885243987a5df0e77ad0029961ebe8bd20cb18 Mon Sep 17 00:00:00 2001 From: FractalFir Date: Wed, 9 Jul 2025 20:22:44 +0200 Subject: [PATCH 089/363] Skip needlessly setting the default visibility on functions --- src/mono_item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono_item.rs b/src/mono_item.rs index 539e3ac85076..82faeec948c6 100644 --- a/src/mono_item.rs +++ b/src/mono_item.rs @@ -64,7 +64,7 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { if linkage != Linkage::Internal && self.tcx.is_compiler_builtins(LOCAL_CRATE) { #[cfg(feature = "master")] decl.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); - } else { + } else if visibility != Visibility::Default { #[cfg(feature = "master")] decl.add_attribute(FnAttribute::Visibility(base::visibility_to_gcc(visibility))); } From 7e844720bdedc7b8bb4ed1d5414e557d7358e7df Mon Sep 17 00:00:00 2001 From: FractalFir Date: Tue, 8 Jul 2025 23:00:40 +0200 Subject: [PATCH 090/363] Inserted a local variable in volatile_load, to ensure reads don't move across blocks. --- src/builder.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index 100091692bab..e65eea6d5994 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -980,7 +980,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn volatile_load(&mut self, ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> { let ptr = self.context.new_cast(self.location, ptr, ty.make_volatile().make_pointer()); - ptr.dereference(self.location).to_rvalue() + // (FractalFir): We insert a local here, to ensure this volatile load can't move across + // blocks. + let local = self.current_func().new_local(self.location, ty, "volatile_tmp"); + self.block.add_assignment(self.location, local, ptr.dereference(self.location).to_rvalue()); + local.to_rvalue() } fn atomic_load( From 42472f26452505cb42477990e6450bed21b3a50d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 9 Jul 2025 22:49:41 +0200 Subject: [PATCH 091/363] add missing word --- src/doc/rustc-dev-guide/src/tests/misc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/misc.md b/src/doc/rustc-dev-guide/src/tests/misc.md index c0288b3dd10c..39f881748792 100644 --- a/src/doc/rustc-dev-guide/src/tests/misc.md +++ b/src/doc/rustc-dev-guide/src/tests/misc.md @@ -9,7 +9,7 @@ for testing: - `RUSTC_BOOTSTRAP=1` will "cheat" and bypass usual stability checking, allowing you to use unstable features and cli flags on a stable `rustc`. -- `RUSTC_BOOTSTRAP=-1` will force a given `rustc` to pretend that is a stable +- `RUSTC_BOOTSTRAP=-1` will force a given `rustc` to pretend it is a stable compiler, even if it's actually a nightly `rustc`. This is useful because some behaviors of the compiler (e.g. diagnostics) can differ depending on whether the compiler is nightly or not. From d99af0b77cde2cc7d13419d7ca9b244afbcd365f Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 9 Jul 2025 23:02:16 +0200 Subject: [PATCH 092/363] distcheck had only one possible invocation That is, calling it an example is misleading --- src/doc/rustc-dev-guide/src/tests/intro.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/intro.md b/src/doc/rustc-dev-guide/src/tests/intro.md index c55d60f4a5c7..e97574f02de2 100644 --- a/src/doc/rustc-dev-guide/src/tests/intro.md +++ b/src/doc/rustc-dev-guide/src/tests/intro.md @@ -116,7 +116,9 @@ This requires building all of the documentation, which might take a while. `distcheck` verifies that the source distribution tarball created by the build system will unpack, build, and run all tests. -> Example: `./x test distcheck` +```console +./x test distcheck +``` ### Tool tests From 99fc05bb1830f6c6132ff7b1e48e2e655c863ad6 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 9 Jul 2025 23:03:37 +0200 Subject: [PATCH 093/363] do not invent a name Nowhere else is this called "Dist check" --- src/doc/rustc-dev-guide/src/tests/intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/intro.md b/src/doc/rustc-dev-guide/src/tests/intro.md index c55d60f4a5c7..84f99e9461e8 100644 --- a/src/doc/rustc-dev-guide/src/tests/intro.md +++ b/src/doc/rustc-dev-guide/src/tests/intro.md @@ -111,7 +111,7 @@ and it can be invoked so: This requires building all of the documentation, which might take a while. -### Dist check +### `distcheck` `distcheck` verifies that the source distribution tarball created by the build system will unpack, build, and run all tests. From e726c643e8319ee5eb2a8be45eb65f7600be2d5d Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 10 Jul 2025 04:58:14 +0000 Subject: [PATCH 094/363] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index a9394819541f..0af6b8c6fc79 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -688ea65df6a47866d0f72a00f1e18b47a7edf83b +32cd9114712a24010b0583624dc52ac302194128 From 5e940f581008dbc9b84aa1a8672a3c0a940da7be Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 10 Jul 2025 05:06:47 +0000 Subject: [PATCH 095/363] fmt --- src/tools/miri/src/machine.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 35399dbf4cb0..7c4d394525bd 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1828,7 +1828,9 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn enter_trace_span(span: impl FnOnce() -> tracing::Span) -> impl EnteredTraceSpan { #[cfg(feature = "tracing")] - { span().entered() } + { + span().entered() + } #[cfg(not(feature = "tracing"))] { let _ = span; // so we avoid the "unused variable" warning From 17b240e04f8d14e5563b6afb2ed3b842f87d1c78 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Jul 2025 08:33:05 +0200 Subject: [PATCH 096/363] silence clippy --- src/tools/miri/src/machine.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 7c4d394525bd..9c077e5b7b6e 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1832,6 +1832,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { span().entered() } #[cfg(not(feature = "tracing"))] + #[expect(clippy::unused_unit)] { let _ = span; // so we avoid the "unused variable" warning () From f1ae43f14d2b1737b71fc14c20b1242a74d66c2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 10 Jul 2025 09:56:59 +0200 Subject: [PATCH 097/363] Mention that compiler-builtins is now using `rustc-josh-sync` --- src/doc/rustc-dev-guide/src/external-repos.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index 0f7322357b9d..68986a0bc688 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -44,7 +44,7 @@ implement a new tool feature or test, that should happen in one collective rustc * `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` + * `compiler-builtins` ([josh sync](#synchronizing-a-josh-subtree)) * `stdarch` ([josh sync](#synchronizing-a-josh-subtree)) ### Josh subtrees @@ -56,6 +56,7 @@ The [josh] tool is an alternative to git subtrees, which manages git history in 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: +- compiler-builtins - rustc-dev-guide - stdarch From c6bedc1bf9752c482e7a2fd58e24c7569fb58555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 10 Jul 2025 10:02:39 +0200 Subject: [PATCH 098/363] Migrate rustc-pull to CI workflow from `josh-sync` --- .../.github/workflows/rustc-pull.yml | 111 ++---------------- 1 file changed, 9 insertions(+), 102 deletions(-) diff --git a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml index 7190fc733db0..ad570ee4595d 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml @@ -9,105 +9,12 @@ on: jobs: pull: if: github.repository == 'rust-lang/rustc-dev-guide' - runs-on: ubuntu-latest - outputs: - pr_url: ${{ steps.update-pr.outputs.pr_url }} - permissions: - contents: write - pull-requests: write - steps: - - uses: actions/checkout@v4 - with: - # We need the full history for josh to work - fetch-depth: '0' - - name: Install stable Rust toolchain - run: rustup update stable - - uses: Swatinem/rust-cache@v2 - with: - # Cache the josh directory with checked out rustc - cache-directories: "/home/runner/.cache/rustc-josh" - - name: Install rustc-josh-sync - run: cargo install --locked --git https://github.com/rust-lang/josh-sync - - name: Setup bot git name and email - run: | - git config --global user.name 'The rustc-dev-guide Cronjob Bot' - git config --global user.email 'github-actions@github.com' - - name: Perform rustc-pull - id: rustc-pull - # Turn off -e to disable early exit - shell: bash {0} - run: | - rustc-josh-sync pull - exitcode=$? - - # If no pull was performed, we want to mark this job as successful, - # but we do not want to perform the follow-up steps. - if [ $exitcode -eq 0 ]; then - echo "pull_result=pull-finished" >> $GITHUB_OUTPUT - elif [ $exitcode -eq 2 ]; then - echo "pull_result=skipped" >> $GITHUB_OUTPUT - exitcode=0 - fi - - exit ${exitcode} - - name: Push changes to a branch - if: ${{ steps.rustc-pull.outputs.pull_result == 'pull-finished' }} - run: | - # Update a sticky branch that is used only for rustc pulls - BRANCH="rustc-pull" - git switch -c $BRANCH - git push -u origin $BRANCH --force - - name: Create pull request - id: update-pr - if: ${{ steps.rustc-pull.outputs.pull_result == 'pull-finished' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # Check if an open pull request for an rustc pull update already exists - # If it does, the previous push has just updated it - # If not, we create it now - RESULT=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | length' --json title` - if [[ "$RESULT" -eq 0 ]]; then - echo "Creating new pull request" - PR_URL=`gh pr create -B master --title 'Rustc pull update' --body 'Latest update from rustc.'` - echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT - else - PR_URL=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].url' --json url,title` - echo "Updating pull request ${PR_URL}" - echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT - fi - send-zulip-message: - needs: [pull] - if: ${{ !cancelled() }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Compute message - id: create-message - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - if [ "${{ needs.pull.result }}" == "failure" ]; then - WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - echo "message=Rustc pull sync failed. Check out the [workflow URL]($WORKFLOW_URL)." >> $GITHUB_OUTPUT - else - CREATED_AT=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].createdAt' --json createdAt,title` - PR_URL=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].url' --json url,title` - week_ago=$(date +%F -d '7 days ago') - - # If there is an open PR that is at least a week old, post a message about it - if [[ -n $DATE_GH && $DATE_GH < $week_ago ]]; then - echo "message=A PR with a Rustc pull has been opened for more a week. Check out the [PR](${PR_URL})." >> $GITHUB_OUTPUT - fi - fi - - name: Send a Zulip message about updated PR - if: ${{ steps.create-message.outputs.message != '' }} - uses: zulip/github-actions-zulip/send-message@e4c8f27c732ba9bd98ac6be0583096dea82feea5 - with: - api-key: ${{ secrets.ZULIP_API_TOKEN }} - email: "rustc-dev-guide-gha-notif-bot@rust-lang.zulipchat.com" - organization-url: "https://rust-lang.zulipchat.com" - to: 196385 - type: "stream" - topic: "Subtree sync automation" - content: ${{ steps.create-message.outputs.message }} + uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@main + with: + zulip-stream-id: 196385 + zulip-bot-email: "rustc-dev-guide-gha-notif-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 }} From 205587b37e8598b2123a803de2df076ef501706d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 10 Jul 2025 10:10:55 +0200 Subject: [PATCH 099/363] Rename `for_compiler` to `for_use_by_compiler` --- src/bootstrap/src/core/build_steps/compile.rs | 17 ++++++++++------- src/bootstrap/src/core/build_steps/dist.rs | 4 ++-- src/bootstrap/src/core/build_steps/tool.rs | 6 +++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 6d9160236e36..d1285340cd6a 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2056,7 +2056,7 @@ impl Step for Assemble { if builder.config.llvm_bitcode_linker_enabled { trace!("llvm-bitcode-linker enabled, installing"); let llvm_bitcode_linker = builder.ensure( - crate::core::build_steps::tool::LlvmBitcodeLinker::for_compiler( + crate::core::build_steps::tool::LlvmBitcodeLinker::for_use_by_compiler( builder, target_compiler, ), @@ -2259,9 +2259,11 @@ impl Step for Assemble { copy_codegen_backends_to_sysroot(builder, build_compiler, target_compiler); if builder.config.lld_enabled { - let lld_wrapper = builder.ensure( - crate::core::build_steps::tool::LldWrapper::for_compiler(builder, target_compiler), - ); + let lld_wrapper = + builder.ensure(crate::core::build_steps::tool::LldWrapper::for_use_by_compiler( + builder, + target_compiler, + )); copy_lld_artifacts(builder, lld_wrapper, target_compiler); } @@ -2289,11 +2291,12 @@ impl Step for Assemble { // In addition to `rust-lld` also install `wasm-component-ld` when // is enabled. This is used by the `wasm32-wasip2` target of Rust. if builder.tool_enabled("wasm-component-ld") { - let wasm_component = - builder.ensure(crate::core::build_steps::tool::WasmComponentLd::for_compiler( + let wasm_component = builder.ensure( + crate::core::build_steps::tool::WasmComponentLd::for_use_by_compiler( builder, target_compiler, - )); + ), + ); builder.copy_link( &wasm_component.tool_path, &libdir_bin.join(wasm_component.tool_path.file_name().unwrap()), diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 7d8825effc86..af17a69302b2 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2370,8 +2370,8 @@ impl Step for LlvmBitcodeLinker { fn run(self, builder: &Builder<'_>) -> Option { let target = self.target; - let llbc_linker = - builder.ensure(tool::LlvmBitcodeLinker::for_compiler(builder, self.target_compiler)); + let llbc_linker = builder + .ensure(tool::LlvmBitcodeLinker::for_use_by_compiler(builder, self.target_compiler)); let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index aa71574eef8a..daa47db76b0c 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -897,7 +897,7 @@ pub struct LldWrapper { impl LldWrapper { /// Returns `LldWrapper` that should be **used** by the passed compiler. - pub fn for_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self { + pub fn for_use_by_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self { Self { build_compiler: get_tool_target_compiler( builder, @@ -998,7 +998,7 @@ pub struct WasmComponentLd { impl WasmComponentLd { /// Returns `WasmComponentLd` that should be **used** by the passed compiler. - pub fn for_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self { + pub fn for_use_by_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self { Self { build_compiler: get_tool_target_compiler( builder, @@ -1165,7 +1165,7 @@ pub struct LlvmBitcodeLinker { impl LlvmBitcodeLinker { /// Returns `LlvmBitcodeLinker` that should be **used** by the passed compiler. - pub fn for_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self { + pub fn for_use_by_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self { Self { build_compiler: get_tool_target_compiler( builder, From 85c286aaa839d61c25398cce5aa3b1889e5861c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 10 Jul 2025 10:12:55 +0200 Subject: [PATCH 100/363] Clarify `get_tool_target_compiler` --- src/bootstrap/src/core/build_steps/tool.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index daa47db76b0c..caaaaad845d6 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -381,20 +381,26 @@ pub(crate) fn get_tool_target_compiler( builder: &Builder<'_>, mode: ToolTargetBuildMode, ) -> Compiler { - let (target, min_build_compiler_stage) = match mode { + let (target, build_compiler_stage) = match mode { ToolTargetBuildMode::Build(target) => { assert!(builder.top_stage > 0); + // If we want to build a stage N tool, we need to compile it with stage N-1 rustc (target, builder.top_stage - 1) } ToolTargetBuildMode::Dist(target_compiler) => { assert!(target_compiler.stage > 0); + // If we want to dist a stage N rustc, we want to attach stage N tool to it. + // And to build that tool, we need to compile it with stage N-1 rustc (target_compiler.host, target_compiler.stage - 1) } }; + let compiler = if builder.host_target == target { - builder.compiler(min_build_compiler_stage, builder.host_target) + builder.compiler(build_compiler_stage, builder.host_target) } else { - builder.compiler(min_build_compiler_stage.max(1), builder.host_target) + // If we are cross-compiling a stage 1 tool, we cannot do that with a stage 0 compiler, + // so we auto-bump the tool's stage to 2. + builder.compiler(build_compiler_stage.max(1), builder.host_target) }; builder.std(compiler, target); compiler From 81a6f189408b71b452a9804818f2cd50d2ed9108 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Wed, 9 Jul 2025 15:24:28 +0500 Subject: [PATCH 101/363] added error for invalid char cast --- compiler/rustc_lint/messages.ftl | 7 ++ compiler/rustc_lint/src/lints.rs | 14 +++ compiler/rustc_lint/src/types/literal.rs | 42 ++++++-- tests/ui/cast/cast-char.rs | 56 +++++++++- tests/ui/cast/cast-char.stderr | 124 +++++++++++++++++++++-- 5 files changed, 222 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 8d9f2385b710..5d07afdaf17b 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -440,6 +440,7 @@ lint_invalid_asm_label_named = avoid using named labels in inline assembly .help = only local labels of the form `:` should be used in inline asm .note = see the asm section of Rust By Example for more information lint_invalid_asm_label_no_span = the label may be declared in the expansion of a macro + lint_invalid_crate_type_value = invalid `crate_type` value .suggestion = did you mean @@ -790,6 +791,9 @@ lint_supertrait_as_deref_target = this `Deref` implementation is covered by an i .label2 = target type is a supertrait of `{$self_ty}` .help = consider removing this implementation or replacing it with a method instead +lint_surrogate_char_cast = surrogate values are not valid for `char` + .note = `0xD800..=0xDFFF` are reserved for Unicode surrogates and are not valid `char` values + lint_suspicious_double_ref_clone = using `.clone()` on a double reference, which returns `{$ty}` instead of cloning the inner type @@ -799,6 +803,9 @@ lint_suspicious_double_ref_deref = lint_symbol_intern_string_literal = using `Symbol::intern` on a string literal .help = consider adding the symbol to `compiler/rustc_span/src/symbol.rs` +lint_too_large_char_cast = value exceeds maximum `char` value + .note = maximum valid `char` value is `0x10FFFF` + lint_trailing_semi_macro = trailing semicolon in macro used in expression position .note1 = macro invocations at the end of a block are treated as expressions .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}` diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 21148833eaf7..19989cbcce68 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1746,6 +1746,20 @@ pub(crate) struct OverflowingLiteral<'a> { pub lit: String, } +#[derive(LintDiagnostic)] +#[diag(lint_surrogate_char_cast)] +#[note] +pub(crate) struct SurrogateCharCast { + pub literal: u128, +} + +#[derive(LintDiagnostic)] +#[diag(lint_too_large_char_cast)] +#[note] +pub(crate) struct TooLargeCharCast { + pub literal: u128, +} + #[derive(LintDiagnostic)] #[diag(lint_uses_power_alignment)] pub(crate) struct UsesPowerAlignment; diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs index d44f45177bde..2bac58ba23d0 100644 --- a/compiler/rustc_lint/src/types/literal.rs +++ b/compiler/rustc_lint/src/types/literal.rs @@ -12,7 +12,7 @@ use crate::context::LintContext; use crate::lints::{ OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub, OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, - RangeEndpointOutOfRange, UseInclusiveRange, + RangeEndpointOutOfRange, SurrogateCharCast, TooLargeCharCast, UseInclusiveRange, }; use crate::types::{OVERFLOWING_LITERALS, TypeLimits}; @@ -38,12 +38,18 @@ fn lint_overflowing_range_endpoint<'tcx>( // We only want to handle exclusive (`..`) ranges, // which are represented as `ExprKind::Struct`. - let Node::ExprField(field) = cx.tcx.parent_hir_node(hir_id) else { return false }; - let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { return false }; + let Node::ExprField(field) = cx.tcx.parent_hir_node(hir_id) else { + return false; + }; + let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { + return false; + }; if !is_range_literal(struct_expr) { return false; }; - let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { return false }; + let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { + return false; + }; // We can suggest using an inclusive range // (`..=`) instead only if it is the `end` that is @@ -61,7 +67,9 @@ fn lint_overflowing_range_endpoint<'tcx>( }; let sub_sugg = if span.lo() == lit_span.lo() { - let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false }; + let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { + return false; + }; UseInclusiveRange::WithoutParen { sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()), start, @@ -316,11 +324,25 @@ fn lint_uint_literal<'tcx>( match par_e.kind { hir::ExprKind::Cast(..) => { if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { - cx.emit_span_lint( - OVERFLOWING_LITERALS, - par_e.span, - OnlyCastu8ToChar { span: par_e.span, literal: lit_val }, - ); + if lit_val > 0x10FFFF { + cx.emit_span_lint( + OVERFLOWING_LITERALS, + par_e.span, + TooLargeCharCast { literal: lit_val }, + ); + } else if (0xD800..=0xDFFF).contains(&lit_val) { + cx.emit_span_lint( + OVERFLOWING_LITERALS, + par_e.span, + SurrogateCharCast { literal: lit_val }, + ); + } else { + cx.emit_span_lint( + OVERFLOWING_LITERALS, + par_e.span, + OnlyCastu8ToChar { span: par_e.span, literal: lit_val }, + ); + } return; } } diff --git a/tests/ui/cast/cast-char.rs b/tests/ui/cast/cast-char.rs index 9634ed56f7b7..5bf05072253f 100644 --- a/tests/ui/cast/cast-char.rs +++ b/tests/ui/cast/cast-char.rs @@ -1,10 +1,58 @@ #![deny(overflowing_literals)] fn main() { - const XYZ: char = 0x1F888 as char; + // Valid cases - should suggest char literal + + // u8 range (0-255) + const VALID_U8_1: char = 0x41 as char; // 'A' + const VALID_U8_2: char = 0xFF as char; // maximum u8 + const VALID_U8_3: char = 0x00 as char; // minimum u8 + + // Valid Unicode in lower range [0x0, 0xD7FF] + const VALID_LOW_1: char = 0x1000 as char; // 4096 + //~^ ERROR: only `u8` can be cast into `char` + const VALID_LOW_2: char = 0xD7FF as char; // last valid in lower range + //~^ ERROR: only `u8` can be cast into `char` + const VALID_LOW_3: char = 0x0500 as char; // cyrillic range + //~^ ERROR: only `u8` can be cast into `char` + + // Valid Unicode in upper range [0xE000, 0x10FFFF] + const VALID_HIGH_1: char = 0xE000 as char; // first valid in upper range //~^ ERROR only `u8` can be cast into `char` - const XY: char = 129160 as char; + const VALID_HIGH_2: char = 0x1F888 as char; // 129160 - example from issue + //~^ ERROR only `u8` can be cast into `char` + const VALID_HIGH_3: char = 0x10FFFF as char; // maximum valid Unicode + //~^ ERROR only `u8` can be cast into `char` + const VALID_HIGH_4: char = 0xFFFD as char; // replacement character + //~^ ERROR only `u8` can be cast into `char` + const VALID_HIGH_5: char = 0x1F600 as char; // emoji + //~^ ERROR only `u8` can be cast into `char` + + // Invalid cases - should show InvalidCharCast + + // Surrogate range [0xD800, 0xDFFF] - reserved for UTF-16 + const INVALID_SURROGATE_1: char = 0xD800 as char; // first surrogate + //~^ ERROR: surrogate values are not valid + const INVALID_SURROGATE_2: char = 0xDFFF as char; // last surrogate + //~^ ERROR: surrogate values are not valid + const INVALID_SURROGATE_3: char = 0xDB00 as char; // middle of surrogate range + //~^ ERROR: surrogate values are not valid + + // Too large values (> 0x10FFFF) + const INVALID_TOO_BIG_1: char = 0x110000 as char; // one more than maximum + //~^ ERROR: value exceeds maximum `char` value + const INVALID_TOO_BIG_2: char = 0xEF8888 as char; // example from issue + //~^ ERROR: value exceeds maximum `char` value + const INVALID_TOO_BIG_3: char = 0x1FFFFF as char; // much larger + //~^ ERROR: value exceeds maximum `char` value + const INVALID_TOO_BIG_4: char = 0xFFFFFF as char; // 24-bit maximum + //~^ ERROR: value exceeds maximum `char` value + + // Boundary cases + const BOUNDARY_1: char = 0xD7FE as char; // valid, before surrogate + //~^ ERROR only `u8` can be cast into `char` + const BOUNDARY_2: char = 0xE001 as char; // valid, after surrogate + //~^ ERROR only `u8` can be cast into `char` + const BOUNDARY_3: char = 0x10FFFE as char; // valid, near maximum //~^ ERROR only `u8` can be cast into `char` - const ZYX: char = '\u{01F888}'; - println!("{}", XYZ); } diff --git a/tests/ui/cast/cast-char.stderr b/tests/ui/cast/cast-char.stderr index 211937c9d6fa..a8d0b3b04b0c 100644 --- a/tests/ui/cast/cast-char.stderr +++ b/tests/ui/cast/cast-char.stderr @@ -1,8 +1,8 @@ error: only `u8` can be cast into `char` - --> $DIR/cast-char.rs:4:23 + --> $DIR/cast-char.rs:12:31 | -LL | const XYZ: char = 0x1F888 as char; - | ^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'` +LL | const VALID_LOW_1: char = 0x1000 as char; // 4096 + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1000}'` | note: the lint level is defined here --> $DIR/cast-char.rs:1:9 @@ -11,10 +11,120 @@ LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ error: only `u8` can be cast into `char` - --> $DIR/cast-char.rs:6:22 + --> $DIR/cast-char.rs:14:31 | -LL | const XY: char = 129160 as char; - | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'` +LL | const VALID_LOW_2: char = 0xD7FF as char; // last valid in lower range + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{D7FF}'` -error: aborting due to 2 previous errors +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:16:31 + | +LL | const VALID_LOW_3: char = 0x0500 as char; // cyrillic range + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{500}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:20:32 + | +LL | const VALID_HIGH_1: char = 0xE000 as char; // first valid in upper range + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{E000}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:22:32 + | +LL | const VALID_HIGH_2: char = 0x1F888 as char; // 129160 - example from issue + | ^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:24:32 + | +LL | const VALID_HIGH_3: char = 0x10FFFF as char; // maximum valid Unicode + | ^^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{10FFFF}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:26:32 + | +LL | const VALID_HIGH_4: char = 0xFFFD as char; // replacement character + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{FFFD}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:28:32 + | +LL | const VALID_HIGH_5: char = 0x1F600 as char; // emoji + | ^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F600}'` + +error: surrogate values are not valid for `char` + --> $DIR/cast-char.rs:34:39 + | +LL | const INVALID_SURROGATE_1: char = 0xD800 as char; // first surrogate + | ^^^^^^^^^^^^^^ + | + = note: `0xD800..=0xDFFF` are reserved for Unicode surrogates and are not valid `char` values + +error: surrogate values are not valid for `char` + --> $DIR/cast-char.rs:36:39 + | +LL | const INVALID_SURROGATE_2: char = 0xDFFF as char; // last surrogate + | ^^^^^^^^^^^^^^ + | + = note: `0xD800..=0xDFFF` are reserved for Unicode surrogates and are not valid `char` values + +error: surrogate values are not valid for `char` + --> $DIR/cast-char.rs:38:39 + | +LL | const INVALID_SURROGATE_3: char = 0xDB00 as char; // middle of surrogate range + | ^^^^^^^^^^^^^^ + | + = note: `0xD800..=0xDFFF` are reserved for Unicode surrogates and are not valid `char` values + +error: value exceeds maximum `char` value + --> $DIR/cast-char.rs:42:37 + | +LL | const INVALID_TOO_BIG_1: char = 0x110000 as char; // one more than maximum + | ^^^^^^^^^^^^^^^^ + | + = note: maximum valid `char` value is `0x10FFFF` + +error: value exceeds maximum `char` value + --> $DIR/cast-char.rs:44:37 + | +LL | const INVALID_TOO_BIG_2: char = 0xEF8888 as char; // example from issue + | ^^^^^^^^^^^^^^^^ + | + = note: maximum valid `char` value is `0x10FFFF` + +error: value exceeds maximum `char` value + --> $DIR/cast-char.rs:46:37 + | +LL | const INVALID_TOO_BIG_3: char = 0x1FFFFF as char; // much larger + | ^^^^^^^^^^^^^^^^ + | + = note: maximum valid `char` value is `0x10FFFF` + +error: value exceeds maximum `char` value + --> $DIR/cast-char.rs:48:37 + | +LL | const INVALID_TOO_BIG_4: char = 0xFFFFFF as char; // 24-bit maximum + | ^^^^^^^^^^^^^^^^ + | + = note: maximum valid `char` value is `0x10FFFF` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:52:30 + | +LL | const BOUNDARY_1: char = 0xD7FE as char; // valid, before surrogate + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{D7FE}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:54:30 + | +LL | const BOUNDARY_2: char = 0xE001 as char; // valid, after surrogate + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{E001}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:56:30 + | +LL | const BOUNDARY_3: char = 0x10FFFE as char; // valid, near maximum + | ^^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{10FFFE}'` + +error: aborting due to 18 previous errors From e6bb6442a9029633cc53db546880c05acb6734a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 10 Jul 2025 19:19:59 +0200 Subject: [PATCH 102/363] Remove `min-specialization` feature from `WasmComponentLd` --- src/bootstrap/src/core/build_steps/tool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index caaaaad845d6..df89eb1da20c 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1052,7 +1052,7 @@ impl Step for WasmComponentLd { path: "src/tools/wasm-component-ld", source_type: SourceType::InTree, extra_features: vec![], - allow_features: "min-specialization", + allow_features: "", cargo_args: vec![], artifact_kind: ToolArtifactKind::Binary, }) From 13b1e4030aecb24b5a78cfa44594641e7d49b4b6 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 11 Jul 2025 03:57:19 -0700 Subject: [PATCH 103/363] More discriminant codegen tests These are from 139729, updated to pass on master. --- tests/codegen/enum/enum-discriminant-eq.rs | 231 ++++++++++++++++ tests/codegen/enum/enum-match.rs | 307 +++++++++++++++++++++ 2 files changed, 538 insertions(+) create mode 100644 tests/codegen/enum/enum-discriminant-eq.rs diff --git a/tests/codegen/enum/enum-discriminant-eq.rs b/tests/codegen/enum/enum-discriminant-eq.rs new file mode 100644 index 000000000000..fd6f3499cb1f --- /dev/null +++ b/tests/codegen/enum/enum-discriminant-eq.rs @@ -0,0 +1,231 @@ +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +//@ min-llvm-version: 20 +//@ only-64bit + +// The `derive(PartialEq)` on enums with field-less variants compares discriminants, +// so make sure we emit that in some reasonable way. + +#![crate_type = "lib"] +#![feature(ascii_char)] +#![feature(core_intrinsics)] +#![feature(repr128)] + +use std::ascii::Char as AC; +use std::cmp::Ordering; +use std::intrinsics::discriminant_value; +use std::num::NonZero; + +// A type that's bigger than `isize`, unlike the usual cases that have small tags. +#[repr(u128)] +pub enum Giant { + Two = 2, + Three = 3, + Four = 4, +} + +#[unsafe(no_mangle)] +pub fn opt_bool_eq_discr(a: Option, b: Option) -> bool { + // CHECK-LABEL: @opt_bool_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i8 %a, 2 + // CHECK: %[[B:.+]] = icmp eq i8 %b, 2 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn opt_ord_eq_discr(a: Option, b: Option) -> bool { + // CHECK-LABEL: @opt_ord_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i8 %a, 2 + // CHECK: %[[B:.+]] = icmp eq i8 %b, 2 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn opt_nz32_eq_discr(a: Option>, b: Option>) -> bool { + // CHECK-LABEL: @opt_nz32_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i32 %a, 0 + // CHECK: %[[B:.+]] = icmp eq i32 %b, 0 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn opt_ac_eq_discr(a: Option, b: Option) -> bool { + // CHECK-LABEL: @opt_ac_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i8 %a, -128 + // CHECK: %[[B:.+]] = icmp eq i8 %b, -128 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn opt_giant_eq_discr(a: Option, b: Option) -> bool { + // CHECK-LABEL: @opt_giant_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i128 %a, 1 + // CHECK: %[[B:.+]] = icmp eq i128 %b, 1 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +pub enum Mid { + Before, + Thing(T), + After, +} + +#[unsafe(no_mangle)] +pub fn mid_bool_eq_discr(a: Mid, b: Mid) -> bool { + // CHECK-LABEL: @mid_bool_eq_discr( + + // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2 + // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3 + // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) + // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 + + // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2 + // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3 + // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) + // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 + + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn mid_ord_eq_discr(a: Mid, b: Mid) -> bool { + // CHECK-LABEL: @mid_ord_eq_discr( + + // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2 + // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3 + // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) + // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 + + // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2 + // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3 + // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) + // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 + + // CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]] + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn mid_nz32_eq_discr(a: Mid>, b: Mid>) -> bool { + // CHECK-LABEL: @mid_nz32_eq_discr( + // CHECK: %[[R:.+]] = icmp eq i32 %a.0, %b.0 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn mid_ac_eq_discr(a: Mid, b: Mid) -> bool { + // CHECK-LABEL: @mid_ac_eq_discr( + + // CHECK: %[[A_REL_DISCR:.+]] = xor i8 %a, -128 + // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3 + // 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 + + // CHECK: %[[B_REL_DISCR:.+]] = xor i8 %b, -128 + // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3 + // 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 + + // CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]] + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +// FIXME: This should be improved once our LLVM fork picks up the fix for +// +#[unsafe(no_mangle)] +pub fn mid_giant_eq_discr(a: Mid, b: Mid) -> bool { + // CHECK-LABEL: @mid_giant_eq_discr( + + // CHECK: %[[A_REL_DISCR_WIDE:.+]] = add nsw i128 %a, -5 + // CHECK: %[[A_REL_DISCR:.+]] = trunc nsw i128 %[[A_REL_DISCR_WIDE]] to i64 + // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i128 %[[A_REL_DISCR_WIDE]], 3 + // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i128 %[[A_REL_DISCR_WIDE]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) + // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i64 %[[A_REL_DISCR]], i64 1 + + // CHECK: %[[B_REL_DISCR_WIDE:.+]] = add nsw i128 %b, -5 + // CHECK: %[[B_REL_DISCR:.+]] = trunc nsw i128 %[[B_REL_DISCR_WIDE]] to i64 + // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i128 %[[B_REL_DISCR_WIDE]], 3 + // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i128 %[[B_REL_DISCR_WIDE]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) + // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i64 %[[B_REL_DISCR]], i64 1 + + // CHECK: %[[R:.+]] = icmp eq i64 %[[A_DISCR]], %[[B_DISCR]] + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +// In niche-encoded enums, testing for the untagged variant should optimize to a +// straight-forward comparison looking for the natural range of the payload value. +// FIXME: A bunch don't, though. + +#[unsafe(no_mangle)] +pub fn mid_bool_is_thing(a: Mid) -> bool { + // CHECK-LABEL: @mid_bool_is_thing( + + // CHECK: %[[REL_DISCR:.+]] = add nsw i8 %a, -2 + // CHECK: %[[R:.+]] = icmp ugt i8 %[[REL_DISCR]], 2 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} + +#[unsafe(no_mangle)] +pub fn mid_ord_is_thing(a: Mid) -> bool { + // CHECK-LABEL: @mid_ord_is_thing( + // CHECK: %[[REL_DISCR:.+]] = add nsw i8 %a, -2 + // CHECK: %[[R:.+]] = icmp ugt i8 %[[REL_DISCR]], 2 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} + +#[unsafe(no_mangle)] +pub fn mid_nz32_is_thing(a: Mid>) -> bool { + // CHECK-LABEL: @mid_nz32_is_thing( + // CHECK: %[[R:.+]] = icmp eq i32 %a.0, 1 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} + +#[unsafe(no_mangle)] +pub fn mid_ac_is_thing(a: Mid) -> bool { + // CHECK-LABEL: @mid_ac_is_thing( + // CHECK: %[[R:.+]] = icmp sgt i8 %a, -1 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} + +#[unsafe(no_mangle)] +pub fn mid_giant_is_thing(a: Mid) -> bool { + // CHECK-LABEL: @mid_giant_is_thing( + // CHECK: %[[REL_DISCR_WIDE:.+]] = add nsw i128 %a, -5 + // CHECK: %[[REL_DISCR:.+]] = trunc nsw i128 %[[REL_DISCR_WIDE]] to i64 + // CHECK: %[[NOT_NICHE:.+]] = icmp ugt i128 %[[REL_DISCR_WIDE]], 2 + // CHECK: %[[IS_MID_VARIANT:.+]] = icmp eq i64 %[[REL_DISCR]], 1 + // CHECK: %[[R:.+]] = select i1 %[[NOT_NICHE]], i1 true, i1 %[[IS_MID_VARIANT]] + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs index 98635008d068..9725e64def6a 100644 --- a/tests/codegen/enum/enum-match.rs +++ b/tests/codegen/enum/enum-match.rs @@ -471,3 +471,310 @@ pub fn match5(e: HugeVariantIndex) -> u8 { Possible259 => 100, } } + +// Make an enum where the niche tags wrap both as signed and as unsigned, to hit +// the most-fallback case where there's just nothing smart to do. + +pub enum E10Through65 { + D10 = 10, + D11 = 11, + D12 = 12, + D13 = 13, + D14 = 14, + D15 = 15, + D16 = 16, + D17 = 17, + D18 = 18, + D19 = 19, + D20 = 20, + D21 = 21, + D22 = 22, + D23 = 23, + D24 = 24, + D25 = 25, + D26 = 26, + D27 = 27, + D28 = 28, + D29 = 29, + D30 = 30, + D31 = 31, + D32 = 32, + D33 = 33, + D34 = 34, + D35 = 35, + D36 = 36, + D37 = 37, + D38 = 38, + D39 = 39, + D40 = 40, + D41 = 41, + D42 = 42, + D43 = 43, + D44 = 44, + D45 = 45, + D46 = 46, + D47 = 47, + D48 = 48, + D49 = 49, + D50 = 50, + D51 = 51, + D52 = 52, + D53 = 53, + D54 = 54, + D55 = 55, + D56 = 56, + D57 = 57, + D58 = 58, + D59 = 59, + D60 = 60, + D61 = 61, + D62 = 62, + D63 = 63, + D64 = 64, + D65 = 65, +} + +pub enum Tricky { + Untagged(E10Through65), + V001, + V002, + V003, + V004, + V005, + V006, + V007, + V008, + V009, + V010, + V011, + V012, + V013, + V014, + V015, + V016, + V017, + V018, + V019, + V020, + V021, + V022, + V023, + V024, + V025, + V026, + V027, + V028, + V029, + V030, + V031, + V032, + V033, + V034, + V035, + V036, + V037, + V038, + V039, + V040, + V041, + V042, + V043, + V044, + V045, + V046, + V047, + V048, + V049, + V050, + V051, + V052, + V053, + V054, + V055, + V056, + V057, + V058, + V059, + V060, + V061, + V062, + V063, + V064, + V065, + V066, + V067, + V068, + V069, + V070, + V071, + V072, + V073, + V074, + V075, + V076, + V077, + V078, + V079, + V080, + V081, + V082, + V083, + V084, + V085, + V086, + V087, + V088, + V089, + V090, + V091, + V092, + V093, + V094, + V095, + V096, + V097, + V098, + V099, + V100, + V101, + V102, + V103, + V104, + V105, + V106, + V107, + V108, + V109, + V110, + V111, + V112, + V113, + V114, + V115, + V116, + V117, + V118, + V119, + V120, + V121, + V122, + V123, + V124, + V125, + V126, + V127, + V128, + V129, + V130, + V131, + V132, + V133, + V134, + V135, + V136, + V137, + V138, + V139, + V140, + V141, + V142, + V143, + V144, + V145, + V146, + V147, + V148, + V149, + V150, + V151, + V152, + V153, + V154, + V155, + V156, + V157, + V158, + V159, + V160, + V161, + V162, + V163, + V164, + V165, + V166, + V167, + V168, + V169, + V170, + V171, + V172, + V173, + V174, + V175, + V176, + V177, + V178, + V179, + V180, + V181, + V182, + V183, + V184, + V185, + V186, + V187, + V188, + V189, + V190, + V191, + V192, + V193, + V194, + V195, + V196, + V197, + V198, + V199, + V200, +} + +const _: () = assert!(std::intrinsics::discriminant_value(&Tricky::V100) == 100); + +// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @discriminant6(i8 noundef %e) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %e, -66 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], -56 +// CHECK-NEXT: %[[TAGGED_DISCR:.+]] = add i8 %e, -65 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[TAGGED_DISCR]], i8 0 +// CHECK-NEXT: ret i8 %[[DISCR]] +#[no_mangle] +pub fn discriminant6(e: Tricky) -> u8 { + std::intrinsics::discriminant_value(&e) as _ +} + +// Case from , +// where sign-extension is important. + +pub enum OpenResult { + Ok(()), + Err(()), + TransportErr(TransportErr), +} + +#[repr(i32)] +pub enum TransportErr { + UnknownMethod = -2, +} + +#[no_mangle] +pub fn match7(result: OpenResult) -> u8 { + // CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match7(i32{{.+}}%result) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[NOT_OK:.+]] = icmp ne i32 %result, -1 + // CHECK-NEXT: %[[RET:.+]] = zext i1 %[[NOT_OK]] to i8 + // CHECK-NEXT: ret i8 %[[RET]] + match result { + OpenResult::Ok(()) => 0, + _ => 1, + } +} From 28af50075724bd1fa94b7e147b1e230534a70ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 11 Jul 2025 15:20:03 +0200 Subject: [PATCH 104/363] Opaque type collection: Guard against endlessly recursing free alias types --- compiler/rustc_ty_utils/src/opaque_types.rs | 11 +++++++---- .../opaq-ty-collection-infinite-recur.rs | 18 ++++++++++++++++++ .../opaq-ty-collection-infinite-recur.stderr | 11 +++++++++++ 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs create mode 100644 tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 3b313edea6f4..4a7263d0ccd2 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -223,7 +223,10 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { } // Skips type aliases, as they are meant to be transparent. // FIXME(type_alias_impl_trait): can we require mentioning nested type aliases explicitly? - ty::Alias(ty::Free, alias_ty) if alias_ty.def_id.is_local() => { + ty::Alias(ty::Free, alias_ty) if let Some(def_id) = alias_ty.def_id.as_local() => { + if !self.seen.insert(def_id) { + return; + } self.tcx .type_of(alias_ty.def_id) .instantiate(self.tcx, alias_ty.args) @@ -256,16 +259,16 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { return; } - let impl_args = alias_ty.args.rebase_onto( + let alias_args = alias_ty.args.rebase_onto( self.tcx, impl_trait_ref.def_id, ty::GenericArgs::identity_for_item(self.tcx, parent), ); - if self.tcx.check_args_compatible(assoc.def_id, impl_args) { + if self.tcx.check_args_compatible(assoc.def_id, alias_args) { self.tcx .type_of(assoc.def_id) - .instantiate(self.tcx, impl_args) + .instantiate(self.tcx, alias_args) .visit_with(self); return; } else { diff --git a/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs new file mode 100644 index 000000000000..34803c8c1034 --- /dev/null +++ b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs @@ -0,0 +1,18 @@ +// The opaque type collector used to expand free alias types (in situ) without guarding against +// endlessly recursing aliases which lead to the compiler overflowing its stack in certain +// situations. +// +// In most situations we wouldn't even reach the collector when there's an overflow because we +// would've already bailed out early during the item's wfcheck due to the normalization failure. +// +// In the case below however, while collecting the opaque types defined by the AnonConst, we +// descend into its nested items (here: type alias `Recur`) to acquire their opaque types -- +// meaning we get there before we wfcheck `Recur`. +// +// issue: +#![feature(lazy_type_alias)] +#![expect(incomplete_features)] + +struct Hold([(); { type Recur = Recur; 0 }]); //~ ERROR overflow normalizing the type alias `Recur` + +fn main() {} diff --git a/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr new file mode 100644 index 000000000000..e93fcd03a966 --- /dev/null +++ b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr @@ -0,0 +1,11 @@ +error[E0275]: overflow normalizing the type alias `Recur` + --> $DIR/opaq-ty-collection-infinite-recur.rs:16:20 + | +LL | struct Hold([(); { type Recur = Recur; 0 }]); + | ^^^^^^^^^^ + | + = note: in case this is a recursive type alias, consider using a struct, enum, or union instead + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. From cfb66e5e88a4f5333b328df0b6363ded674f92b4 Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 05:53:40 -0400 Subject: [PATCH 105/363] Consolidate infinity tests --- library/coretests/tests/floats/f128.rs | 12 ------------ library/coretests/tests/floats/f16.rs | 12 ------------ library/coretests/tests/floats/f32.rs | 12 ------------ library/coretests/tests/floats/f64.rs | 12 ------------ library/coretests/tests/floats/mod.rs | 18 ++++++++++++++++++ 5 files changed, 18 insertions(+), 48 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 38df09a91c10..1b7ac82c1e9c 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -55,18 +55,6 @@ fn test_num_f128() { // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_infinity() { - let inf: f128 = f128::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - #[test] fn test_neg_infinity() { let neg_inf: f128 = f128::NEG_INFINITY; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index f6749d796cca..e69fe4d70bc7 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -51,18 +51,6 @@ fn test_num_f16() { // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_infinity() { - let inf: f16 = f16::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - #[test] fn test_neg_infinity() { let neg_inf: f16 = f16::NEG_INFINITY; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index f5d5723fea45..1efa8b3fdd5e 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -35,18 +35,6 @@ fn test_num_f32() { super::test_num(10f32, 2f32); } -#[test] -fn test_infinity() { - let inf: f32 = f32::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - #[test] fn test_neg_infinity() { let neg_inf: f32 = f32::NEG_INFINITY; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 34af87c241e9..9771abd2fe31 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -30,18 +30,6 @@ fn test_num_f64() { super::test_num(10f64, 2f64); } -#[test] -fn test_infinity() { - let inf: f64 = f64::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - #[test] fn test_neg_infinity() { let neg_inf: f64 = f64::NEG_INFINITY; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 36743a7d6df9..9fe74090f158 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -273,6 +273,24 @@ float_test! { } } +float_test! { + name: infinity, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let inf: Float = Float::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert!(matches!(inf.classify(), Fp::Infinite)); + } +} + float_test! { name: min, attrs: { From c5e67b48ef0b073c07a57557d0dd205c099fc56e Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:20:28 -0400 Subject: [PATCH 106/363] Consolidate test_num tests --- library/coretests/tests/floats/f128.rs | 15 -------- library/coretests/tests/floats/f16.rs | 5 --- library/coretests/tests/floats/f32.rs | 5 --- library/coretests/tests/floats/f64.rs | 5 --- library/coretests/tests/floats/mod.rs | 53 ++++++++++++++++---------- library/coretests/tests/lib.rs | 1 + 6 files changed, 34 insertions(+), 50 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 1b7ac82c1e9c..508d30963a55 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -1,7 +1,6 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy #![cfg(target_has_reliable_f128)] -use core::ops::{Add, Div, Mul, Sub}; use std::f128::consts; use std::num::FpCategory as Fp; @@ -38,20 +37,6 @@ const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa; /// Second pattern over the mantissa const NAN_MASK2: u128 = 0x00005555555555555555555555555555; -#[test] -fn test_num_f128() { - // FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128` - // function is available on all platforms. - let ten = 10f128; - let two = 2f128; - assert_biteq!(ten.add(two), ten + two); - assert_biteq!(ten.sub(two), ten - two); - assert_biteq!(ten.mul(two), ten * two); - assert_biteq!(ten.div(two), ten / two); - #[cfg(any(miri, target_has_reliable_f128_math))] - assert_biteq!(core::ops::Rem::rem(ten, two), ten % two); -} - // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index e69fe4d70bc7..426411f67372 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -43,11 +43,6 @@ const NAN_MASK1: u16 = 0x02aa; /// Second pattern over the mantissa const NAN_MASK2: u16 = 0x0155; -#[test] -fn test_num_f16() { - super::test_num(10f16, 2f16); -} - // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 1efa8b3fdd5e..4fe21975d41f 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,11 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_num_f32() { - super::test_num(10f32, 2f32); -} - #[test] fn test_neg_infinity() { let neg_inf: f32 = f32::NEG_INFINITY; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 9771abd2fe31..7016f3643c88 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,11 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_num_f64() { - super::test_num(10f64, 2f64); -} - #[test] fn test_neg_infinity() { let neg_inf: f64 = f64::NEG_INFINITY; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 9fe74090f158..a746e4bf40d3 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1,4 +1,3 @@ -use std::fmt; use std::num::FpCategory as Fp; use std::ops::{Add, Div, Mul, Rem, Sub}; @@ -190,6 +189,8 @@ macro_rules! float_test { use super::Approx; #[allow(unused)] use std::num::FpCategory as Fp; + #[allow(unused)] + use std::ops::{Add, Div, Mul, Rem, Sub}; // Shadow the runtime versions of the macro with const-compatible versions. #[allow(unused)] use $crate::floats::{ @@ -229,30 +230,42 @@ macro_rules! float_test { }; } -/// Helper function for testing numeric operations -pub fn test_num(ten: T, two: T) -where - T: PartialEq - + Add - + Sub - + Mul - + Div - + Rem - + fmt::Debug - + Copy, -{ - assert_eq!(ten.add(two), ten + two); - assert_eq!(ten.sub(two), ten - two); - assert_eq!(ten.mul(two), ten * two); - assert_eq!(ten.div(two), ten / two); - assert_eq!(ten.rem(two), ten % two); -} - mod f128; mod f16; mod f32; mod f64; +float_test! { + name: num, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let two: Float = 2.0; + let ten: Float = 10.0; + assert_biteq!(ten.add(two), ten + two); + assert_biteq!(ten.sub(two), ten - two); + assert_biteq!(ten.mul(two), ten * two); + assert_biteq!(ten.div(two), ten / two); + } +} + +// FIXME(f16_f128): merge into `num` once the required `fmodl`/`fmodf128` function is available on +// all platforms. +float_test! { + name: num_rem, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + let two: Float = 2.0; + let ten: Float = 10.0; + assert_biteq!(ten.rem(two), ten % two); + } +} + float_test! { name: nan, attrs: { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index fdef736c0c0f..e2249bd7f6a1 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(const_destruct)] #![feature(const_eval_select)] #![feature(const_float_round_methods)] +#![feature(const_ops)] #![feature(const_ref_cell)] #![feature(const_trait_impl)] #![feature(core_float_math)] From c2e6b39474beacf2be7313326f0a06e3d7f85f04 Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:10:39 -0400 Subject: [PATCH 107/363] Consolidate neg_infinity tests --- library/coretests/tests/floats/f128.rs | 12 ------------ library/coretests/tests/floats/f16.rs | 12 ------------ library/coretests/tests/floats/f32.rs | 12 ------------ library/coretests/tests/floats/f64.rs | 12 ------------ library/coretests/tests/floats/mod.rs | 18 ++++++++++++++++++ 5 files changed, 18 insertions(+), 48 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 508d30963a55..db6441df32bc 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,18 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_neg_infinity() { - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - #[test] fn test_zero() { let zero: f128 = 0.0f128; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 426411f67372..051737c34c31 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,18 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_neg_infinity() { - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - #[test] fn test_zero() { let zero: f16 = 0.0f16; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 4fe21975d41f..0cf9ef042a0d 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,18 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_neg_infinity() { - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - #[test] fn test_zero() { let zero: f32 = 0.0f32; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 7016f3643c88..1e995d77e3c8 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,18 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_neg_infinity() { - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - #[test] fn test_zero() { let zero: f64 = 0.0f64; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index a746e4bf40d3..ed30aae44115 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -304,6 +304,24 @@ float_test! { } } +float_test! { + name: neg_infinity, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let neg_inf: Float = Float::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert!(matches!(neg_inf.classify(), Fp::Infinite)); + } +} + float_test! { name: min, attrs: { From 0c01322ec6578644108fb66b279f18f3d5382368 Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:26:39 -0400 Subject: [PATCH 108/363] Consolidate zero tests --- library/coretests/tests/floats/f128.rs | 13 ------------- library/coretests/tests/floats/f16.rs | 13 ------------- library/coretests/tests/floats/f32.rs | 13 ------------- library/coretests/tests/floats/f64.rs | 13 ------------- library/coretests/tests/floats/mod.rs | 19 +++++++++++++++++++ 5 files changed, 19 insertions(+), 52 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index db6441df32bc..85e9bfef125b 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,19 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_zero() { - let zero: f128 = 0.0f128; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - #[test] fn test_neg_zero() { let neg_zero: f128 = -0.0; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 051737c34c31..fced642eb132 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,19 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_zero() { - let zero: f16 = 0.0f16; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - #[test] fn test_neg_zero() { let neg_zero: f16 = -0.0; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 0cf9ef042a0d..23e98a9589c0 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,19 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_zero() { - let zero: f32 = 0.0f32; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - #[test] fn test_neg_zero() { let neg_zero: f32 = -0.0; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 1e995d77e3c8..739ff8a7aa7b 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,19 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_zero() { - let zero: f64 = 0.0f64; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - #[test] fn test_neg_zero() { let neg_zero: f64 = -0.0; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index ed30aae44115..75dbe4a9d6db 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -322,6 +322,25 @@ float_test! { } } +float_test! { + name: zero, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let zero: Float = 0.0; + assert_biteq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert!(matches!(zero.classify(), Fp::Zero)); + } +} + float_test! { name: min, attrs: { From fc01eed02444e412761ac1b5b723d45f443800fb Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:31:29 -0400 Subject: [PATCH 109/363] Consolidate negative zero tests --- library/coretests/tests/floats/f128.rs | 14 -------------- library/coretests/tests/floats/f16.rs | 14 -------------- library/coretests/tests/floats/f32.rs | 14 -------------- library/coretests/tests/floats/f64.rs | 14 -------------- library/coretests/tests/floats/mod.rs | 20 ++++++++++++++++++++ 5 files changed, 20 insertions(+), 56 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 85e9bfef125b..dbf4d6df6365 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,20 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_neg_zero() { - let neg_zero: f128 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - #[test] fn test_one() { let one: f128 = 1.0f128; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index fced642eb132..15ab57f8e7ee 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,20 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_neg_zero() { - let neg_zero: f16 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - #[test] fn test_one() { let one: f16 = 1.0f16; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 23e98a9589c0..935bfa8b2734 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,20 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_neg_zero() { - let neg_zero: f32 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - #[test] fn test_one() { let one: f32 = 1.0f32; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 739ff8a7aa7b..d3637dfd9d67 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,20 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_neg_zero() { - let neg_zero: f64 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - #[test] fn test_one() { let one: f64 = 1.0f64; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 75dbe4a9d6db..006f51488dde 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -341,6 +341,26 @@ float_test! { } } +float_test! { + name: neg_zero, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let neg_zero: Float = -0.0; + assert!(0.0 == neg_zero); + assert_biteq!(-0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert!(matches!(neg_zero.classify(), Fp::Zero)); + } +} + float_test! { name: min, attrs: { From 868020e0594969356d1c41831c84fe68f7b514f0 Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:40:10 -0400 Subject: [PATCH 110/363] Consolidate one tests --- library/coretests/tests/floats/f128.rs | 13 ------------- library/coretests/tests/floats/f16.rs | 13 ------------- library/coretests/tests/floats/f32.rs | 13 ------------- library/coretests/tests/floats/f64.rs | 13 ------------- library/coretests/tests/floats/mod.rs | 19 +++++++++++++++++++ 5 files changed, 19 insertions(+), 52 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index dbf4d6df6365..289752673fe7 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,19 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_one() { - let one: f128 = 1.0f128; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - #[test] fn test_is_nan() { let nan: f128 = f128::NAN; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 15ab57f8e7ee..3435630a4ffd 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,19 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_one() { - let one: f16 = 1.0f16; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - #[test] fn test_is_nan() { let nan: f16 = f16::NAN; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 935bfa8b2734..5b1151aca9fe 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,19 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_one() { - let one: f32 = 1.0f32; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - #[test] fn test_is_nan() { let nan: f32 = f32::NAN; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index d3637dfd9d67..7473fc07dbeb 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,19 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_one() { - let one: f64 = 1.0f64; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - #[test] fn test_is_nan() { let nan: f64 = f64::NAN; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 006f51488dde..abe827b69885 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -361,6 +361,25 @@ float_test! { } } +float_test! { + name: one, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let one: Float = 1.0; + assert_biteq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert!(matches!(one.classify(), Fp::Normal)); + } +} + float_test! { name: min, attrs: { From 1b8904c0c59a1790f38d2ddc05f4c3416030e07e Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:42:48 -0400 Subject: [PATCH 111/363] Consolidate is_nan --- library/coretests/tests/floats/f128.rs | 13 ------------- library/coretests/tests/floats/f16.rs | 13 ------------- library/coretests/tests/floats/f32.rs | 13 ------------- library/coretests/tests/floats/f64.rs | 13 ------------- library/coretests/tests/floats/mod.rs | 22 ++++++++++++++++++++++ 5 files changed, 22 insertions(+), 52 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 289752673fe7..6a987494a6a4 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,19 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_nan() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f128.is_nan()); - assert!(!5.3f128.is_nan()); - assert!(!(-10.732f128).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - #[test] fn test_is_infinite() { let nan: f128 = f128::NAN; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 3435630a4ffd..dec371a7de94 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,19 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_nan() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f16.is_nan()); - assert!(!5.3f16.is_nan()); - assert!(!(-10.732f16).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - #[test] fn test_is_infinite() { let nan: f16 = f16::NAN; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 5b1151aca9fe..5ca6a633a97b 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,19 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_is_nan() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f32.is_nan()); - assert!(!5.3f32.is_nan()); - assert!(!(-10.732f32).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - #[test] fn test_is_infinite() { let nan: f32 = f32::NAN; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 7473fc07dbeb..6dd18b25527f 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,19 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_is_nan() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f64.is_nan()); - assert!(!5.3f64.is_nan()); - assert!(!(-10.732f64).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - #[test] fn test_is_infinite() { let nan: f64 = f64::NAN; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index abe827b69885..613557975a20 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -380,6 +380,28 @@ float_test! { } } +float_test! { + name: is_nan, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 5.3; + let neg: Float = -10.732; + assert!(nan.is_nan()); + assert!(!zero.is_nan()); + assert!(!pos.is_nan()); + assert!(!neg.is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); + } +} + float_test! { name: min, attrs: { From e3d83679cb1a921fd50ee70dee15e57c6529abed Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:49:48 -0400 Subject: [PATCH 112/363] Consolidate is_infinite tests --- library/coretests/tests/floats/f128.rs | 13 ------------- library/coretests/tests/floats/f16.rs | 13 ------------- library/coretests/tests/floats/f32.rs | 13 ------------- library/coretests/tests/floats/f64.rs | 13 ------------- library/coretests/tests/floats/mod.rs | 22 ++++++++++++++++++++++ 5 files changed, 22 insertions(+), 52 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 6a987494a6a4..7ed17731a81a 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,19 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_infinite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f128.is_infinite()); - assert!(!42.8f128.is_infinite()); - assert!(!(-109.2f128).is_infinite()); -} - #[test] fn test_is_finite() { let nan: f128 = f128::NAN; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index dec371a7de94..ac972200c3d2 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,19 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_infinite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f16.is_infinite()); - assert!(!42.8f16.is_infinite()); - assert!(!(-109.2f16).is_infinite()); -} - #[test] fn test_is_finite() { let nan: f16 = f16::NAN; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 5ca6a633a97b..d6a34ba2ac62 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,19 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_is_infinite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f32.is_infinite()); - assert!(!42.8f32.is_infinite()); - assert!(!(-109.2f32).is_infinite()); -} - #[test] fn test_is_finite() { let nan: f32 = f32::NAN; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 6dd18b25527f..cb3c57140e9e 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,19 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_is_infinite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f64.is_infinite()); - assert!(!42.8f64.is_infinite()); - assert!(!(-109.2f64).is_infinite()); -} - #[test] fn test_is_finite() { let nan: f64 = f64::NAN; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 613557975a20..3f6fe91d36e8 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -402,6 +402,28 @@ float_test! { } } +float_test! { + name: is_infinite, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 42.8; + let neg: Float = -109.2; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!zero.is_infinite()); + assert!(!pos.is_infinite()); + assert!(!neg.is_infinite()); + } +} + float_test! { name: min, attrs: { From 7dd2811b2af5beb2962d58d2f9f9b78e815a2576 Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:53:48 -0400 Subject: [PATCH 113/363] Consolidate is_finite tests --- library/coretests/tests/floats/f128.rs | 13 ------------- library/coretests/tests/floats/f16.rs | 13 ------------- library/coretests/tests/floats/f32.rs | 13 ------------- library/coretests/tests/floats/f64.rs | 13 ------------- library/coretests/tests/floats/mod.rs | 22 ++++++++++++++++++++++ 5 files changed, 22 insertions(+), 52 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 7ed17731a81a..160fe0380a73 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,19 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_finite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f128.is_finite()); - assert!(42.8f128.is_finite()); - assert!((-109.2f128).is_finite()); -} - #[test] fn test_is_normal() { let nan: f128 = f128::NAN; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index ac972200c3d2..1b62278a9a33 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,19 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_finite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f16.is_finite()); - assert!(42.8f16.is_finite()); - assert!((-109.2f16).is_finite()); -} - #[test] fn test_is_normal() { let nan: f16 = f16::NAN; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index d6a34ba2ac62..0aa95235fdec 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,19 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_is_finite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f32.is_finite()); - assert!(42.8f32.is_finite()); - assert!((-109.2f32).is_finite()); -} - #[test] fn test_is_normal() { let nan: f32 = f32::NAN; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index cb3c57140e9e..9f30afb1fe1a 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,19 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_is_finite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f64.is_finite()); - assert!(42.8f64.is_finite()); - assert!((-109.2f64).is_finite()); -} - #[test] fn test_is_normal() { let nan: f64 = f64::NAN; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 3f6fe91d36e8..b8ec82f75b8a 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -424,6 +424,28 @@ float_test! { } } +float_test! { + name: is_finite, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 42.8; + let neg: Float = -109.2; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(zero.is_finite()); + assert!(pos.is_finite()); + assert!(neg.is_finite()); + } +} + float_test! { name: min, attrs: { From d2c1900086a057359bf6ae0f8a5b8f658fbc8bce Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:20:45 -0400 Subject: [PATCH 114/363] Consolidate is_normal tests --- library/coretests/tests/floats/f128.rs | 17 ------- library/coretests/tests/floats/f16.rs | 17 ------- library/coretests/tests/floats/f32.rs | 17 ------- library/coretests/tests/floats/f64.rs | 17 ------- library/coretests/tests/floats/mod.rs | 65 ++++++++++++++++++++------ 5 files changed, 51 insertions(+), 82 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 160fe0380a73..b741906a6e9e 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,23 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_normal() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f128.is_normal()); - assert!(1e-4931f128.is_normal()); - assert!(!1e-4932f128.is_normal()); -} - #[test] fn test_classify() { let nan: f128 = f128::NAN; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 1b62278a9a33..da6414fc2444 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,23 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_normal() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f16.is_normal()); - assert!(1e-4f16.is_normal()); - assert!(!1e-5f16.is_normal()); -} - #[test] fn test_classify() { let nan: f16 = f16::NAN; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 0aa95235fdec..3464930b72f7 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,23 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_is_normal() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f32.is_normal()); - assert!(1e-37f32.is_normal()); - assert!(!1e-38f32.is_normal()); -} - #[test] fn test_classify() { let nan: f32 = f32::NAN; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 9f30afb1fe1a..917dae1b6c66 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,23 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_is_normal() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f64.is_normal()); - assert!(1e-307f64.is_normal()); - assert!(!1e-308f64.is_normal()); -} - #[test] fn test_classify() { let nan: f64 = f64::NAN; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index b8ec82f75b8a..b1686514a122 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1,27 +1,40 @@ use std::num::FpCategory as Fp; use std::ops::{Add, Div, Mul, Rem, Sub}; -/// Set the default tolerance for float comparison based on the type. -trait Approx { - const LIM: Self; +trait TestableFloat { + /// Set the default tolerance for float comparison based on the type. + const APPROX: Self; + const MIN_POSITIVE_NORMAL: Self; + const MAX_SUBNORMAL: Self; } -impl Approx for f16 { - const LIM: Self = 1e-3; +impl TestableFloat for f16 { + const APPROX: Self = 1e-3; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f32 { - const LIM: Self = 1e-6; + +impl TestableFloat for f32 { + const APPROX: Self = 1e-6; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f64 { - const LIM: Self = 1e-6; + +impl TestableFloat for f64 { + const APPROX: Self = 1e-6; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f128 { - const LIM: Self = 1e-9; + +impl TestableFloat for f128 { + const APPROX: Self = 1e-9; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } /// Determine the tolerance for values of the argument type. -const fn lim_for_ty(_x: T) -> T { - T::LIM +const fn lim_for_ty(_x: T) -> T { + T::APPROX } // We have runtime ("rt") and const versions of these macros. @@ -186,7 +199,7 @@ macro_rules! float_test { $( $( #[$const_meta] )+ )? mod const_ { #[allow(unused)] - use super::Approx; + use super::TestableFloat; #[allow(unused)] use std::num::FpCategory as Fp; #[allow(unused)] @@ -446,6 +459,30 @@ float_test! { } } +float_test! { + name: is_normal, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let neg_zero: Float = -0.0; + let one : Float = 1.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(one.is_normal()); + assert!(Float::MIN_POSITIVE_NORMAL.is_normal()); + assert!(!Float::MAX_SUBNORMAL.is_normal()); + } +} + float_test! { name: min, attrs: { From 79769f2d5babdfc8ca0c88045fdedcf312a3d83d Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 12:08:14 -0400 Subject: [PATCH 115/363] Consolidate classify tests --- library/coretests/tests/floats/f128.rs | 18 ------------------ library/coretests/tests/floats/f16.rs | 18 ------------------ library/coretests/tests/floats/f32.rs | 18 ------------------ library/coretests/tests/floats/f64.rs | 17 ----------------- library/coretests/tests/floats/mod.rs | 23 +++++++++++++++++++++++ 5 files changed, 23 insertions(+), 71 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index b741906a6e9e..36d6a20a9442 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -2,7 +2,6 @@ #![cfg(target_has_reliable_f128)] use std::f128::consts; -use std::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -40,23 +39,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_classify() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f128.classify(), Fp::Normal); - assert_eq!(1e-4931f128.classify(), Fp::Normal); - assert_eq!(1e-4932f128.classify(), Fp::Subnormal); -} - #[test] #[cfg(any(miri, target_has_reliable_f128_math))] fn test_abs() { diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index da6414fc2444..351c008a37ba 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -2,7 +2,6 @@ #![cfg(target_has_reliable_f16)] use std::f16::consts; -use std::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -46,23 +45,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_classify() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f16.classify(), Fp::Normal); - assert_eq!(1e-4f16.classify(), Fp::Normal); - assert_eq!(1e-5f16.classify(), Fp::Subnormal); -} - #[test] #[cfg(any(miri, target_has_reliable_f16_math))] fn test_abs() { diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 3464930b72f7..267b0e4e2943 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -1,6 +1,5 @@ use core::f32; use core::f32::consts; -use core::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -30,23 +29,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_classify() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f32.classify(), Fp::Normal); - assert_eq!(1e-37f32.classify(), Fp::Normal); - assert_eq!(1e-38f32.classify(), Fp::Subnormal); -} - #[test] fn test_abs() { assert_biteq!(f32::INFINITY.abs(), f32::INFINITY); diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 917dae1b6c66..735b7a765151 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -1,6 +1,5 @@ use core::f64; use core::f64::consts; -use core::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -25,22 +24,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_classify() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1e-307f64.classify(), Fp::Normal); - assert_eq!(1e-308f64.classify(), Fp::Subnormal); -} - #[test] fn test_abs() { assert_biteq!(f64::INFINITY.abs(), f64::INFINITY); diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index b1686514a122..43431bba6954 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -483,6 +483,29 @@ float_test! { } } +float_test! { + name: classify, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let neg_zero: Float = -0.0; + let one: Float = 1.0; + assert!(matches!(nan.classify(), Fp::Nan)); + assert!(matches!(inf.classify(), Fp::Infinite)); + assert!(matches!(neg_inf.classify(), Fp::Infinite)); + assert!(matches!(zero.classify(), Fp::Zero)); + assert!(matches!(neg_zero.classify(), Fp::Zero)); + assert!(matches!(one.classify(), Fp::Normal)); + assert!(matches!(Float::MIN_POSITIVE_NORMAL.classify(), Fp::Normal)); + assert!(matches!(Float::MAX_SUBNORMAL.classify(), Fp::Subnormal)); + } +} + float_test! { name: min, attrs: { From 7803c25deaa3f330a952a18c7c3d5ea3850e9ff7 Mon Sep 17 00:00:00 2001 From: lolbinarycat Date: Fri, 11 Jul 2025 13:39:39 -0500 Subject: [PATCH 116/363] directives.md: build-aux-docs does not work with aux-crate --- src/doc/rustc-dev-guide/src/tests/directives.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 839076b809df..63aa08c389cc 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -59,7 +59,7 @@ not be exhaustive. Directives can generally be found by browsing the | `aux-crate` | Like `aux-build` but makes available as extern prelude | All except `run-make` | `=` | | `aux-codegen-backend` | Similar to `aux-build` but pass the compiled dylib to `-Zcodegen-backend` when building the main file | `ui-fulldeps` | Path to codegen backend file | | `proc-macro` | Similar to `aux-build`, but for aux forces host and don't use `-Cprefer-dynamic`[^pm]. | All except `run-make` | Path to auxiliary proc-macro `.rs` file | -| `build-aux-docs` | Build docs for auxiliaries as well | All except `run-make` | N/A | +| `build-aux-docs` | Build docs for auxiliaries as well. Note that this only works with `aux-build`, not `aux-crate`. | All except `run-make` | N/A | [^pm]: please see the Auxiliary proc-macro section in the [compiletest](./compiletest.md) chapter for specifics. From 5d7db7e16ec5af85c39138dd7c669bc2219d1507 Mon Sep 17 00:00:00 2001 From: nazo6 Date: Sat, 12 Jul 2025 10:59:19 +0900 Subject: [PATCH 117/363] Fixed a core crate compilation failure when enabling the `optimize_for_size` feature on some targets --- library/core/src/fmt/num.rs | 8 ++++---- library/core/src/lib.rs | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index e1381ace4415..7d41ae45093e 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -358,7 +358,7 @@ macro_rules! impl_Display { } #[cfg(feature = "optimize_for_size")] { - offset = _inner_slow_integer_to_str(self.unsigned_abs().$conv_fn(), &mut buf.buf); + offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.unsigned_abs().$conv_fn(), &mut buf.buf); } // Only difference between signed and unsigned are these 4 lines. if self < 0 { @@ -401,7 +401,7 @@ macro_rules! impl_Display { } #[cfg(feature = "optimize_for_size")] { - offset = _inner_slow_integer_to_str(self.$conv_fn(), &mut buf.buf); + offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.$conv_fn(), &mut buf.buf); } // SAFETY: Starting from `offset`, all elements of the slice have been set. unsafe { slice_buffer_to_str(&buf.buf, offset) } @@ -412,7 +412,7 @@ macro_rules! impl_Display { )* #[cfg(feature = "optimize_for_size")] - fn _inner_slow_integer_to_str(mut n: $u, buf: &mut [MaybeUninit::]) -> usize { + fn ${concat(_inner_slow_integer_to_str, $gen_name)}(mut n: $u, buf: &mut [MaybeUninit::]) -> usize { let mut curr = buf.len(); // SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning @@ -437,7 +437,7 @@ macro_rules! impl_Display { const MAX_DEC_N: usize = $u::MAX.ilog(10) as usize + 1; let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; - let offset = _inner_slow_integer_to_str(n, &mut buf); + let offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(n, &mut buf); // SAFETY: Starting from `offset`, all elements of the slice have been set. let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) }; f.pad_integral(is_nonnegative, "", buf_slice) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 2f701171505c..e08edde3b38b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -160,6 +160,7 @@ #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(macro_metavar_expr)] +#![feature(macro_metavar_expr_concat)] #![feature(marker_trait_attr)] #![feature(min_specialization)] #![feature(multiple_supertrait_upcastable)] From bccc32bf791d7a0f5ccb0f345223548b9ae98844 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Jul 2025 08:55:17 +0200 Subject: [PATCH 118/363] readme: update strict provenance link --- src/tools/miri/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index b05acff72b50..7816ce1ac561 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -342,9 +342,9 @@ environment variable. We first document the most relevant and most commonly used is enabled (the default), this is also used to emulate system entropy. The default seed is 0. You can increase test coverage by running Miri multiple times with different seeds. * `-Zmiri-strict-provenance` enables [strict - provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that - casting an integer to a pointer will stop execution because the provenance of the pointer - cannot be determined. + provenance](https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) checking in + Miri. This means that casting an integer to a pointer will stop execution because the provenance + of the pointer cannot be determined. * `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a program passes the alignment check by pure chance, because things From d5bcfb334b616e01c3589ba7b1697c7ebc47a024 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 11 Jul 2025 05:07:37 -0700 Subject: [PATCH 119/363] Simplify codegen for niche-encoded variant tests --- compiler/rustc_abi/src/lib.rs | 35 ++++++++- compiler/rustc_codegen_ssa/src/mir/operand.rs | 77 ++++++++++++------- tests/codegen/enum/enum-discriminant-eq.rs | 42 ++++------ tests/codegen/enum/enum-match.rs | 19 +++-- 4 files changed, 110 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index de4b5a46c81a..5bd73502d980 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -43,7 +43,7 @@ use std::fmt; #[cfg(feature = "nightly")] use std::iter::Step; use std::num::{NonZeroUsize, ParseIntError}; -use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub}; +use std::ops::{Add, AddAssign, Deref, Mul, RangeFull, RangeInclusive, Sub}; use std::str::FromStr; use bitflags::bitflags; @@ -1391,12 +1391,45 @@ impl WrappingRange { } /// Returns `true` if `size` completely fills the range. + /// + /// Note that this is *not* the same as `self == WrappingRange::full(size)`. + /// Niche calculations can produce full ranges which are not the canonical one; + /// for example `Option>` gets `valid_range: (..=0) | (1..)`. #[inline] fn is_full_for(&self, size: Size) -> bool { let max_value = size.unsigned_int_max(); debug_assert!(self.start <= max_value && self.end <= max_value); self.start == (self.end.wrapping_add(1) & max_value) } + + /// Checks whether this range is considered non-wrapping when the values are + /// interpreted as *unsigned* numbers of width `size`. + /// + /// Returns `Ok(true)` if there's no wrap-around, `Ok(false)` if there is, + /// and `Err(..)` if the range is full so it depends how you think about it. + #[inline] + pub fn no_unsigned_wraparound(&self, size: Size) -> Result { + if self.is_full_for(size) { Err(..) } else { Ok(self.start <= self.end) } + } + + /// Checks whether this range is considered non-wrapping when the values are + /// interpreted as *signed* numbers of width `size`. + /// + /// This is heavily dependent on the `size`, as `100..=200` does wrap when + /// interpreted as `i8`, but doesn't when interpreted as `i16`. + /// + /// Returns `Ok(true)` if there's no wrap-around, `Ok(false)` if there is, + /// and `Err(..)` if the range is full so it depends how you think about it. + #[inline] + pub fn no_signed_wraparound(&self, size: Size) -> Result { + if self.is_full_for(size) { + Err(..) + } else { + let start: i128 = size.sign_extend(self.start); + let end: i128 = size.sign_extend(self.end); + Ok(start <= end) + } + } } impl fmt::Debug for WrappingRange { diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index b0d191528a89..9910cb5469fc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -486,6 +486,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { // value and the variant index match, since that's all `Niche` can encode. let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); + let niche_start_const = bx.cx().const_uint_big(tag_llty, niche_start); // We have a subrange `niche_start..=niche_end` inside `range`. // If the value of the tag is inside this subrange, it's a @@ -511,35 +512,44 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { // } else { // untagged_variant // } - let niche_start = bx.cx().const_uint_big(tag_llty, niche_start); - let is_niche = bx.icmp(IntPredicate::IntEQ, tag, niche_start); + let is_niche = bx.icmp(IntPredicate::IntEQ, tag, niche_start_const); let tagged_discr = bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64); (is_niche, tagged_discr, 0) } else { // The special cases don't apply, so we'll have to go with // the general algorithm. - let relative_discr = bx.sub(tag, bx.cx().const_uint_big(tag_llty, niche_start)); - let cast_tag = bx.intcast(relative_discr, cast_to, false); - let is_niche = bx.icmp( - IntPredicate::IntULE, - relative_discr, - bx.cx().const_uint(tag_llty, relative_max as u64), - ); - // Thanks to parameter attributes and load metadata, LLVM already knows - // the general valid range of the tag. It's possible, though, for there - // to be an impossible value *in the middle*, which those ranges don't - // communicate, so it's worth an `assume` to let the optimizer know. - if niche_variants.contains(&untagged_variant) - && bx.cx().sess().opts.optimize != OptLevel::No - { - let impossible = - u64::from(untagged_variant.as_u32() - niche_variants.start().as_u32()); - let impossible = bx.cx().const_uint(tag_llty, impossible); - let ne = bx.icmp(IntPredicate::IntNE, relative_discr, impossible); - bx.assume(ne); - } + let tag_range = tag_scalar.valid_range(&dl); + let tag_size = tag_scalar.size(&dl); + let niche_end = u128::from(relative_max).wrapping_add(niche_start); + let niche_end = tag_size.truncate(niche_end); + + let relative_discr = bx.sub(tag, niche_start_const); + let cast_tag = bx.intcast(relative_discr, cast_to, false); + let is_niche = if tag_range.no_unsigned_wraparound(tag_size) == Ok(true) { + if niche_start == tag_range.start { + let niche_end_const = bx.cx().const_uint_big(tag_llty, niche_end); + bx.icmp(IntPredicate::IntULE, tag, niche_end_const) + } else { + assert_eq!(niche_end, tag_range.end); + bx.icmp(IntPredicate::IntUGE, tag, niche_start_const) + } + } else if tag_range.no_signed_wraparound(tag_size) == Ok(true) { + if niche_start == tag_range.start { + let niche_end_const = bx.cx().const_uint_big(tag_llty, niche_end); + bx.icmp(IntPredicate::IntSLE, tag, niche_end_const) + } else { + assert_eq!(niche_end, tag_range.end); + bx.icmp(IntPredicate::IntSGE, tag, niche_start_const) + } + } else { + bx.icmp( + IntPredicate::IntULE, + relative_discr, + bx.cx().const_uint(tag_llty, relative_max as u64), + ) + }; (is_niche, cast_tag, niche_variants.start().as_u32() as u128) }; @@ -550,11 +560,24 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { bx.add(tagged_discr, bx.cx().const_uint_big(cast_to, delta)) }; - let discr = bx.select( - is_niche, - tagged_discr, - bx.cx().const_uint(cast_to, untagged_variant.as_u32() as u64), - ); + let untagged_variant_const = + bx.cx().const_uint(cast_to, u64::from(untagged_variant.as_u32())); + + // Thanks to parameter attributes and load metadata, LLVM already knows + // the general valid range of the tag. It's possible, though, for there + // to be an impossible value *in the middle*, which those ranges don't + // communicate, so it's worth an `assume` to let the optimizer know. + // Most importantly, this means when optimizing a variant test like + // `SELECT(is_niche, complex, CONST) == CONST` it's ok to simplify that + // to `!is_niche` because the `complex` part can't possibly match. + if niche_variants.contains(&untagged_variant) + && bx.cx().sess().opts.optimize != OptLevel::No + { + let ne = bx.icmp(IntPredicate::IntNE, tagged_discr, untagged_variant_const); + bx.assume(ne); + } + + let discr = bx.select(is_niche, tagged_discr, untagged_variant_const); // In principle we could insert assumes on the possible range of `discr`, but // currently in LLVM this isn't worth it because the original `tag` will diff --git a/tests/codegen/enum/enum-discriminant-eq.rs b/tests/codegen/enum/enum-discriminant-eq.rs index fd6f3499cb1f..0494c5f551b3 100644 --- a/tests/codegen/enum/enum-discriminant-eq.rs +++ b/tests/codegen/enum/enum-discriminant-eq.rs @@ -89,13 +89,13 @@ pub fn mid_bool_eq_discr(a: Mid, b: Mid) -> bool { // CHECK-LABEL: @mid_bool_eq_discr( // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2 - // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3 + // CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i8 %a, 1 // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1 // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2 - // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3 + // CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i8 %b, 1 // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1 // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 @@ -109,13 +109,13 @@ pub fn mid_ord_eq_discr(a: Mid, b: Mid) -> bool { // CHECK-LABEL: @mid_ord_eq_discr( // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2 - // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3 + // CHECK: %[[A_IS_NICHE:.+]] = icmp sgt i8 %a, 1 // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1 // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2 - // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3 + // CHECK: %[[B_IS_NICHE:.+]] = icmp sgt i8 %b, 1 // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1 // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 @@ -138,13 +138,13 @@ pub fn mid_ac_eq_discr(a: Mid, b: Mid) -> bool { // CHECK-LABEL: @mid_ac_eq_discr( // CHECK: %[[A_REL_DISCR:.+]] = xor i8 %a, -128 - // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3 + // 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 // CHECK: %[[B_REL_DISCR:.+]] = xor i8 %b, -128 - // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3 + // 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 @@ -160,17 +160,17 @@ pub fn mid_ac_eq_discr(a: Mid, b: Mid) -> bool { pub fn mid_giant_eq_discr(a: Mid, b: Mid) -> bool { // CHECK-LABEL: @mid_giant_eq_discr( - // CHECK: %[[A_REL_DISCR_WIDE:.+]] = add nsw i128 %a, -5 - // CHECK: %[[A_REL_DISCR:.+]] = trunc nsw i128 %[[A_REL_DISCR_WIDE]] to i64 - // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i128 %[[A_REL_DISCR_WIDE]], 3 - // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i128 %[[A_REL_DISCR_WIDE]], 1 + // CHECK: %[[A_TRUNC:.+]] = trunc nuw nsw i128 %a to i64 + // CHECK: %[[A_REL_DISCR:.+]] = add nsw i64 %[[A_TRUNC]], -5 + // CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i128 %a, 4 + // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i64 %[[A_REL_DISCR]], 1 // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i64 %[[A_REL_DISCR]], i64 1 - // CHECK: %[[B_REL_DISCR_WIDE:.+]] = add nsw i128 %b, -5 - // CHECK: %[[B_REL_DISCR:.+]] = trunc nsw i128 %[[B_REL_DISCR_WIDE]] to i64 - // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i128 %[[B_REL_DISCR_WIDE]], 3 - // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i128 %[[B_REL_DISCR_WIDE]], 1 + // CHECK: %[[B_TRUNC:.+]] = trunc nuw nsw i128 %b to i64 + // CHECK: %[[B_REL_DISCR:.+]] = add nsw i64 %[[B_TRUNC]], -5 + // CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i128 %b, 4 + // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i64 %[[B_REL_DISCR]], 1 // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i64 %[[B_REL_DISCR]], i64 1 @@ -181,14 +181,11 @@ pub fn mid_giant_eq_discr(a: Mid, b: Mid) -> bool { // In niche-encoded enums, testing for the untagged variant should optimize to a // straight-forward comparison looking for the natural range of the payload value. -// FIXME: A bunch don't, though. #[unsafe(no_mangle)] pub fn mid_bool_is_thing(a: Mid) -> bool { // CHECK-LABEL: @mid_bool_is_thing( - - // CHECK: %[[REL_DISCR:.+]] = add nsw i8 %a, -2 - // CHECK: %[[R:.+]] = icmp ugt i8 %[[REL_DISCR]], 2 + // CHECK: %[[R:.+]] = icmp samesign ult i8 %a, 2 // CHECK: ret i1 %[[R]] discriminant_value(&a) == 1 } @@ -196,8 +193,7 @@ pub fn mid_bool_is_thing(a: Mid) -> bool { #[unsafe(no_mangle)] pub fn mid_ord_is_thing(a: Mid) -> bool { // CHECK-LABEL: @mid_ord_is_thing( - // CHECK: %[[REL_DISCR:.+]] = add nsw i8 %a, -2 - // CHECK: %[[R:.+]] = icmp ugt i8 %[[REL_DISCR]], 2 + // CHECK: %[[R:.+]] = icmp slt i8 %a, 2 // CHECK: ret i1 %[[R]] discriminant_value(&a) == 1 } @@ -221,11 +217,7 @@ pub fn mid_ac_is_thing(a: Mid) -> bool { #[unsafe(no_mangle)] pub fn mid_giant_is_thing(a: Mid) -> bool { // CHECK-LABEL: @mid_giant_is_thing( - // CHECK: %[[REL_DISCR_WIDE:.+]] = add nsw i128 %a, -5 - // CHECK: %[[REL_DISCR:.+]] = trunc nsw i128 %[[REL_DISCR_WIDE]] to i64 - // CHECK: %[[NOT_NICHE:.+]] = icmp ugt i128 %[[REL_DISCR_WIDE]], 2 - // CHECK: %[[IS_MID_VARIANT:.+]] = icmp eq i64 %[[REL_DISCR]], 1 - // CHECK: %[[R:.+]] = select i1 %[[NOT_NICHE]], i1 true, i1 %[[IS_MID_VARIANT]] + // CHECK: %[[R:.+]] = icmp samesign ult i128 %a, 5 // CHECK: ret i1 %[[R]] discriminant_value(&a) == 1 } diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs index 9725e64def6a..57db44ec74e8 100644 --- a/tests/codegen/enum/enum-match.rs +++ b/tests/codegen/enum/enum-match.rs @@ -41,7 +41,7 @@ pub enum Enum1 { // CHECK-NEXT: start: // CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 // CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 -// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 2 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp{{( samesign)?}} ugt i8 %0, 1 // CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1 // CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0 // CHECK-NEXT: switch i64 %[[DISCR]] @@ -148,10 +148,10 @@ pub enum MiddleNiche { // CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0) // CHECK-NEXT: start: // CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 -// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 5 // CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2 // CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) -// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[REL_VAR]], i8 2 +// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp{{( samesign)?}} ult i8 %0, 2 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[NOT_NICHE]], i8 2, i8 %[[REL_VAR]] // CHECK-NEXT: switch i8 %[[DISCR]] #[no_mangle] pub fn match4(e: MiddleNiche) -> u8 { @@ -167,11 +167,10 @@ pub fn match4(e: MiddleNiche) -> u8 { // CHECK-LABEL: define{{.+}}i1 @match4_is_c(i8{{.+}}%e) // CHECK-NEXT: start -// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %e, -2 -// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp ugt i8 %[[REL_VAR]], 4 -// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2 +// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %e, 4 // CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) -// CHECK-NEXT: ret i1 %[[NOT_NICHE]] +// CHECK-NEXT: %[[IS_C:.+]] = icmp{{( samesign)?}} ult i8 %e, 2 +// CHECK-NEXT: ret i1 %[[IS_C]] #[no_mangle] pub fn match4_is_c(e: MiddleNiche) -> bool { // Before #139098, this couldn't optimize out the `select` because it looked @@ -453,10 +452,10 @@ pub enum HugeVariantIndex { // CHECK-NEXT: start: // CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 // CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 -// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 3 -// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 1 -// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp{{( samesign)?}} ugt i8 %0, 1 // CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 257 +// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i64 %[[NICHE_DISCR]], 258 +// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) // CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 258 // CHECK-NEXT: switch i64 %[[DISCR]], // CHECK-NEXT: i64 257, From 0bb092a93fa32ac5d68fdeb4fc0482705a25247b Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 12 Jul 2025 10:28:44 -0400 Subject: [PATCH 120/363] Fix building the sysroot --- build_system/build_sysroot/Cargo.lock | 502 -------------------------- build_system/build_sysroot/Cargo.toml | 39 -- build_system/build_sysroot/lib.rs | 1 - build_system/src/build.rs | 35 +- build_system/src/utils.rs | 13 - 5 files changed, 10 insertions(+), 580 deletions(-) delete mode 100644 build_system/build_sysroot/Cargo.lock delete mode 100644 build_system/build_sysroot/Cargo.toml delete mode 100644 build_system/build_sysroot/lib.rs diff --git a/build_system/build_sysroot/Cargo.lock b/build_system/build_sysroot/Cargo.lock deleted file mode 100644 index 0c75977ee798..000000000000 --- a/build_system/build_sysroot/Cargo.lock +++ /dev/null @@ -1,502 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "compiler_builtins", - "gimli", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "alloc" -version = "0.0.0" -dependencies = [ - "compiler_builtins", - "core", -] - -[[package]] -name = "alloctests" -version = "0.0.0" -dependencies = [ - "rand", - "rand_xorshift", -] - -[[package]] -name = "cc" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "compiler_builtins" -version = "0.1.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6376049cfa92c0aa8b9ac95fae22184b981c658208d4ed8a1dc553cd83612895" -dependencies = [ - "cc", - "rustc-std-workspace-core", -] - -[[package]] -name = "core" -version = "0.0.0" - -[[package]] -name = "coretests" -version = "0.0.0" -dependencies = [ - "rand", - "rand_xorshift", -] - -[[package]] -name = "dlmalloc" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cff88b751e7a276c4ab0e222c3f355190adc6dde9ce39c851db39da34990df7" -dependencies = [ - "cfg-if", - "compiler_builtins", - "libc", - "rustc-std-workspace-core", - "windows-sys", -] - -[[package]] -name = "fortanix-sgx-abi" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "getopts" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -dependencies = [ - "rustc-std-workspace-core", - "rustc-std-workspace-std", - "unicode-width", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "hashbrown" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "hermit-abi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "libc" -version = "0.2.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" -dependencies = [ - "rustc-std-workspace-core", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" -dependencies = [ - "adler2", - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "compiler_builtins", - "memchr", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "panic_abort" -version = "0.0.0" -dependencies = [ - "alloc", - "compiler_builtins", - "core", - "libc", -] - -[[package]] -name = "panic_unwind" -version = "0.0.0" -dependencies = [ - "alloc", - "cfg-if", - "compiler_builtins", - "core", - "libc", - "unwind", -] - -[[package]] -name = "proc_macro" -version = "0.0.0" -dependencies = [ - "core", - "rustc-literal-escaper", - "std", -] - -[[package]] -name = "profiler_builtins" -version = "0.0.0" -dependencies = [ - "cc", -] - -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "r-efi-alloc" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e43c53ff1a01d423d1cb762fd991de07d32965ff0ca2e4f80444ac7804198203" -dependencies = [ - "compiler_builtins", - "r-efi", - "rustc-std-workspace-core", -] - -[[package]] -name = "rand" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" - -[[package]] -name = "rand_xorshift" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "rustc-literal-escaper" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04" -dependencies = [ - "rustc-std-workspace-std", -] - -[[package]] -name = "rustc-std-workspace-alloc" -version = "1.99.0" -dependencies = [ - "alloc", -] - -[[package]] -name = "rustc-std-workspace-core" -version = "1.99.0" -dependencies = [ - "core", -] - -[[package]] -name = "rustc-std-workspace-std" -version = "1.99.0" -dependencies = [ - "std", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "std" -version = "0.0.0" -dependencies = [ - "addr2line", - "alloc", - "cfg-if", - "compiler_builtins", - "core", - "dlmalloc", - "fortanix-sgx-abi", - "hashbrown", - "hermit-abi", - "libc", - "miniz_oxide", - "object", - "panic_abort", - "panic_unwind", - "r-efi", - "r-efi-alloc", - "rand", - "rand_xorshift", - "rustc-demangle", - "std_detect", - "unwind", - "wasi", - "windows-targets 0.0.0", -] - -[[package]] -name = "std_detect" -version = "0.1.5" -dependencies = [ - "cfg-if", - "compiler_builtins", - "libc", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "sysroot" -version = "0.0.0" -dependencies = [ - "proc_macro", - "profiler_builtins", - "std", - "test", -] - -[[package]] -name = "test" -version = "0.0.0" -dependencies = [ - "core", - "getopts", - "libc", - "std", -] - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", - "rustc-std-workspace-std", -] - -[[package]] -name = "unwind" -version = "0.0.0" -dependencies = [ - "cfg-if", - "compiler_builtins", - "core", - "libc", - "unwinding", -] - -[[package]] -name = "unwinding" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345" -dependencies = [ - "compiler_builtins", - "gimli", - "rustc-std-workspace-core", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.0.0" - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/build_system/build_sysroot/Cargo.toml b/build_system/build_sysroot/Cargo.toml deleted file mode 100644 index 29a3bcec304c..000000000000 --- a/build_system/build_sysroot/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -authors = ["rustc_codegen_gcc devs"] -name = "sysroot" -version = "0.0.0" -resolver = "2" - -[dependencies] -core = { path = "./sysroot_src/library/core" } -compiler_builtins = { path = "./sysroot_src/library/compiler-builtins/compiler-builtins" } -alloc = { path = "./sysroot_src/library/alloc" } -std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] } -test = { path = "./sysroot_src/library/test" } -proc_macro = { path = "./sysroot_src/library/proc_macro" } - -[patch.crates-io] -rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" } -rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" } -rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" } -compiler_builtins = { path = "./sysroot_src/library/compiler-builtins/compiler-builtins" } - -# For compiler-builtins we always use a high number of codegen units. -# The goal here is to place every single intrinsic into its own object -# file to avoid symbol clashes with the system libgcc if possible. Note -# that this number doesn't actually produce this many object files, we -# just don't create more than this number of object files. -# -# It's a bit of a bummer that we have to pass this here, unfortunately. -# Ideally this would be specified through an env var to Cargo so Cargo -# knows how many CGUs are for this specific crate, but for now -# per-crate configuration isn't specifiable in the environment. -[profile.dev.package.compiler_builtins] -codegen-units = 10000 - -[profile.release.package.compiler_builtins] -codegen-units = 10000 - -[profile.release] -debug = "limited" -#lto = "fat" # TODO(antoyo): re-enable when the failing LTO tests regarding proc-macros are fixed. diff --git a/build_system/build_sysroot/lib.rs b/build_system/build_sysroot/lib.rs deleted file mode 100644 index 0c9ac1ac8e4b..000000000000 --- a/build_system/build_sysroot/lib.rs +++ /dev/null @@ -1 +0,0 @@ -#![no_std] diff --git a/build_system/src/build.rs b/build_system/src/build.rs index ecc4c1b2fe22..8c09ea3ba42b 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -5,7 +5,7 @@ use std::path::Path; use crate::config::{Channel, ConfigInfo}; use crate::utils::{ - copy_file, create_dir, get_sysroot_dir, run_command, run_command_with_output_and_env, walk_dir, + create_dir, get_sysroot_dir, run_command, run_command_with_output_and_env, walk_dir, }; #[derive(Default)] @@ -53,11 +53,11 @@ impl BuildArg { } } -fn cleanup_sysroot_previous_build(start_dir: &Path) { +fn cleanup_sysroot_previous_build(library_dir: &Path) { // Cleanup for previous run // Clean target dir except for build scripts and incremental cache let _ = walk_dir( - start_dir.join("target"), + library_dir.join("target"), &mut |dir: &Path| { for top in &["debug", "release"] { let _ = fs::remove_dir_all(dir.join(top).join("build")); @@ -96,30 +96,14 @@ fn cleanup_sysroot_previous_build(start_dir: &Path) { false, ); - let _ = fs::remove_file(start_dir.join("Cargo.lock")); - let _ = fs::remove_file(start_dir.join("test_target/Cargo.lock")); - let _ = fs::remove_dir_all(start_dir.join("sysroot")); -} - -pub fn create_build_sysroot_content(start_dir: &Path) -> Result<(), String> { - if !start_dir.is_dir() { - create_dir(start_dir)?; - } - copy_file("build_system/build_sysroot/Cargo.toml", start_dir.join("Cargo.toml"))?; - copy_file("build_system/build_sysroot/Cargo.lock", start_dir.join("Cargo.lock"))?; - - let src_dir = start_dir.join("src"); - if !src_dir.is_dir() { - create_dir(&src_dir)?; - } - copy_file("build_system/build_sysroot/lib.rs", start_dir.join("src/lib.rs")) + let _ = fs::remove_file(library_dir.join("Cargo.lock")); } pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Result<(), String> { let start_dir = get_sysroot_dir(); - cleanup_sysroot_previous_build(&start_dir); - create_build_sysroot_content(&start_dir)?; + let library_dir = start_dir.join("sysroot_src").join("library"); + cleanup_sysroot_previous_build(&library_dir); // Builds libs let mut rustflags = env.get("RUSTFLAGS").cloned().unwrap_or_default(); @@ -159,7 +143,8 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu let mut env = env.clone(); env.insert("RUSTFLAGS".to_string(), rustflags); - run_command_with_output_and_env(&args, Some(&start_dir), Some(&env))?; + let sysroot_dir = library_dir.join("sysroot"); + run_command_with_output_and_env(&args, Some(&sysroot_dir), Some(&env))?; // Copy files to sysroot let sysroot_path = start_dir.join(format!("sysroot/lib/rustlib/{}/lib/", config.target_triple)); @@ -169,7 +154,7 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu run_command(&[&"cp", &"-r", &dir_to_copy, &sysroot_path], None).map(|_| ()) }; walk_dir( - start_dir.join(format!("target/{}/{}/deps", config.target_triple, channel)), + library_dir.join(format!("target/{}/{}/deps", config.target_triple, channel)), &mut copier.clone(), &mut copier, false, @@ -178,7 +163,7 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu // Copy the source files to the sysroot (Rust for Linux needs this). let sysroot_src_path = start_dir.join("sysroot/lib/rustlib/src/rust"); create_dir(&sysroot_src_path)?; - run_command(&[&"cp", &"-r", &start_dir.join("sysroot_src/library/"), &sysroot_src_path], None)?; + run_command(&[&"cp", &"-r", &library_dir, &sysroot_src_path], None)?; Ok(()) } diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index d77707d5f17a..fc948c54b24a 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -303,19 +303,6 @@ pub fn create_dir>(path: P) -> Result<(), String> { }) } -pub fn copy_file, T: AsRef>(from: F, to: T) -> Result<(), String> { - fs::copy(&from, &to) - .map_err(|error| { - format!( - "Failed to copy file `{}` into `{}`: {:?}", - from.as_ref().display(), - to.as_ref().display(), - error - ) - }) - .map(|_| ()) -} - /// This function differs from `git_clone` in how it handles *where* the repository will be cloned. /// In `git_clone`, it is cloned in the provided path. In this function, the path you provide is /// the parent folder. So if you pass "a" as folder and try to clone "b.git", it will be cloned into From 1954034e3472d2c8c8229e029e92b81db5809f9c Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 12 Jul 2025 10:44:48 -0400 Subject: [PATCH 121/363] Comment test that cannot be fixed currently --- build_system/src/build.rs | 2 -- example/mini_core_hello_world.rs | 17 ++++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 8c09ea3ba42b..4033ffe0694a 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -95,8 +95,6 @@ fn cleanup_sysroot_previous_build(library_dir: &Path) { &mut |_| Ok(()), false, ); - - let _ = fs::remove_file(library_dir.join("Cargo.lock")); } pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Result<(), String> { diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 6b6f71edaf8c..092fd6a76409 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -6,7 +6,7 @@ )] #![no_core] #![allow(dead_code, internal_features, non_camel_case_types)] -#![rustfmt::skip] +#![cfg_attr(rustfmt, rustfmt_skip)] extern crate mini_core; @@ -198,10 +198,17 @@ fn main() { assert_eq!(intrinsics::align_of::() as u8, 2); assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); - assert!(!const { intrinsics::needs_drop::() }); - assert!(!const { intrinsics::needs_drop::<[u8]>() }); - assert!(const { intrinsics::needs_drop::() }); - assert!(const { intrinsics::needs_drop::() }); + /* + * TODO: re-enable in the next sync. + let u8_needs_drop = const { intrinsics::needs_drop::() }; + assert!(!u8_needs_drop); + let slice_needs_drop = const { intrinsics::needs_drop::<[u8]>() }; + assert!(!slice_needs_drop); + let noisy_drop = const { intrinsics::needs_drop::() }; + assert!(noisy_drop); + let noisy_unsized_drop = const { intrinsics::needs_drop::() }; + assert!(noisy_unsized_drop); + */ Unique { pointer: 0 as *const &str, From afeed5067762d0a087744bda528cc3c95cb81e9a Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Jul 2025 20:10:36 +0800 Subject: [PATCH 122/363] Adjust `run_make_support::symbols` helpers Massage the `symbols` helpers to fill out {match all, match any} x {substring match, exact match}: | | Substring match | Exact match | |-----------|----------------------------------------|-------------------------------| | Match any | `object_contains_any_symbol_substring` | `object_contains_any_symbol` | | Match all | `object_contains_all_symbol_substring` | `object_contains_all_symbols` | As part of this, rename `any_symbol_contains` to `object_contains_any_symbol_substring` for accuracy. --- src/tools/run-make-support/src/symbols.rs | 184 +++++++++++++++--- .../symbols-helpers/rmake.rs | 92 +++++++++ .../symbols-helpers/sample.rs | 13 ++ 3 files changed, 264 insertions(+), 25 deletions(-) create mode 100644 tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs create mode 100644 tests/run-make/compiletest-self-test/symbols-helpers/sample.rs diff --git a/src/tools/run-make-support/src/symbols.rs b/src/tools/run-make-support/src/symbols.rs index e4d244e14a4a..0e11360bd5a0 100644 --- a/src/tools/run-make-support/src/symbols.rs +++ b/src/tools/run-make-support/src/symbols.rs @@ -1,6 +1,7 @@ +use std::collections::BTreeSet; use std::path::Path; -use object::{self, Object, ObjectSymbol, SymbolIterator}; +use object::{self, Object, ObjectSymbol}; /// Given an [`object::File`], find the exported dynamic symbol names via /// [`object::Object::exports`]. This does not distinguish between which section the symbols appear @@ -14,47 +15,180 @@ pub fn exported_dynamic_symbol_names<'file>(file: &'file object::File<'file>) -> .collect() } -/// Iterate through the symbols in an object file. See [`object::Object::symbols`]. +/// Check an object file's symbols for any matching **substrings**. That is, if an object file +/// contains a symbol named `hello_world`, it will be matched against a provided `substrings` of +/// `["hello", "bar"]`. +/// +/// Returns `true` if **any** of the symbols found in the object file at `path` contain a +/// **substring** listed in `substrings`. /// /// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be /// parsed as a recognized object file. +/// +/// # Platform-specific behavior +/// +/// On Windows MSVC, the binary (e.g. `main.exe`) does not contain the symbols, but in the separate +/// PDB file instead. Furthermore, you will need to use [`crate::llvm::llvm_pdbutil`] as `object` +/// crate does not handle PDB files. #[track_caller] -pub fn with_symbol_iter(path: P, func: F) -> R +pub fn object_contains_any_symbol_substring(path: P, substrings: &[S]) -> bool where P: AsRef, - F: FnOnce(&mut SymbolIterator<'_, '_>) -> R, + S: AsRef, { let path = path.as_ref(); let blob = crate::fs::read(path); - let f = object::File::parse(&*blob) + let obj = object::File::parse(&*blob) .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display())); - let mut iter = f.symbols(); - func(&mut iter) + let substrings = substrings.iter().map(|s| s.as_ref()).collect::>(); + for sym in obj.symbols() { + for substring in &substrings { + if sym.name_bytes().unwrap().windows(substring.len()).any(|x| x == substring.as_bytes()) + { + return true; + } + } + } + false } -/// Check an object file's symbols for substrings. +/// Check an object file's symbols for any exact matches against those provided in +/// `candidate_symbols`. /// -/// Returns `true` if any of the symbols found in the object file at `path` contain a substring -/// listed in `substrings`. +/// Returns `true` if **any** of the symbols found in the object file at `path` contain an **exact +/// match** against those listed in `candidate_symbols`. Take care to account for (1) platform +/// differences and (2) calling convention and symbol decorations differences. /// /// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be /// parsed as a recognized object file. +/// +/// # Platform-specific behavior +/// +/// See [`object_contains_any_symbol_substring`]. #[track_caller] -pub fn any_symbol_contains(path: impl AsRef, substrings: &[&str]) -> bool { - with_symbol_iter(path, |syms| { - for sym in syms { - for substring in substrings { - if sym - .name_bytes() - .unwrap() - .windows(substring.len()) - .any(|x| x == substring.as_bytes()) - { - eprintln!("{:?} contains {}", sym, substring); - return true; - } +pub fn object_contains_any_symbol(path: P, candidate_symbols: &[S]) -> bool +where + P: AsRef, + S: AsRef, +{ + let path = path.as_ref(); + let blob = crate::fs::read(path); + let obj = object::File::parse(&*blob) + .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display())); + let candidate_symbols = candidate_symbols.iter().map(|s| s.as_ref()).collect::>(); + for sym in obj.symbols() { + for candidate_symbol in &candidate_symbols { + if sym.name_bytes().unwrap() == candidate_symbol.as_bytes() { + return true; } } - false - }) + } + false +} + +#[derive(Debug, PartialEq)] +pub enum ContainsAllSymbolSubstringsOutcome<'a> { + Ok, + MissingSymbolSubstrings(BTreeSet<&'a str>), +} + +/// Check an object file's symbols for presence of all of provided **substrings**. That is, if an +/// object file contains symbols `["hello", "goodbye", "world"]`, it will be matched against a list +/// of `substrings` of `["he", "go"]`. In this case, `he` is a substring of `hello`, and `go` is a +/// substring of `goodbye`, so each of `substrings` was found. +/// +/// Returns `true` if **all** `substrings` were present in the names of symbols for the given object +/// file (as substrings of symbol names). +/// +/// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be +/// parsed as a recognized object file. +/// +/// # Platform-specific behavior +/// +/// See [`object_contains_any_symbol_substring`]. +#[track_caller] +pub fn object_contains_all_symbol_substring<'s, P, S>( + path: P, + substrings: &'s [S], +) -> ContainsAllSymbolSubstringsOutcome<'s> +where + P: AsRef, + S: AsRef, +{ + let path = path.as_ref(); + let blob = crate::fs::read(path); + let obj = object::File::parse(&*blob) + .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display())); + let substrings = substrings.iter().map(|s| s.as_ref()); + let mut unmatched_symbol_substrings = BTreeSet::from_iter(substrings); + unmatched_symbol_substrings.retain(|unmatched_symbol_substring| { + for sym in obj.symbols() { + if sym + .name_bytes() + .unwrap() + .windows(unmatched_symbol_substring.len()) + .any(|x| x == unmatched_symbol_substring.as_bytes()) + { + return false; + } + } + + true + }); + + if unmatched_symbol_substrings.is_empty() { + ContainsAllSymbolSubstringsOutcome::Ok + } else { + ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(unmatched_symbol_substrings) + } +} + +#[derive(Debug, PartialEq)] +pub enum ContainsAllSymbolsOutcome<'a> { + Ok, + MissingSymbols(BTreeSet<&'a str>), +} + +/// Check an object file contains all symbols provided in `candidate_symbols`. +/// +/// Returns `true` if **all** of the symbols in `candidate_symbols` are found within the object file +/// at `path` by **exact match**. Take care to account for (1) platform differences and (2) calling +/// convention and symbol decorations differences. +/// +/// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be +/// parsed as a recognized object file. +/// +/// # Platform-specific behavior +/// +/// See [`object_contains_any_symbol_substring`]. +#[track_caller] +pub fn object_contains_all_symbols( + path: P, + candidate_symbols: &[S], +) -> ContainsAllSymbolsOutcome<'_> +where + P: AsRef, + S: AsRef, +{ + let path = path.as_ref(); + let blob = crate::fs::read(path); + let obj = object::File::parse(&*blob) + .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display())); + let candidate_symbols = candidate_symbols.iter().map(|s| s.as_ref()); + let mut unmatched_symbols = BTreeSet::from_iter(candidate_symbols); + unmatched_symbols.retain(|unmatched_symbol| { + for sym in obj.symbols() { + if sym.name_bytes().unwrap() == unmatched_symbol.as_bytes() { + return false; + } + } + + true + }); + + if unmatched_symbols.is_empty() { + ContainsAllSymbolsOutcome::Ok + } else { + ContainsAllSymbolsOutcome::MissingSymbols(unmatched_symbols) + } } diff --git a/tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs b/tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs new file mode 100644 index 000000000000..73826214aac6 --- /dev/null +++ b/tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs @@ -0,0 +1,92 @@ +//! `run_make_support::symbols` helpers self test. + +// Only intended as a basic smoke test, does not try to account for platform or calling convention +// specific symbol decorations. +//@ only-x86_64-unknown-linux-gnu +//@ ignore-cross-compile + +use std::collections::BTreeSet; + +use object::{Object, ObjectSymbol}; +use run_make_support::symbols::{ + ContainsAllSymbolSubstringsOutcome, ContainsAllSymbolsOutcome, + object_contains_all_symbol_substring, object_contains_all_symbols, object_contains_any_symbol, + object_contains_any_symbol_substring, +}; +use run_make_support::{object, rfs, rust_lib_name, rustc}; + +fn main() { + rustc().input("sample.rs").emit("obj").edition("2024").run(); + + // `sample.rs` has two `no_mangle` functions, `eszett` and `beta`, in addition to `main`. + // + // These two symbol names and the test substrings used below are carefully picked to make sure + // they do not overlap with `sample` and contain non-hex characters, to avoid accidentally + // matching against CGU names like `sample.dad0f15d00c84e70-cgu.0`. + + let obj_filename = "sample.o"; + let blob = rfs::read(obj_filename); + let obj = object::File::parse(&*blob).unwrap(); + eprintln!("found symbols:"); + for sym in obj.symbols() { + eprintln!("symbol = {}", sym.name().unwrap()); + } + + // `hello` contains `hel` + assert!(object_contains_any_symbol_substring(obj_filename, &["zett"])); + assert!(object_contains_any_symbol_substring(obj_filename, &["zett", "does_not_exist"])); + assert!(!object_contains_any_symbol_substring(obj_filename, &["does_not_exist"])); + + assert!(object_contains_any_symbol(obj_filename, &["eszett"])); + assert!(object_contains_any_symbol(obj_filename, &["eszett", "beta"])); + assert!(!object_contains_any_symbol(obj_filename, &["zett"])); + assert!(!object_contains_any_symbol(obj_filename, &["does_not_exist"])); + + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["zett"]), + ContainsAllSymbolSubstringsOutcome::Ok + ); + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["zett", "bet"]), + ContainsAllSymbolSubstringsOutcome::Ok + ); + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["does_not_exist"]), + ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(BTreeSet::from([ + "does_not_exist" + ])) + ); + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["zett", "does_not_exist"]), + ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(BTreeSet::from([ + "does_not_exist" + ])) + ); + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["zett", "bet", "does_not_exist"]), + ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(BTreeSet::from([ + "does_not_exist" + ])) + ); + + assert_eq!( + object_contains_all_symbols(obj_filename, &["eszett"]), + ContainsAllSymbolsOutcome::Ok + ); + assert_eq!( + object_contains_all_symbols(obj_filename, &["eszett", "beta"]), + ContainsAllSymbolsOutcome::Ok + ); + assert_eq!( + object_contains_all_symbols(obj_filename, &["zett"]), + ContainsAllSymbolsOutcome::MissingSymbols(BTreeSet::from(["zett"])) + ); + assert_eq!( + object_contains_all_symbols(obj_filename, &["zett", "beta"]), + ContainsAllSymbolsOutcome::MissingSymbols(BTreeSet::from(["zett"])) + ); + assert_eq!( + object_contains_all_symbols(obj_filename, &["does_not_exist"]), + ContainsAllSymbolsOutcome::MissingSymbols(BTreeSet::from(["does_not_exist"])) + ); +} diff --git a/tests/run-make/compiletest-self-test/symbols-helpers/sample.rs b/tests/run-make/compiletest-self-test/symbols-helpers/sample.rs new file mode 100644 index 000000000000..3566d2997668 --- /dev/null +++ b/tests/run-make/compiletest-self-test/symbols-helpers/sample.rs @@ -0,0 +1,13 @@ +#![crate_type = "lib"] + +#[unsafe(no_mangle)] +pub extern "C" fn eszett() -> i8 { + 42 +} + +#[unsafe(no_mangle)] +pub extern "C" fn beta() -> u32 { + 1 +} + +fn main() {} From 1d0cbc6816cbc3cf069a9970a09666ed5b4aafdf Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Jul 2025 21:16:46 +0800 Subject: [PATCH 123/363] Update `run-make` tests to use adjusted `symbols` helpers --- tests/run-make/fmt-write-bloat/rmake.rs | 4 ++-- tests/run-make/used/rmake.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/run-make/fmt-write-bloat/rmake.rs b/tests/run-make/fmt-write-bloat/rmake.rs index 3348651d501f..b78e8f49683c 100644 --- a/tests/run-make/fmt-write-bloat/rmake.rs +++ b/tests/run-make/fmt-write-bloat/rmake.rs @@ -20,7 +20,7 @@ use run_make_support::artifact_names::bin_name; use run_make_support::env::no_debug_assertions; use run_make_support::rustc; -use run_make_support::symbols::any_symbol_contains; +use run_make_support::symbols::object_contains_any_symbol_substring; fn main() { rustc().input("main.rs").opt().run(); @@ -31,5 +31,5 @@ fn main() { // otherwise, add them to the list of symbols to deny. panic_syms.extend_from_slice(&["panicking", "panic_fmt", "pad_integral", "Display"]); } - assert!(!any_symbol_contains(bin_name("main"), &panic_syms)); + assert!(!object_contains_any_symbol_substring(bin_name("main"), &panic_syms)); } diff --git a/tests/run-make/used/rmake.rs b/tests/run-make/used/rmake.rs index bcdb84132d3f..456321e2f56c 100644 --- a/tests/run-make/used/rmake.rs +++ b/tests/run-make/used/rmake.rs @@ -8,9 +8,9 @@ // https://rust-lang.github.io/rfcs/2386-used.html use run_make_support::rustc; -use run_make_support::symbols::any_symbol_contains; +use run_make_support::symbols::object_contains_any_symbol_substring; fn main() { rustc().opt_level("3").emit("obj").input("used.rs").run(); - assert!(any_symbol_contains("used.o", &["FOO"])); + assert!(object_contains_any_symbol_substring("used.o", &["FOO"])); } From 10866f46172e92a7949dca2e5a52b8c444a5b082 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 13 Jul 2025 15:51:32 +0800 Subject: [PATCH 124/363] Fix typo in `std::vec` Signed-off-by: xizheyin --- library/alloc/src/vec/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index c8341750f4d3..a4741f30fa5a 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3695,7 +3695,7 @@ impl Vec { /// This is optimal if: /// /// * The tail (elements in the vector after `range`) is empty, - /// * or `replace_with` yields fewer or equal elements than `range`’s length + /// * or `replace_with` yields fewer or equal elements than `range`'s length /// * or the lower bound of its `size_hint()` is exact. /// /// Otherwise, a temporary vector is allocated and the tail is moved twice. From 1cab09ed9c582e7804bd0f9a6ead61129bb537d5 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 13 Jul 2025 16:06:53 +0800 Subject: [PATCH 125/363] `std::vec`: Upgrade `debug_assert` to UB check in `set_len` Signed-off-by: xizheyin --- library/alloc/src/lib.rs | 1 + library/alloc/src/vec/mod.rs | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 4290bb7a8a93..947df24d44f5 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -153,6 +153,7 @@ #![feature(try_trait_v2)] #![feature(try_with_capacity)] #![feature(tuple_trait)] +#![feature(ub_checks)] #![feature(unicode_internals)] #![feature(unsize)] #![feature(unwrap_infallible)] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index a4741f30fa5a..da3d3596d192 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -64,7 +64,7 @@ use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; -use core::{fmt, intrinsics}; +use core::{fmt, intrinsics, ub_checks}; #[stable(feature = "extract_if", since = "1.87.0")] pub use self::extract_if::ExtractIf; @@ -1950,7 +1950,11 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn set_len(&mut self, new_len: usize) { - debug_assert!(new_len <= self.capacity()); + ub_checks::assert_unsafe_precondition!( + check_library_ub, + "Vec::set_len requires that new_len <= capacity()", + (new_len: usize = new_len, capacity: usize = self.capacity()) => new_len <= capacity + ); self.len = new_len; } From 090c177003272da7d2d3b04702f35261d3952b72 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 13 Jul 2025 16:17:43 +0800 Subject: [PATCH 126/363] std::vec: Add UB check in `from_raw_parts_in` Signed-off-by: xizheyin --- library/alloc/src/vec/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index da3d3596d192..6d44681fb28b 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1058,6 +1058,11 @@ impl Vec { #[inline] #[unstable(feature = "allocator_api", issue = "32838")] pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self { + ub_checks::assert_unsafe_precondition!( + check_library_ub, + "Vec::from_raw_parts_in requires that length <= capacity", + (length: usize = length, capacity: usize = capacity) => length <= capacity + ); unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } } } From 48caa5f8897263da935ebdc2bbec8a95b5d3d025 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 13 Jul 2025 16:18:56 +0800 Subject: [PATCH 127/363] std::vec: Add UB check in `from_parts_in` Signed-off-by: xizheyin --- library/alloc/src/vec/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 6d44681fb28b..50f8cc375bfe 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1179,6 +1179,11 @@ impl Vec { #[unstable(feature = "allocator_api", reason = "new API", issue = "32838")] // #[unstable(feature = "box_vec_non_null", issue = "130364")] pub unsafe fn from_parts_in(ptr: NonNull, length: usize, capacity: usize, alloc: A) -> Self { + ub_checks::assert_unsafe_precondition!( + check_library_ub, + "Vec::from_parts_in requires that length <= capacity", + (length: usize = length, capacity: usize = capacity) => length <= capacity + ); unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } } } From f58accb8f370a0a9e89548f2d890bd09ede3e613 Mon Sep 17 00:00:00 2001 From: usamoi Date: Sun, 13 Jul 2025 00:12:33 +0800 Subject: [PATCH 128/363] pass --gc-sections if -Zexport-executable-symbols is enabled and improve tests --- compiler/rustc_codegen_ssa/src/back/link.rs | 9 ++---- .../export-executable-symbols/rmake.rs | 25 ++++++++-------- tests/ui/linking/export-executable-symbols.rs | 29 +++++++++++++++---- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index b46773396fce..ae148287a601 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2542,12 +2542,9 @@ fn add_order_independent_options( // sections to ensure we have all the data for PGO. let keep_metadata = crate_type == CrateType::Dylib || sess.opts.cg.profile_generate.enabled(); - if crate_type != CrateType::Executable || !sess.opts.unstable_opts.export_executable_symbols - { - cmd.gc_sections(keep_metadata); - } else { - cmd.no_gc_sections(); - } + cmd.gc_sections(keep_metadata); + } else { + cmd.no_gc_sections(); } cmd.set_output_kind(link_output_kind, crate_type, out_filename); diff --git a/tests/run-make/export-executable-symbols/rmake.rs b/tests/run-make/export-executable-symbols/rmake.rs index 884c7362822f..c602a43f9572 100644 --- a/tests/run-make/export-executable-symbols/rmake.rs +++ b/tests/run-make/export-executable-symbols/rmake.rs @@ -4,20 +4,21 @@ // symbol. // See https://github.com/rust-lang/rust/pull/85673 -//@ only-unix -// Reason: the export-executable-symbols flag only works on Unix -// due to hardcoded platform-specific implementation -// (See #85673) -//@ ignore-cross-compile //@ ignore-wasm -use run_make_support::{bin_name, llvm_readobj, rustc}; +use run_make_support::object::Object; +use run_make_support::{bin_name, is_darwin, object, rustc}; fn main() { - rustc().arg("-Zexport-executable-symbols").input("main.rs").crate_type("bin").run(); - llvm_readobj() - .symbols() - .input(bin_name("main")) - .run() - .assert_stdout_contains("exported_symbol"); + rustc() + .arg("-Ctarget-feature=-crt-static") + .arg("-Zexport-executable-symbols") + .input("main.rs") + .crate_type("bin") + .run(); + let name: &[u8] = if is_darwin() { b"_exported_symbol" } else { b"exported_symbol" }; + let contents = std::fs::read(bin_name("main")).unwrap(); + let object = object::File::parse(contents.as_slice()).unwrap(); + let found = object.exports().unwrap().iter().any(|x| x.name() == name); + assert!(found); } diff --git a/tests/ui/linking/export-executable-symbols.rs b/tests/ui/linking/export-executable-symbols.rs index aea5527b6a1c..edaf312f1928 100644 --- a/tests/ui/linking/export-executable-symbols.rs +++ b/tests/ui/linking/export-executable-symbols.rs @@ -1,22 +1,21 @@ //@ run-pass -//@ only-linux -//@ only-gnu -//@ compile-flags: -Zexport-executable-symbols +//@ compile-flags: -Ctarget-feature=-crt-static -Zexport-executable-symbols +//@ ignore-wasm //@ edition: 2024 // Regression test for . #![feature(rustc_private)] -extern crate libc; - #[unsafe(no_mangle)] fn hack() -> u64 { 998244353 } fn main() { + #[cfg(unix)] unsafe { + extern crate libc; let handle = libc::dlopen(std::ptr::null(), libc::RTLD_NOW); let ptr = libc::dlsym(handle, c"hack".as_ptr()); let ptr: Option u64> = std::mem::transmute(ptr); @@ -27,4 +26,24 @@ fn main() { panic!("symbol `hack` is not found"); } } + #[cfg(windows)] + unsafe { + type PCSTR = *const u8; + type HMODULE = *mut core::ffi::c_void; + type FARPROC = Option isize>; + #[link(name = "kernel32", kind = "raw-dylib")] + unsafe extern "system" { + fn GetModuleHandleA(lpmodulename: PCSTR) -> HMODULE; + fn GetProcAddress(hmodule: HMODULE, lpprocname: PCSTR) -> FARPROC; + } + let handle = GetModuleHandleA(std::ptr::null_mut()); + let ptr = GetProcAddress(handle, b"hack\0".as_ptr()); + let ptr: Option u64> = std::mem::transmute(ptr); + if let Some(f) = ptr { + assert!(f() == 998244353); + println!("symbol `hack` is found successfully"); + } else { + panic!("symbol `hack` is not found"); + } + } } From ef726a4cef26710fb190d9a179f7be62be16e95c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Jul 2025 15:47:17 +0000 Subject: [PATCH 129/363] Ensure proper item queries for assoc tys --- compiler/rustc_hir_analysis/src/check/check.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f4bbf03f0c26..604add6ffb90 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -889,8 +889,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), tcx.ensure_ok().predicates_of(def_id); tcx.ensure_ok().explicit_item_bounds(def_id); tcx.ensure_ok().explicit_item_self_bounds(def_id); - tcx.ensure_ok().item_bounds(def_id); - tcx.ensure_ok().item_self_bounds(def_id); if tcx.is_conditionally_const(def_id) { tcx.ensure_ok().explicit_implied_const_bounds(def_id); tcx.ensure_ok().const_conditions(def_id); @@ -1042,8 +1040,12 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), let has_type = match assoc_item.container { ty::AssocItemContainer::Impl => true, ty::AssocItemContainer::Trait => { - tcx.ensure_ok().item_bounds(def_id); - tcx.ensure_ok().item_self_bounds(def_id); + tcx.ensure_ok().explicit_item_bounds(def_id); + tcx.ensure_ok().explicit_item_self_bounds(def_id); + if tcx.is_conditionally_const(def_id) { + tcx.ensure_ok().explicit_implied_const_bounds(def_id); + tcx.ensure_ok().const_conditions(def_id); + } res = res.and(check_trait_item(tcx, def_id)); assoc_item.defaultness(tcx).has_value() } From 549a5d8b2843cff903a872ffa682f34d74bb341a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Jul 2025 16:23:20 +0000 Subject: [PATCH 130/363] Dont collect assoc ty item bounds from trait where clause for host effect predicates --- .../src/collect/item_bounds.rs | 56 +++++++++++-------- tests/crashes/133275-1.rs | 13 ----- tests/crashes/133275-2.rs | 15 ----- .../const-assoc-bound-in-trait-wc.rs | 13 +++++ 4 files changed, 47 insertions(+), 50 deletions(-) delete mode 100644 tests/crashes/133275-1.rs delete mode 100644 tests/crashes/133275-2.rs create mode 100644 tests/ui/traits/const-traits/const-assoc-bound-in-trait-wc.rs diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index e51ef46afb72..7e3fb5448f64 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -38,12 +38,13 @@ fn associated_type_bounds<'tcx>( let icx = ItemCtxt::new(tcx, assoc_item_def_id); let mut bounds = Vec::new(); icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); - // Implicit bounds are added to associated types unless a `?Trait` bound is found + match filter { PredicateFilter::All | PredicateFilter::SelfOnly | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { + // Implicit bounds are added to associated types unless a `?Trait` bound is found. icx.lowerer().add_sizedness_bounds( &mut bounds, item_ty, @@ -53,37 +54,48 @@ fn associated_type_bounds<'tcx>( span, ); icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span); + + // Also collect `where Self::Assoc: Trait` from the parent trait's where clauses. + let trait_def_id = tcx.local_parent(assoc_item_def_id); + let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); + + let item_trait_ref = + ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id())); + bounds.extend(trait_predicates.predicates.iter().copied().filter_map( + |(clause, span)| { + remap_gat_vars_and_recurse_into_nested_projections( + tcx, + filter, + item_trait_ref, + assoc_item_def_id, + span, + clause, + ) + }, + )); } // `ConstIfConst` is only interested in `[const]` bounds. - PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} + PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => { + // FIXME(const_trait_impl): We *could* uplift the + // `where Self::Assoc: [const] Trait` bounds from the parent trait + // here too, but we'd need to split `const_conditions` into two + // queries (like we do for `trait_explicit_predicates_and_bounds`) + // since we need to also filter the predicates *out* of the const + // conditions or they lead to cycles in the trait solver when + // utilizing these bounds. For now, let's do nothing. + } } - let trait_def_id = tcx.local_parent(assoc_item_def_id); - let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); - - let item_trait_ref = ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id())); - let bounds_from_parent = - trait_predicates.predicates.iter().copied().filter_map(|(clause, span)| { - remap_gat_vars_and_recurse_into_nested_projections( - tcx, - filter, - item_trait_ref, - assoc_item_def_id, - span, - clause, - ) - }); - - let all_bounds = tcx.arena.alloc_from_iter(bounds.into_iter().chain(bounds_from_parent)); + let bounds = tcx.arena.alloc_from_iter(bounds); debug!( "associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id.to_def_id()), - all_bounds + bounds ); - assert_only_contains_predicates_from(filter, all_bounds, item_ty); + assert_only_contains_predicates_from(filter, bounds, item_ty); - all_bounds + bounds }) } diff --git a/tests/crashes/133275-1.rs b/tests/crashes/133275-1.rs deleted file mode 100644 index 73c04f5d6e41..000000000000 --- a/tests/crashes/133275-1.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: #133275 -#![feature(const_trait_impl)] -#![feature(associated_type_defaults)] - -#[const_trait] -trait Foo3 -where - Self::Baz: Clone, -{ - type Baz = T; -} - -pub fn main() {} diff --git a/tests/crashes/133275-2.rs b/tests/crashes/133275-2.rs deleted file mode 100644 index a774b3cdb690..000000000000 --- a/tests/crashes/133275-2.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: #133275 -#![feature(const_trait_impl)] -#[const_trait] -pub trait Owo::T> {} - -#[const_trait] -trait Foo3 -where - Self::Bar: Clone, - Self::Baz: Clone, -{ - type Bar = Vec; - type Baz = T; - //~^ ERROR the trait bound `T: Clone` is not satisfied -} diff --git a/tests/ui/traits/const-traits/const-assoc-bound-in-trait-wc.rs b/tests/ui/traits/const-traits/const-assoc-bound-in-trait-wc.rs new file mode 100644 index 000000000000..81acce65f2a9 --- /dev/null +++ b/tests/ui/traits/const-traits/const-assoc-bound-in-trait-wc.rs @@ -0,0 +1,13 @@ +//@ check-pass + +#![feature(const_clone)] +#![feature(const_trait_impl)] + +#[const_trait] +trait A where Self::Target: [const] Clone { + type Target; +} + +const fn foo() where T: [const] A {} + +fn main() {} From 8daf98b6236bed2db074b8e8beb7e3225201b71a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Jul 2025 16:26:13 +0000 Subject: [PATCH 131/363] Imply always-const host effects the same as any other item bound --- .../src/collect/item_bounds.rs | 1 + .../traits/const-traits/imply-always-const.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/ui/traits/const-traits/imply-always-const.rs diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 7e3fb5448f64..548ba343aaee 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -124,6 +124,7 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( ty::ClauseKind::Trait(tr) => tr.self_ty(), ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty(), ty::ClauseKind::TypeOutlives(outlives) => outlives.0, + ty::ClauseKind::HostEffect(host) => host.self_ty(), _ => return None, }; diff --git a/tests/ui/traits/const-traits/imply-always-const.rs b/tests/ui/traits/const-traits/imply-always-const.rs new file mode 100644 index 000000000000..f6cab0681ec2 --- /dev/null +++ b/tests/ui/traits/const-traits/imply-always-const.rs @@ -0,0 +1,19 @@ +//@ check-pass + +#![feature(const_trait_impl)] + +#[const_trait] +trait A where Self::Assoc: const B { + type Assoc; +} + +#[const_trait] +trait B {} + +fn needs_b() {} + +fn test() { + needs_b::(); +} + +fn main() {} From 56a82a2402e369ba999e88de125e27014f975f17 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 13 Jul 2025 16:14:30 -0400 Subject: [PATCH 132/363] Fix empty backtrace --- build_system/src/build.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 4033ffe0694a..94b40319f4a7 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -139,6 +139,9 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu rustflags.push_str(&cg_rustflags); } + args.push(&"--features"); + args.push(&"backtrace"); + let mut env = env.clone(); env.insert("RUSTFLAGS".to_string(), rustflags); let sysroot_dir = library_dir.join("sysroot"); From 623609e7132b80425e8661c9753bce78cab49bce Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 13 Jul 2025 16:34:14 -0400 Subject: [PATCH 133/363] Ignore failing test --- tests/failing-ui-tests.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index 544d0bfc7105..6979c04d5343 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -80,3 +80,5 @@ tests/ui/uninhabited/uninhabited-transparent-return-abi.rs tests/ui/coroutine/panic-drops-resume.rs tests/ui/coroutine/panic-drops.rs tests/ui/coroutine/panic-safe.rs +tests/ui/process/nofile-limit.rs +tests/ui/simd/intrinsic/generic-arithmetic-pass.rs From b01bbe06cc2fea18957895f2722d687b00efcbd7 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 13 Jul 2025 16:36:41 -0400 Subject: [PATCH 134/363] Fix no-f16-f128 feature name --- .github/workflows/m68k.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 4b67360df9df..176ee8628b09 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -82,14 +82,14 @@ jobs: - name: Build sample project with target defined as JSON spec run: | ./y.sh prepare --only-libcore --cross - ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json + ./y.sh build --sysroot --features compiler-builtins-no-f16-f128 --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ./y.sh cargo build --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json ./y.sh clean all - name: Build run: | ./y.sh prepare --only-libcore --cross - ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu + ./y.sh build --sysroot --features compiler-builtins-no-f16-f128 --target-triple m68k-unknown-linux-gnu ./y.sh test --mini-tests --target-triple m68k-unknown-linux-gnu CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu ./y.sh test --cargo-tests --target-triple m68k-unknown-linux-gnu ./y.sh clean all @@ -102,7 +102,7 @@ jobs: - name: Run tests run: | - ./y.sh test --target-triple m68k-unknown-linux-gnu --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }} + ./y.sh test --target-triple m68k-unknown-linux-gnu --release --clean --build-sysroot --sysroot-features compiler-builtins-no-f16-f128 ${{ matrix.commands }} - name: Run Hello World! run: | From b0ab2bf68efae0b1ccaa2a1ed643083d94756bae Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 13 Jul 2025 16:14:50 -0400 Subject: [PATCH 135/363] Fix LTO test --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1d8eaf9a141f..b0c552751e3e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,7 +78,7 @@ jobs: - name: Run tests run: | # FIXME(antoyo): we cannot enable LTO for stdarch tests currently because of some failing LTO tests using proc-macros. - echo -n 'lto = "fat"' >> build_system/build_sysroot/Cargo.toml + printf '[profile.release]\nlto = "fat"\n' >> build/build_sysroot/sysroot_src/library/sysroot/Cargo.toml EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot --keep-lto-tests ${{ matrix.commands }} - name: Run y.sh cargo build From 6760cd2859db68d47d62089d9805d860fb37d518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Sun, 13 Jul 2025 22:33:49 +0200 Subject: [PATCH 136/363] core: make `str::split_at_unchecked()` inline This PR adds `#[inline]` to the method `str::split_at_unchecked()`. This is done for two reasons: 1. The method is tiny, e.g. on AMD-64 (): ```asm movq %rdi, %rax subq %rcx, %rdx movq %rsi, (%rdi) addq %rcx, %rsi movq %rcx, 8(%rdi) movq %rsi, 16(%rdi) movq %rdx, 24(%rdi) retq ``` 2. More importantly, inlining the method enables further automatic optimizations. E.g. if you split at index 3, then in the compiler (rustc, llvm or both) knows that this code cannot fail, and the panicking path is omitted in the generated code: ```rust pub fn punctuation(i: &str) -> Result<(), ()> { const THREE_CHARS: &[[u8; 3]] = &[*b"<<=", *b">>=", *b"...", *b"..="]; if let Some((head, _)) = i.split_at_checked(3) && THREE_CHARS.contains(&head.as_bytes().try_into().unwrap()) { Ok(()) } else { Err(()) } } ```
Without PR ```asm playground::punctuation: subq $40, %rsp movq %rsi, %rdx movq %rdi, %rsi movb $1, %al cmpq $3, %rdx ja .LBB2_2 je .LBB2_3 .LBB2_11: addq $40, %rsp retq .LBB2_2: cmpb $-64, 3(%rsi) jl .LBB2_11 .LBB2_3: leaq 8(%rsp), %rdi movl $3, %ecx callq *core::str::::split_at_unchecked@GOTPCREL(%rip) movq 8(%rsp), %rcx movb $1, %al testq %rcx, %rcx je .LBB2_11 cmpq $3, 16(%rsp) jne .LBB2_12 movzwl (%rcx), %edx movzbl 2(%rcx), %ecx shll $16, %ecx orl %edx, %ecx cmpl $4013115, %ecx jg .LBB2_8 cmpl $3026478, %ecx je .LBB2_10 cmpl $4009518, %ecx je .LBB2_10 jmp .LBB2_11 .LBB2_8: cmpl $4013630, %ecx je .LBB2_10 cmpl $4013116, %ecx jne .LBB2_11 .LBB2_10: xorl %eax, %eax addq $40, %rsp retq .LBB2_12: leaq .Lanon.d98a7fbb86d10a97c24516e267466134.2(%rip), %rdi leaq .Lanon.d98a7fbb86d10a97c24516e267466134.1(%rip), %rcx leaq .Lanon.d98a7fbb86d10a97c24516e267466134.6(%rip), %r8 leaq 7(%rsp), %rdx movl $43, %esi callq *core::result::unwrap_failed@GOTPCREL(%rip) ```
With PR ```asm playground::punctuation: movb $1, %al cmpq $3, %rsi ja .LBB0_2 je .LBB0_3 .LBB0_9: retq .LBB0_2: cmpb $-64, 3(%rdi) jl .LBB0_9 .LBB0_3: movzwl (%rdi), %eax movzbl 2(%rdi), %ecx shll $16, %ecx orl %eax, %ecx movb $1, %al cmpl $4013115, %ecx jg .LBB0_6 cmpl $3026478, %ecx je .LBB0_8 cmpl $4009518, %ecx je .LBB0_8 jmp .LBB0_9 .LBB0_6: cmpl $4013630, %ecx je .LBB0_8 cmpl $4013116, %ecx jne .LBB0_9 .LBB0_8: xorl %eax, %eax retq ```
--- library/core/src/str/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 32a229881753..b1ce643e87cd 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -952,6 +952,7 @@ impl str { /// /// The caller must ensure that `mid` is a valid byte offset from the start /// of the string and falls on the boundary of a UTF-8 code point. + #[inline] const unsafe fn split_at_unchecked(&self, mid: usize) -> (&str, &str) { let len = self.len(); let ptr = self.as_ptr(); From b7d024b05622702df0b8f0eb7d67c9e7b534b9ea Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Mon, 14 Jul 2025 02:18:24 +0500 Subject: [PATCH 137/363] moved tests --- .../deduplicate-diagnostics.deduplicate.stderr | 0 .../deduplicate-diagnostics.duplicate.stderr | 0 tests/ui/{ => diagnostic-flags}/deduplicate-diagnostics.rs | 0 tests/ui/{log-poly.rs => fmt/println-debug-different-types.rs} | 0 tests/ui/{darwin-ld64.rs => linking/ld64-cross-compilation.rs} | 0 .../ui/{lexical-scopes.rs => shadowed/shadowing-generic-item.rs} | 0 .../shadowing-generic-item.stderr} | 0 .../struct-constructor-mangling.rs} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{ => diagnostic-flags}/deduplicate-diagnostics.deduplicate.stderr (100%) rename tests/ui/{ => diagnostic-flags}/deduplicate-diagnostics.duplicate.stderr (100%) rename tests/ui/{ => diagnostic-flags}/deduplicate-diagnostics.rs (100%) rename tests/ui/{log-poly.rs => fmt/println-debug-different-types.rs} (100%) rename tests/ui/{darwin-ld64.rs => linking/ld64-cross-compilation.rs} (100%) rename tests/ui/{lexical-scopes.rs => shadowed/shadowing-generic-item.rs} (100%) rename tests/ui/{lexical-scopes.stderr => shadowed/shadowing-generic-item.stderr} (100%) rename tests/ui/{struct-ctor-mangling.rs => symbol-names/struct-constructor-mangling.rs} (100%) diff --git a/tests/ui/deduplicate-diagnostics.deduplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr similarity index 100% rename from tests/ui/deduplicate-diagnostics.deduplicate.stderr rename to tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr diff --git a/tests/ui/deduplicate-diagnostics.duplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr similarity index 100% rename from tests/ui/deduplicate-diagnostics.duplicate.stderr rename to tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr diff --git a/tests/ui/deduplicate-diagnostics.rs b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs similarity index 100% rename from tests/ui/deduplicate-diagnostics.rs rename to tests/ui/diagnostic-flags/deduplicate-diagnostics.rs diff --git a/tests/ui/log-poly.rs b/tests/ui/fmt/println-debug-different-types.rs similarity index 100% rename from tests/ui/log-poly.rs rename to tests/ui/fmt/println-debug-different-types.rs diff --git a/tests/ui/darwin-ld64.rs b/tests/ui/linking/ld64-cross-compilation.rs similarity index 100% rename from tests/ui/darwin-ld64.rs rename to tests/ui/linking/ld64-cross-compilation.rs diff --git a/tests/ui/lexical-scopes.rs b/tests/ui/shadowed/shadowing-generic-item.rs similarity index 100% rename from tests/ui/lexical-scopes.rs rename to tests/ui/shadowed/shadowing-generic-item.rs diff --git a/tests/ui/lexical-scopes.stderr b/tests/ui/shadowed/shadowing-generic-item.stderr similarity index 100% rename from tests/ui/lexical-scopes.stderr rename to tests/ui/shadowed/shadowing-generic-item.stderr diff --git a/tests/ui/struct-ctor-mangling.rs b/tests/ui/symbol-names/struct-constructor-mangling.rs similarity index 100% rename from tests/ui/struct-ctor-mangling.rs rename to tests/ui/symbol-names/struct-constructor-mangling.rs From f5485e55644cea6395fb2196b915dee1b48f6427 Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Sun, 13 Jul 2025 23:24:27 +0100 Subject: [PATCH 138/363] docs(alloc::fmt): Make `type` optional, instead of matching the empty string --- library/alloc/src/fmt.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index 30f42050ac8a..d0ba9c398864 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -348,13 +348,13 @@ //! format := '{' [ argument ] [ ':' format_spec ] [ ws ] * '}' //! argument := integer | identifier //! -//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision]type +//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type] //! fill := character //! align := '<' | '^' | '>' //! sign := '+' | '-' //! width := count //! precision := count | '*' -//! type := '' | '?' | 'x?' | 'X?' | identifier +//! type := '?' | 'x?' | 'X?' | identifier //! count := parameter | integer //! parameter := argument '$' //! ``` From dbeb05cd2addf012e6c1e1ddea00a5e6fb8ca609 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Mon, 14 Jul 2025 05:00:14 +0000 Subject: [PATCH 139/363] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 0af6b8c6fc79..adf3f7389c68 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -32cd9114712a24010b0583624dc52ac302194128 +9c3064e131f4939cc95a29bb11413c49bbda1491 From 500b743f7ef8e38a0ad6154493a84c53e06ea888 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sun, 13 Jul 2025 12:11:37 +0200 Subject: [PATCH 140/363] tests: Test line debuginfo for linebreaked function parameters --- ...parameters-on-different-lines-debuginfo.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/codegen/fn-parameters-on-different-lines-debuginfo.rs diff --git a/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs b/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs new file mode 100644 index 000000000000..2097567f3227 --- /dev/null +++ b/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs @@ -0,0 +1,22 @@ +//! Make sure that line debuginfo of function parameters are correct even if +//! they are not on the same line. Regression test for +// . + +//@ compile-flags: -g -Copt-level=0 + +#[rustfmt::skip] // Having parameters on different lines is crucial for this test. +pub fn foo( + x_parameter_not_in_std: i32, + y_parameter_not_in_std: i32, +) -> i32 { + x_parameter_not_in_std + y_parameter_not_in_std +} + +fn main() { + foo(42, 43); // Ensure `wasm32-wasip1` keeps `foo()` (even if `-Copt-level=0`) +} + +// CHECK: !DILocalVariable(name: "x_parameter_not_in_std", arg: 1, +// CHECK-SAME: line: 9 +// CHECK: !DILocalVariable(name: "y_parameter_not_in_std", arg: 2, +// CHECK-SAME: line: 10 From 1cac8cbde98e7b15ad24fc96af4864cdd67b9c30 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Mon, 14 Jul 2025 03:39:24 +0800 Subject: [PATCH 141/363] Add test array-type-no-semi.rs Signed-off-by: xizheyin --- tests/ui/parser/recover/array-type-no-semi.rs | 18 ++++++ .../parser/recover/array-type-no-semi.stderr | 56 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 tests/ui/parser/recover/array-type-no-semi.rs create mode 100644 tests/ui/parser/recover/array-type-no-semi.stderr diff --git a/tests/ui/parser/recover/array-type-no-semi.rs b/tests/ui/parser/recover/array-type-no-semi.rs new file mode 100644 index 000000000000..ae5efbaf36ca --- /dev/null +++ b/tests/ui/parser/recover/array-type-no-semi.rs @@ -0,0 +1,18 @@ +// when the next token is not a semicolon, +// we should suggest to use semicolon if recovery is allowed +// See issue #143828 + +fn main() { + let x = 5; + let b: [i32, 5]; + //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + //~| ERROR expected value, found builtin type `i32` [E0423] + let a: [i32, ]; + //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + //~| ERROR expected value, found builtin type `i32` [E0423] + let c: [i32, x]; + //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + //~| ERROR expected value, found builtin type `i32` [E0423] + let e: [i32 5]; + //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `5` +} diff --git a/tests/ui/parser/recover/array-type-no-semi.stderr b/tests/ui/parser/recover/array-type-no-semi.stderr new file mode 100644 index 000000000000..84b7282b4fed --- /dev/null +++ b/tests/ui/parser/recover/array-type-no-semi.stderr @@ -0,0 +1,56 @@ +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + --> $DIR/array-type-no-semi.rs:7:16 + | +LL | let b: [i32, 5]; + | - ^ expected one of 7 possible tokens + | | + | while parsing the type for `b` + | help: use `=` if you meant to assign + +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + --> $DIR/array-type-no-semi.rs:10:16 + | +LL | let a: [i32, ]; + | - ^ expected one of 7 possible tokens + | | + | while parsing the type for `a` + | help: use `=` if you meant to assign + +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + --> $DIR/array-type-no-semi.rs:13:16 + | +LL | let c: [i32, x]; + | - ^ expected one of 7 possible tokens + | | + | while parsing the type for `c` + | help: use `=` if you meant to assign + +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `5` + --> $DIR/array-type-no-semi.rs:16:17 + | +LL | let e: [i32 5]; + | - ^ expected one of 7 possible tokens + | | + | while parsing the type for `e` + +error[E0423]: expected value, found builtin type `i32` + --> $DIR/array-type-no-semi.rs:7:13 + | +LL | let b: [i32, 5]; + | ^^^ not a value + +error[E0423]: expected value, found builtin type `i32` + --> $DIR/array-type-no-semi.rs:10:13 + | +LL | let a: [i32, ]; + | ^^^ not a value + +error[E0423]: expected value, found builtin type `i32` + --> $DIR/array-type-no-semi.rs:13:13 + | +LL | let c: [i32, x]; + | ^^^ not a value + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0423`. From d3d51b4fdbd6854da015f501e6566ca17cb023e5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:12:42 +0000 Subject: [PATCH 142/363] Avoid a bunch of unnecessary `unsafe` blocks in cg_llvm --- compiler/rustc_codegen_llvm/src/back/write.rs | 73 +++++++++---------- compiler/rustc_codegen_llvm/src/common.rs | 8 +- compiler/rustc_codegen_llvm/src/consts.rs | 12 ++- .../rustc_codegen_llvm/src/debuginfo/gdb.rs | 2 +- .../src/debuginfo/metadata.rs | 2 +- compiler/rustc_codegen_llvm/src/declare.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 6 +- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 10 +-- 8 files changed, 52 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 506286fc2559..313bf6d20a66 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -879,9 +879,7 @@ pub(crate) fn codegen( .generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name); let thin_bc = module.thin_lto_buffer.as_deref().expect("cannot find embedded bitcode"); - unsafe { - embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc); - } + embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc); } } @@ -945,7 +943,7 @@ pub(crate) fn codegen( // binaries. So we must clone the module to produce the asm output // if we are also producing object code. let llmod = if let EmitObj::ObjectCode(_) = config.emit_obj { - unsafe { llvm::LLVMCloneModule(llmod) } + llvm::LLVMCloneModule(llmod) } else { llmod }; @@ -1073,7 +1071,7 @@ pub(crate) fn bitcode_section_name(cgcx: &CodegenContext) -> } /// Embed the bitcode of an LLVM module for LTO in the LLVM module itself. -unsafe fn embed_bitcode( +fn embed_bitcode( cgcx: &CodegenContext, llcx: &llvm::Context, llmod: &llvm::Module, @@ -1115,43 +1113,40 @@ unsafe fn embed_bitcode( // Unfortunately, LLVM provides no way to set custom section flags. For ELF // and COFF we emit the sections using module level inline assembly for that // reason (see issue #90326 for historical background). - unsafe { - if cgcx.target_is_like_darwin - || cgcx.target_is_like_aix - || cgcx.target_arch == "wasm32" - || cgcx.target_arch == "wasm64" - { - // We don't need custom section flags, create LLVM globals. - let llconst = common::bytes_in_context(llcx, bitcode); - let llglobal = - llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module"); - llvm::set_initializer(llglobal, llconst); - llvm::set_section(llglobal, bitcode_section_name(cgcx)); - llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); - llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + if cgcx.target_is_like_darwin + || cgcx.target_is_like_aix + || cgcx.target_arch == "wasm32" + || cgcx.target_arch == "wasm64" + { + // We don't need custom section flags, create LLVM globals. + let llconst = common::bytes_in_context(llcx, bitcode); + let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module"); + llvm::set_initializer(llglobal, llconst); - let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); - let llglobal = - llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); - llvm::set_initializer(llglobal, llconst); - let section = if cgcx.target_is_like_darwin { - c"__LLVM,__cmdline" - } else if cgcx.target_is_like_aix { - c".info" - } else { - c".llvmcmd" - }; - llvm::set_section(llglobal, section); - llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::set_section(llglobal, bitcode_section_name(cgcx)); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + + let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); + let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); + llvm::set_initializer(llglobal, llconst); + let section = if cgcx.target_is_like_darwin { + c"__LLVM,__cmdline" + } else if cgcx.target_is_like_aix { + c".info" } else { - // We need custom section flags, so emit module-level inline assembly. - let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; - let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); - llvm::append_module_inline_asm(llmod, &asm); - let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); - llvm::append_module_inline_asm(llmod, &asm); - } + c".llvmcmd" + }; + llvm::set_section(llglobal, section); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + } else { + // We need custom section flags, so emit module-level inline assembly. + let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; + let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); + llvm::append_module_inline_asm(llmod, &asm); + let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); + llvm::append_module_inline_asm(llmod, &asm); } } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index b9b5c776d86a..f9ab96b57895 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -215,10 +215,10 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { bug!("symbol `{}` is already defined", sym); }); llvm::set_initializer(g, sc); - unsafe { - llvm::LLVMSetGlobalConstant(g, True); - llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); - } + + llvm::set_global_constant(g, true); + llvm::set_unnamed_address(g, llvm::UnnamedAddr::Global); + llvm::set_linkage(g, llvm::Linkage::InternalLinkage); // Cast to default address space if globals are in a different addrspace let g = self.const_pointercast(g, self.type_ptr()); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 5deddb3ed981..070a9b64486f 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -19,11 +19,10 @@ use tracing::{debug, instrument, trace}; use crate::common::{AsCCharPtr, CodegenCx}; use crate::errors::SymbolAlreadyDefined; -use crate::llvm::{self, True}; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; -use crate::{base, debuginfo}; +use crate::{base, debuginfo, llvm}; pub(crate) fn const_alloc_to_llvm<'ll>( cx: &CodegenCx<'ll, '_>, @@ -247,7 +246,7 @@ impl<'ll> CodegenCx<'ll, '_> { }; llvm::set_initializer(gv, cv); set_global_alignment(self, gv, align); - llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); + llvm::set_unnamed_address(gv, llvm::UnnamedAddr::Global); gv } @@ -272,9 +271,8 @@ impl<'ll> CodegenCx<'ll, '_> { return gv; } let gv = self.static_addr_of_mut(cv, align, kind); - unsafe { - llvm::LLVMSetGlobalConstant(gv, True); - } + llvm::set_global_constant(gv, true); + self.const_globals.borrow_mut().insert(cv, gv); gv } @@ -465,7 +463,7 @@ impl<'ll> CodegenCx<'ll, '_> { // Forward the allocation's mutability (picked by the const interner) to LLVM. if alloc.mutability.is_not() { - llvm::LLVMSetGlobalConstant(g, llvm::True); + llvm::set_global_constant(g, true); } debuginfo::build_global_var_di_node(self, def_id, g); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 8f0948b8183b..3e04dac6cd68 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -75,7 +75,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( llvm::set_section(section_var, c".debug_gdb_scripts"); llvm::set_initializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); - llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global); + llvm::set_unnamed_address(section_var, llvm::UnnamedAddr::Global); llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage); // This should make sure that the whole section is not larger than // the string it contains. Otherwise we get a warning from GDB. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 9b4736e50e6c..1a50fb5823b2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1630,7 +1630,7 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>( // When full debuginfo is enabled, we want to try and prevent vtables from being // merged. Otherwise debuggers will have a hard time mapping from dyn pointer // to concrete type. - llvm::SetUnnamedAddress(vtable, llvm::UnnamedAddr::No); + llvm::set_unnamed_address(vtable, llvm::UnnamedAddr::No); let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable); diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 2419ec1f8885..710032c774b5 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -49,7 +49,7 @@ pub(crate) fn declare_simple_fn<'ll>( }; llvm::SetFunctionCallConv(llfn, callconv); - llvm::SetUnnamedAddress(llfn, unnamed); + llvm::set_unnamed_address(llfn, unnamed); llvm::set_visibility(llfn, visibility); llfn diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 5c34ab2e3040..2af57e22cd5b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1009,7 +1009,7 @@ unsafe extern "C" { ModuleID: *const c_char, C: &Context, ) -> &Module; - pub(crate) fn LLVMCloneModule(M: &Module) -> &Module; + pub(crate) safe fn LLVMCloneModule(M: &Module) -> &Module; /// Data layout. See Module::getDataLayout. pub(crate) fn LLVMGetDataLayoutStr(M: &Module) -> *const c_char; @@ -1179,7 +1179,7 @@ unsafe extern "C" { pub(crate) fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; - pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); + pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); // Operations on attributes @@ -1718,7 +1718,7 @@ unsafe extern "C" { pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; - pub(crate) fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); + pub(crate) safe fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); pub(crate) fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>; diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 3fc83fca352a..154ba4fd6901 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -217,10 +217,8 @@ pub(crate) fn SetUniqueComdat(llmod: &Module, val: &Value) { set_comdat(llmod, val, &name); } -pub(crate) fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) { - unsafe { - LLVMSetUnnamedAddress(global, unnamed); - } +pub(crate) fn set_unnamed_address(global: &Value, unnamed: UnnamedAddr) { + LLVMSetUnnamedAddress(global, unnamed); } pub(crate) fn set_thread_local_mode(global: &Value, mode: ThreadLocalMode) { @@ -260,9 +258,7 @@ pub(crate) fn set_initializer(llglobal: &Value, constant_val: &Value) { } pub(crate) fn set_global_constant(llglobal: &Value, is_constant: bool) { - unsafe { - LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False }); - } + LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False }); } pub(crate) fn get_linkage(llglobal: &Value) -> Linkage { From e574fef728605089da8144960348469896751c3c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:23:05 +0000 Subject: [PATCH 143/363] Shrink some `unsafe` blocks in cg_llvm --- compiler/rustc_codegen_llvm/src/builder.rs | 13 +- compiler/rustc_codegen_llvm/src/consts.rs | 231 +++++++++---------- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 8 +- compiler/rustc_codegen_llvm/src/mono_item.rs | 4 +- 4 files changed, 127 insertions(+), 129 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 9c3b866aa3c6..7304460c4930 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -637,17 +637,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } else if place.layout.is_llvm_immediate() { let mut const_llval = None; let llty = place.layout.llvm_type(self); - unsafe { - if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) { - if llvm::LLVMIsGlobalConstant(global) == llvm::True { - if let Some(init) = llvm::LLVMGetInitializer(global) { - if self.val_ty(init) == llty { - const_llval = Some(init); - } + if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) { + if llvm::LLVMIsGlobalConstant(global) == llvm::True { + if let Some(init) = llvm::LLVMGetInitializer(global) { + if self.val_ty(init) == llty { + const_llval = Some(init); } } } } + let llval = const_llval.unwrap_or_else(|| { let load = self.load(llty, place.val.llval, place.val.align); if let abi::BackendRepr::Scalar(scalar) = place.layout.backend_repr { diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 070a9b64486f..27f6a1197270 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -396,149 +396,148 @@ impl<'ll> CodegenCx<'ll, '_> { } fn codegen_static_item(&mut self, def_id: DefId) { - unsafe { - assert!( - llvm::LLVMGetInitializer( - self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap() - ) - .is_none() - ); - let attrs = self.tcx.codegen_fn_attrs(def_id); + assert!( + llvm::LLVMGetInitializer( + self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap() + ) + .is_none() + ); + let attrs = self.tcx.codegen_fn_attrs(def_id); - let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else { - // Error has already been reported - return; - }; - let alloc = alloc.inner(); + let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else { + // Error has already been reported + return; + }; + let alloc = alloc.inner(); - let val_llty = self.val_ty(v); + let val_llty = self.val_ty(v); - let g = self.get_static_inner(def_id, val_llty); - let llty = self.get_type_of_global(g); + let g = self.get_static_inner(def_id, val_llty); + let llty = self.get_type_of_global(g); - let g = if val_llty == llty { - g - } else { - // codegen_static_initializer creates the global value just from the - // `Allocation` data by generating one big struct value that is just - // all the bytes and pointers after each other. This will almost never - // match the type that the static was declared with. Unfortunately - // we can't just LLVMConstBitCast our way out of it because that has very - // specific rules on what can be cast. So instead of adding a new way to - // generate static initializers that match the static's type, we picked - // the easier option and retroactively change the type of the static item itself. - let name = llvm::get_value_name(g); - llvm::set_value_name(g, b""); + let g = if val_llty == llty { + g + } else { + // codegen_static_initializer creates the global value just from the + // `Allocation` data by generating one big struct value that is just + // all the bytes and pointers after each other. This will almost never + // match the type that the static was declared with. Unfortunately + // we can't just LLVMConstBitCast our way out of it because that has very + // specific rules on what can be cast. So instead of adding a new way to + // generate static initializers that match the static's type, we picked + // the easier option and retroactively change the type of the static item itself. + let name = String::from_utf8(llvm::get_value_name(g)) + .expect("we declare our statics with a utf8-valid name"); + llvm::set_value_name(g, b""); - let linkage = llvm::get_linkage(g); - let visibility = llvm::get_visibility(g); + let linkage = llvm::get_linkage(g); + let visibility = llvm::get_visibility(g); - let new_g = llvm::LLVMRustGetOrInsertGlobal( - self.llmod, - name.as_c_char_ptr(), - name.len(), - val_llty, - ); + let new_g = self.declare_global(&name, val_llty); - llvm::set_linkage(new_g, linkage); - llvm::set_visibility(new_g, visibility); + llvm::set_linkage(new_g, linkage); + llvm::set_visibility(new_g, visibility); - // The old global has had its name removed but is returned by - // get_static since it is in the instance cache. Provide an - // alternative lookup that points to the new global so that - // global_asm! can compute the correct mangled symbol name - // for the global. - self.renamed_statics.borrow_mut().insert(def_id, new_g); + // The old global has had its name removed but is returned by + // get_static since it is in the instance cache. Provide an + // alternative lookup that points to the new global so that + // global_asm! can compute the correct mangled symbol name + // for the global. + self.renamed_statics.borrow_mut().insert(def_id, new_g); - // To avoid breaking any invariants, we leave around the old - // global for the moment; we'll replace all references to it - // with the new global later. (See base::codegen_backend.) - self.statics_to_rauw.borrow_mut().push((g, new_g)); - new_g - }; - set_global_alignment(self, g, alloc.align); - llvm::set_initializer(g, v); + // To avoid breaking any invariants, we leave around the old + // global for the moment; we'll replace all references to it + // with the new global later. (See base::codegen_backend.) + self.statics_to_rauw.borrow_mut().push((g, new_g)); + new_g + }; + set_global_alignment(self, g, alloc.align); + llvm::set_initializer(g, v); - self.assume_dso_local(g, true); + self.assume_dso_local(g, true); - // Forward the allocation's mutability (picked by the const interner) to LLVM. - if alloc.mutability.is_not() { - llvm::set_global_constant(g, true); - } + // Forward the allocation's mutability (picked by the const interner) to LLVM. + if alloc.mutability.is_not() { + llvm::set_global_constant(g, true); + } - debuginfo::build_global_var_di_node(self, def_id, g); + debuginfo::build_global_var_di_node(self, def_id, g); - if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { - llvm::set_thread_local_mode(g, self.tls_model); - } + if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { + llvm::set_thread_local_mode(g, self.tls_model); + } - // Wasm statics with custom link sections get special treatment as they - // go into custom sections of the wasm executable. The exception to this - // is the `.init_array` section which are treated specially by the wasm linker. - if self.tcx.sess.target.is_like_wasm - && attrs - .link_section - .map(|link_section| !link_section.as_str().starts_with(".init_array")) - .unwrap_or(true) - { - if let Some(section) = attrs.link_section { - let section = llvm::LLVMMDStringInContext2( + // Wasm statics with custom link sections get special treatment as they + // go into custom sections of the wasm executable. The exception to this + // is the `.init_array` section which are treated specially by the wasm linker. + if self.tcx.sess.target.is_like_wasm + && attrs + .link_section + .map(|link_section| !link_section.as_str().starts_with(".init_array")) + .unwrap_or(true) + { + if let Some(section) = attrs.link_section { + let section = unsafe { + llvm::LLVMMDStringInContext2( self.llcx, section.as_str().as_c_char_ptr(), section.as_str().len(), - ); - assert!(alloc.provenance().ptrs().is_empty()); + ) + }; + assert!(alloc.provenance().ptrs().is_empty()); - // The `inspect` method is okay here because we checked for provenance, and - // because we are doing this access to inspect the final interpreter state (not - // as part of the interpreter execution). - let bytes = - alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); - let alloc = - llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()); - let data = [section, alloc]; - let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()); - let val = self.get_metadata_value(meta); + // The `inspect` method is okay here because we checked for provenance, and + // because we are doing this access to inspect the final interpreter state (not + // as part of the interpreter execution). + let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); + let alloc = unsafe { + llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()) + }; + let data = [section, alloc]; + let meta = + unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) }; + let val = self.get_metadata_value(meta); + unsafe { llvm::LLVMAddNamedMetadataOperand( self.llmod, c"wasm.custom_sections".as_ptr(), val, - ); - } - } else { - base::set_link_section(g, attrs); + ) + }; } + } else { + base::set_link_section(g, attrs); + } - base::set_variable_sanitizer_attrs(g, attrs); + base::set_variable_sanitizer_attrs(g, attrs); - if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) { - // `USED` and `USED_LINKER` can't be used together. - assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); + if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); - // The semantics of #[used] in Rust only require the symbol to make it into the - // object file. It is explicitly allowed for the linker to strip the symbol if it - // is dead, which means we are allowed to use `llvm.compiler.used` instead of - // `llvm.used` here. - // - // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique - // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs - // in the handling of `.init_array` (the static constructor list) in versions of - // the gold linker (prior to the one released with binutils 2.36). - // - // That said, we only ever emit these when `#[used(compiler)]` is explicitly - // requested. This is to avoid similar breakage on other targets, in particular - // MachO targets have *their* static constructor lists broken if `llvm.compiler.used` - // is emitted rather than `llvm.used`. However, that check happens when assigning - // the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to - // take care of it here. - self.add_compiler_used_global(g); - } - if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { - // `USED` and `USED_LINKER` can't be used together. - assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)); + // The semantics of #[used] in Rust only require the symbol to make it into the + // object file. It is explicitly allowed for the linker to strip the symbol if it + // is dead, which means we are allowed to use `llvm.compiler.used` instead of + // `llvm.used` here. + // + // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique + // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs + // in the handling of `.init_array` (the static constructor list) in versions of + // the gold linker (prior to the one released with binutils 2.36). + // + // That said, we only ever emit these when `#[used(compiler)]` is explicitly + // requested. This is to avoid similar breakage on other targets, in particular + // MachO targets have *their* static constructor lists broken if `llvm.compiler.used` + // is emitted rather than `llvm.used`. However, that check happens when assigning + // the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to + // take care of it here. + self.add_compiler_used_global(g); + } + if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)); - self.add_used_global(g); - } + self.add_used_global(g); } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 2af57e22cd5b..0b1e632cbc42 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1168,17 +1168,17 @@ unsafe extern "C" { pub(crate) fn LLVMGlobalGetValueType(Global: &Value) -> &Type; // Operations on global variables - pub(crate) fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>; + pub(crate) safe fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMAddGlobal<'a>(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value; pub(crate) fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>; pub(crate) fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>; pub(crate) fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMDeleteGlobal(GlobalVar: &Value); - pub(crate) fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>; + pub(crate) safe fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMSetInitializer<'a>(GlobalVar: &'a Value, ConstantVal: &'a Value); - pub(crate) fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; + pub(crate) safe fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); - pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; + pub(crate) safe fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 3f38e1e191bf..8f70270f203e 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -131,8 +131,8 @@ impl CodegenCx<'_, '_> { } // Thread-local variables generally don't support copy relocations. - let is_thread_local_var = unsafe { llvm::LLVMIsAGlobalVariable(llval) } - .is_some_and(|v| unsafe { llvm::LLVMIsThreadLocal(v) } == llvm::True); + let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval) + .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True); if is_thread_local_var { return false; } From b9baf63f99bbdf69571e26fca907af032c416591 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:31:58 +0000 Subject: [PATCH 144/363] Merge `typeid_metadata` and `create_metadata` --- compiler/rustc_codegen_llvm/src/builder.rs | 2 +- .../rustc_codegen_llvm/src/builder/autodiff.rs | 16 ++++++++-------- compiler/rustc_codegen_llvm/src/context.rs | 7 ++++--- compiler/rustc_codegen_llvm/src/type_.rs | 10 ++++------ 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 7304460c4930..4c5bc8430cc7 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1720,7 +1720,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } else { cfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; - let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap(); + let typeid_metadata = self.cx.create_metadata(typeid); let dbg_loc = self.get_dbg_loc(); // Test whether the function pointer is associated with the type identifier using the diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 5afb9a60d424..9383903fd022 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -76,12 +76,12 @@ fn match_args_from_caller_to_enzyme<'ll>( outer_pos = 1; } - let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap(); - let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap(); - let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap(); - let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()).unwrap(); - let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap(); - let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()).unwrap(); + let enzyme_const = cx.create_metadata("enzyme_const".to_string()); + let enzyme_out = cx.create_metadata("enzyme_out".to_string()); + let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()); + let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()); + let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()); + let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()); while activity_pos < inputs.len() { let diff_activity = inputs[activity_pos as usize]; @@ -378,12 +378,12 @@ fn generate_enzyme_call<'ll>( let mut args = Vec::with_capacity(num_args as usize + 1); args.push(fn_to_diff); - let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap(); + let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()); if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) { args.push(cx.get_metadata_value(enzyme_primal_ret)); } if attrs.width > 1 { - let enzyme_width = cx.create_metadata("enzyme_width".to_string()).unwrap(); + let enzyme_width = cx.create_metadata("enzyme_width".to_string()); args.push(cx.get_metadata_value(enzyme_width)); args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 90582e23b04c..5616c4d4e457 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -473,6 +473,7 @@ pub(crate) unsafe fn create_module<'ll>( #[allow(clippy::option_env_unwrap)] let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); + let name_metadata = unsafe { llvm::LLVMMDStringInContext2( llcx, @@ -698,10 +699,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { } } - pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> { - Some(unsafe { + pub(crate) fn create_metadata(&self, name: String) -> &'ll Metadata { + unsafe { llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len()) - }) + } } pub(crate) fn get_functions(&self) -> Vec<&'ll Value> { diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index ee472e75ed41..5b19ca91e4d1 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -2,7 +2,7 @@ use std::borrow::Borrow; use std::hash::{Hash, Hasher}; use std::{fmt, ptr}; -use libc::{c_char, c_uint}; +use libc::c_uint; use rustc_abi::{AddressSpace, Align, Integer, Reg, Size}; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; @@ -299,7 +299,7 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn add_type_metadata(&self, function: &'ll Value, typeid: String) { - let typeid_metadata = self.typeid_metadata(typeid).unwrap(); + let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMRustGlobalAddMetadata( @@ -311,7 +311,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn set_type_metadata(&self, function: &'ll Value, typeid: String) { - let typeid_metadata = self.typeid_metadata(typeid).unwrap(); + let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMGlobalSetMetadata( @@ -323,9 +323,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn typeid_metadata(&self, typeid: String) -> Option<&'ll Metadata> { - Some(unsafe { - llvm::LLVMMDStringInContext2(self.llcx, typeid.as_ptr() as *const c_char, typeid.len()) - }) + Some(self.create_metadata(typeid)) } fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) { From 56d22cd29ff6d3ea1fa8972462ad94792960b1ef Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:36:19 +0000 Subject: [PATCH 145/363] Use context methods instead of directly calling FFI --- compiler/rustc_codegen_llvm/src/builder.rs | 4 +--- compiler/rustc_codegen_llvm/src/consts.rs | 8 +------- compiler/rustc_codegen_llvm/src/context.rs | 14 +++++--------- .../rustc_codegen_llvm/src/debuginfo/metadata.rs | 8 ++------ 4 files changed, 9 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 4c5bc8430cc7..3c64cb79d5e1 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -303,9 +303,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } let id_str = "branch_weights"; - let id = unsafe { - llvm::LLVMMDStringInContext2(self.cx.llcx, id_str.as_ptr().cast(), id_str.len()) - }; + let id = self.cx.create_metadata(id_str.into()); // For switch instructions with 2 targets, the `llvm.expect` intrinsic is used. // This function handles switch instructions with more than 2 targets and it needs to diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 27f6a1197270..40e686b253cf 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -477,13 +477,7 @@ impl<'ll> CodegenCx<'ll, '_> { .unwrap_or(true) { if let Some(section) = attrs.link_section { - let section = unsafe { - llvm::LLVMMDStringInContext2( - self.llcx, - section.as_str().as_c_char_ptr(), - section.as_str().len(), - ) - }; + let section = self.create_metadata(section.as_str().into()); assert!(alloc.provenance().ptrs().is_empty()); // The `inspect` method is okay here because we checked for provenance, and diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 5616c4d4e457..51ba3fb8089b 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -34,7 +34,6 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; -use crate::common::AsCCharPtr; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; use crate::llvm::Metadata; use crate::type_::Type; @@ -169,6 +168,8 @@ pub(crate) unsafe fn create_module<'ll>( let mod_name = SmallCStr::new(mod_name); let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) }; + let cx = SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size()); + let mut target_data_layout = sess.target.data_layout.to_string(); let llvm_version = llvm_util::get_version(); @@ -474,18 +475,13 @@ pub(crate) unsafe fn create_module<'ll>( let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); - let name_metadata = unsafe { - llvm::LLVMMDStringInContext2( - llcx, - rustc_producer.as_c_char_ptr(), - rustc_producer.as_bytes().len(), - ) - }; + let name_metadata = cx.create_metadata(rustc_producer); + unsafe { llvm::LLVMAddNamedMetadataOperand( llmod, c"llvm.ident".as_ptr(), - &llvm::LLVMMetadataAsValue(llcx, llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), + &cx.get_metadata_value(llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), ); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1a50fb5823b2..3fdf4e19d588 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use std::{iter, ptr}; -use libc::{c_char, c_longlong, c_uint}; +use libc::{c_longlong, c_uint}; use rustc_abi::{Align, Size}; use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo}; use rustc_codegen_ssa::traits::*; @@ -1582,13 +1582,9 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( }; let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref); + let typeid = cx.create_metadata(trait_ref_typeid); unsafe { - let typeid = llvm::LLVMMDStringInContext2( - cx.llcx, - trait_ref_typeid.as_ptr() as *const c_char, - trait_ref_typeid.as_bytes().len(), - ); let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; llvm::LLVMRustGlobalAddMetadata( vtable, From 7f95f042677f86df55da58cdebe9ce31a1e928a8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:48:46 +0000 Subject: [PATCH 146/363] Eliminate all direct uses of LLVMMDStringInContext2 --- compiler/rustc_codegen_llvm/src/builder.rs | 5 ++--- .../rustc_codegen_llvm/src/builder/autodiff.rs | 16 ++++++++-------- compiler/rustc_codegen_llvm/src/consts.rs | 8 +++----- compiler/rustc_codegen_llvm/src/context.rs | 4 ++-- .../rustc_codegen_llvm/src/debuginfo/metadata.rs | 2 +- compiler/rustc_codegen_llvm/src/declare.rs | 4 ++-- compiler/rustc_codegen_llvm/src/type_.rs | 6 +++--- compiler/rustc_codegen_ssa/src/meth.rs | 3 ++- compiler/rustc_codegen_ssa/src/traits/type_.rs | 6 +++--- 9 files changed, 26 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 3c64cb79d5e1..514923ad6f37 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -302,8 +302,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { return; } - let id_str = "branch_weights"; - let id = self.cx.create_metadata(id_str.into()); + let id = self.cx.create_metadata(b"branch_weights"); // For switch instructions with 2 targets, the `llvm.expect` intrinsic is used. // This function handles switch instructions with more than 2 targets and it needs to @@ -1718,7 +1717,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } else { cfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; - let typeid_metadata = self.cx.create_metadata(typeid); + let typeid_metadata = self.cx.create_metadata(typeid.as_bytes()); let dbg_loc = self.get_dbg_loc(); // Test whether the function pointer is associated with the type identifier using the diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 9383903fd022..dff684728473 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -76,12 +76,12 @@ fn match_args_from_caller_to_enzyme<'ll>( outer_pos = 1; } - let enzyme_const = cx.create_metadata("enzyme_const".to_string()); - let enzyme_out = cx.create_metadata("enzyme_out".to_string()); - let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()); - let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()); - let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()); - let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()); + let enzyme_const = cx.create_metadata(b"enzyme_const"); + let enzyme_out = cx.create_metadata(b"enzyme_out"); + let enzyme_dup = cx.create_metadata(b"enzyme_dup"); + let enzyme_dupv = cx.create_metadata(b"enzyme_dupv"); + let enzyme_dupnoneed = cx.create_metadata(b"enzyme_dupnoneed"); + let enzyme_dupnoneedv = cx.create_metadata(b"enzyme_dupnoneedv"); while activity_pos < inputs.len() { let diff_activity = inputs[activity_pos as usize]; @@ -378,12 +378,12 @@ fn generate_enzyme_call<'ll>( let mut args = Vec::with_capacity(num_args as usize + 1); args.push(fn_to_diff); - let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()); + let enzyme_primal_ret = cx.create_metadata(b"enzyme_primal_return"); if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) { args.push(cx.get_metadata_value(enzyme_primal_ret)); } if attrs.width > 1 { - let enzyme_width = cx.create_metadata("enzyme_width".to_string()); + let enzyme_width = cx.create_metadata(b"enzyme_width"); args.push(cx.get_metadata_value(enzyme_width)); args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 40e686b253cf..0b96b63bc857 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::{self, Instance}; use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument, trace}; -use crate::common::{AsCCharPtr, CodegenCx}; +use crate::common::CodegenCx; use crate::errors::SymbolAlreadyDefined; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; @@ -477,16 +477,14 @@ impl<'ll> CodegenCx<'ll, '_> { .unwrap_or(true) { if let Some(section) = attrs.link_section { - let section = self.create_metadata(section.as_str().into()); + let section = self.create_metadata(section.as_str().as_bytes()); assert!(alloc.provenance().ptrs().is_empty()); // The `inspect` method is okay here because we checked for provenance, and // because we are doing this access to inspect the final interpreter state (not // as part of the interpreter execution). let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); - let alloc = unsafe { - llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()) - }; + let alloc = self.create_metadata(bytes); let data = [section, alloc]; let meta = unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) }; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 51ba3fb8089b..6a23becaa96f 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -475,7 +475,7 @@ pub(crate) unsafe fn create_module<'ll>( let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); - let name_metadata = cx.create_metadata(rustc_producer); + let name_metadata = cx.create_metadata(rustc_producer.as_bytes()); unsafe { llvm::LLVMAddNamedMetadataOperand( @@ -695,7 +695,7 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { } } - pub(crate) fn create_metadata(&self, name: String) -> &'ll Metadata { + pub(crate) fn create_metadata(&self, name: &[u8]) -> &'ll Metadata { unsafe { llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len()) } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 3fdf4e19d588..0e9dbfba658d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1582,7 +1582,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( }; let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref); - let typeid = cx.create_metadata(trait_ref_typeid); + let typeid = cx.create_metadata(trait_ref_typeid.as_bytes()); unsafe { let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 710032c774b5..eb75716d768b 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -176,7 +176,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { { let typeid = cfi::typeid_for_instance(self.tcx, instance, options); if typeids.insert(typeid.clone()) { - self.add_type_metadata(llfn, typeid); + self.add_type_metadata(llfn, typeid.as_bytes()); } } } else { @@ -189,7 +189,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { .map(cfi::TypeIdOptions::from_iter) { let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options); - self.add_type_metadata(llfn, typeid); + self.add_type_metadata(llfn, typeid.as_bytes()); } } } diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 5b19ca91e4d1..893655031388 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -298,7 +298,7 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn add_type_metadata(&self, function: &'ll Value, typeid: String) { + fn add_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; @@ -310,7 +310,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn set_type_metadata(&self, function: &'ll Value, typeid: String) { + fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; @@ -322,7 +322,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn typeid_metadata(&self, typeid: String) -> Option<&'ll Metadata> { + fn typeid_metadata(&self, typeid: &[u8]) -> Option<&'ll Metadata> { Some(self.create_metadata(typeid)) } diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 2aa5c3c27ea5..34ad35a729b9 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -139,7 +139,8 @@ pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( && bx.cx().sess().lto() == Lto::Fat { if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) { - let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap(); + let typeid = + bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref).as_bytes()).unwrap(); let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid); return func; } else if nonnull { diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index dcd9e25b2c95..32c24965e1bf 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -154,9 +154,9 @@ pub trait LayoutTypeCodegenMethods<'tcx>: BackendTypes { // For backends that support CFI using type membership (i.e., testing whether a given pointer is // associated with a type identifier). pub trait TypeMembershipCodegenMethods<'tcx>: BackendTypes { - fn add_type_metadata(&self, _function: Self::Function, _typeid: String) {} - fn set_type_metadata(&self, _function: Self::Function, _typeid: String) {} - fn typeid_metadata(&self, _typeid: String) -> Option { + fn add_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {} + fn set_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {} + fn typeid_metadata(&self, _typeid: &[u8]) -> Option { None } fn add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {} From eef08a3f440967d72bf0e8ef8f3c7571abb64738 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 10 Jul 2025 14:55:07 +0000 Subject: [PATCH 147/363] Give all bytes of TypeId provenance --- .../src/interpret/intrinsics.rs | 70 ++++++++++--------- tests/ui/consts/const_transmute_type_id3.rs | 5 +- .../ui/consts/const_transmute_type_id3.stderr | 4 +- tests/ui/consts/const_transmute_type_id5.rs | 21 ++++++ .../ui/consts/const_transmute_type_id5.stderr | 15 ++++ 5 files changed, 80 insertions(+), 35 deletions(-) create mode 100644 tests/ui/consts/const_transmute_type_id5.rs create mode 100644 tests/ui/consts/const_transmute_type_id5.stderr diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 1eba1f2f03c9..22d29eda913a 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -44,17 +44,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { )?; self.copy_op_allow_transmute(&op, dest)?; - // Give the first pointer-size bytes provenance that knows about the type id. + // Give the each pointer-sized chunk provenance that knows about the type id. // Here we rely on `TypeId` being a newtype around an array of pointers, so we - // first project to its only field and then the first array element. + // first project to its only field and then the array elements. let alloc_id = tcx.reserve_and_set_type_id_alloc(ty); let first = self.project_field(dest, FieldIdx::ZERO)?; - let first = self.project_index(&first, 0)?; - let offset = self.read_scalar(&first)?.to_target_usize(&tcx)?; - let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(offset)); - let ptr = self.global_root_pointer(ptr)?; - let val = Scalar::from_pointer(ptr, &tcx); - self.write_scalar(val, &first) + let mut elem_iter = self.project_array_fields(&first)?; + while let Some((_, elem)) = elem_iter.next(self)? { + // Decorate this part of the hash with provenance; leave the integer part unchanged. + let hash_fragment = self.read_scalar(&elem)?.to_target_usize(&tcx)?; + let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(hash_fragment)); + let ptr = self.global_root_pointer(ptr)?; + let val = Scalar::from_pointer(ptr, &tcx); + self.write_scalar(val, &elem)?; + } + interp_ok(()) } /// Returns `true` if emulation happened. @@ -101,34 +105,36 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let mut a_fields = self.project_array_fields(&a_fields)?; let mut b_fields = self.project_array_fields(&b_fields)?; - let (_idx, a) = a_fields - .next(self)? - .expect("we know the layout of TypeId has at least 2 array elements"); - let a = self.deref_pointer(&a)?; - let (a, offset_a) = self.get_ptr_type_id(a.ptr())?; + let mut provenance_a = None; + let mut provenance_b = None; + let mut provenance_matches = true; - let (_idx, b) = b_fields - .next(self)? - .expect("we know the layout of TypeId has at least 2 array elements"); - let b = self.deref_pointer(&b)?; - let (b, offset_b) = self.get_ptr_type_id(b.ptr())?; - - let provenance_matches = a == b; - - let mut eq_id = offset_a == offset_b; - - while let Some((_, a)) = a_fields.next(self)? { + while let Some((i, a)) = a_fields.next(self)? { let (_, b) = b_fields.next(self)?.unwrap(); - let a = self.read_target_usize(&a)?; - let b = self.read_target_usize(&b)?; - eq_id &= a == b; - } + let a = self.deref_pointer(&a)?; + let (a, offset_a) = self.get_ptr_type_id(a.ptr())?; - if !eq_id && provenance_matches { - throw_ub_format!( - "type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents" - ) + let b = self.deref_pointer(&b)?; + let (b, offset_b) = self.get_ptr_type_id(b.ptr())?; + + if *provenance_a.get_or_insert(a) != a { + throw_ub_format!( + "type_id_eq: the first TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's" + ) + } + if *provenance_b.get_or_insert(b) != b { + throw_ub_format!( + "type_id_eq: the second TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's" + ) + } + provenance_matches &= a == b; + + if offset_a != offset_b && provenance_matches { + throw_ub_format!( + "type_id_eq: one of the TypeId arguments is invalid, chunk {i} of the hash does not match the type it represents" + ) + } } self.write_scalar(Scalar::from_bool(provenance_matches), dest)?; diff --git a/tests/ui/consts/const_transmute_type_id3.rs b/tests/ui/consts/const_transmute_type_id3.rs index ed5ff769701f..f1bb8cddf774 100644 --- a/tests/ui/consts/const_transmute_type_id3.rs +++ b/tests/ui/consts/const_transmute_type_id3.rs @@ -1,3 +1,6 @@ +//! Test that all bytes of a TypeId must have the +//! TypeId marker provenance. + #![feature(const_type_id, const_trait_impl, const_cmp)] use std::any::TypeId; @@ -10,7 +13,7 @@ const _: () = { std::ptr::write(ptr.offset(1), 999); } assert!(a == b); - //~^ ERROR: one of the TypeId arguments is invalid, the hash does not match the type it represents + //~^ ERROR: pointer must point to some allocation }; fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id3.stderr b/tests/ui/consts/const_transmute_type_id3.stderr index 8cfdcfebaa4c..e731f496652e 100644 --- a/tests/ui/consts/const_transmute_type_id3.stderr +++ b/tests/ui/consts/const_transmute_type_id3.stderr @@ -1,5 +1,5 @@ -error[E0080]: type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents - --> $DIR/const_transmute_type_id3.rs:12:13 +error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got 0x3e7[noalloc] which is a dangling pointer (it has no provenance) + --> $DIR/const_transmute_type_id3.rs:15:13 | LL | assert!(a == b); | ^^^^^^ evaluation of `_` failed inside this call diff --git a/tests/ui/consts/const_transmute_type_id5.rs b/tests/ui/consts/const_transmute_type_id5.rs new file mode 100644 index 000000000000..0a9ba01e0dd7 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id5.rs @@ -0,0 +1,21 @@ +//! Test that we require an equal TypeId to have the same integer +//! part, even if the provenance matches. + +#![feature(const_type_id, const_trait_impl, const_cmp)] + +use std::any::TypeId; + +const _: () = { + let a = TypeId::of::<()>(); + let mut b = TypeId::of::<()>(); + unsafe { + let ptr = &mut b as *mut TypeId as *mut *const (); + // Copy the ptr at index 0 to index 1 + let val = std::ptr::read(ptr); + std::ptr::write(ptr.offset(1), val); + } + assert!(a == b); + //~^ ERROR: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents +}; + +fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id5.stderr b/tests/ui/consts/const_transmute_type_id5.stderr new file mode 100644 index 000000000000..59823fcc1c9f --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id5.stderr @@ -0,0 +1,15 @@ +error[E0080]: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents + --> $DIR/const_transmute_type_id5.rs:17:13 + | +LL | assert!(a == b); + | ^^^^^^ evaluation of `_` failed inside this call + | +note: inside `::eq` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `::eq::compiletime` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. From 9fd3886838afd28ee3834d0e7162fd6ab5adc944 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 13 Jul 2025 22:53:57 +0000 Subject: [PATCH 148/363] Add experimental backtrace-trace-only std feature --- library/std/Cargo.toml | 3 + library/std/src/sys/backtrace.rs | 98 +++++++++++++++++--------------- library/sysroot/Cargo.toml | 1 + 3 files changed, 56 insertions(+), 46 deletions(-) diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 62ece4b69619..86d23df52381 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -92,6 +92,9 @@ backtrace = [ 'object/rustc-dep-of-std', 'miniz_oxide/rustc-dep-of-std', ] +# Disable symbolization in backtraces. For use with -Zbuild-std. +# FIXME: Ideally this should be an additive backtrace-symbolization feature +backtrace-trace-only = [] panic-unwind = ["dep:panic_unwind"] compiler-builtins-c = ["alloc/compiler-builtins-c"] diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs index efa6a896dad8..272d0fa4d1a1 100644 --- a/library/std/src/sys/backtrace.rs +++ b/library/std/src/sys/backtrace.rs @@ -68,61 +68,67 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: return false; } - let mut hit = false; - backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { - hit = true; + if cfg!(feature = "backtrace-trace-only") { + const HEX_WIDTH: usize = 2 + 2 * size_of::(); + let frame_ip = frame.ip(); + res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}"); + } else { + let mut hit = false; + backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { + hit = true; - // `__rust_end_short_backtrace` means we are done hiding symbols - // for now. Print until we see `__rust_begin_short_backtrace`. - if print_fmt == PrintFmt::Short { - if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { - if sym.contains("__rust_end_short_backtrace") { - print = true; - return; - } - if print && sym.contains("__rust_begin_short_backtrace") { - print = false; - return; - } - if !print { - omitted_count += 1; + // `__rust_end_short_backtrace` means we are done hiding symbols + // for now. Print until we see `__rust_begin_short_backtrace`. + if print_fmt == PrintFmt::Short { + if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { + if sym.contains("__rust_end_short_backtrace") { + print = true; + return; + } + if print && sym.contains("__rust_begin_short_backtrace") { + print = false; + return; + } + if !print { + omitted_count += 1; + } } } - } - if print { - if omitted_count > 0 { - debug_assert!(print_fmt == PrintFmt::Short); - // only print the message between the middle of frames - if !first_omit { - let _ = writeln!( - bt_fmt.formatter(), - " [... omitted {} frame{} ...]", - omitted_count, - if omitted_count > 1 { "s" } else { "" } - ); + if print { + if omitted_count > 0 { + debug_assert!(print_fmt == PrintFmt::Short); + // only print the message between the middle of frames + if !first_omit { + let _ = writeln!( + bt_fmt.formatter(), + " [... omitted {} frame{} ...]", + omitted_count, + if omitted_count > 1 { "s" } else { "" } + ); + } + first_omit = false; + omitted_count = 0; } - first_omit = false; - omitted_count = 0; + res = bt_fmt.frame().symbol(frame, symbol); } - res = bt_fmt.frame().symbol(frame, symbol); + }); + #[cfg(target_os = "nto")] + if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { + if !hit && print { + use crate::backtrace_rs::SymbolName; + res = bt_fmt.frame().print_raw( + frame.ip(), + Some(SymbolName::new("__my_thread_exit".as_bytes())), + None, + None, + ); + } + return false; } - }); - #[cfg(target_os = "nto")] - if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { if !hit && print { - use crate::backtrace_rs::SymbolName; - res = bt_fmt.frame().print_raw( - frame.ip(), - Some(SymbolName::new("__my_thread_exit".as_bytes())), - None, - None, - ); + res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); } - return false; - } - if !hit && print { - res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); } idx += 1; diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 290c2eeed44c..032f5272a9cd 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -20,6 +20,7 @@ test = { path = "../test", public = true } [features] default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"] backtrace = ["std/backtrace"] +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"] From 000e67aafb7ae8c755387a073f34662c4f6fc335 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 07:25:12 +0000 Subject: [PATCH 149/363] Preserve constness in trait objects up to hir ty lowering --- .../src/hir_ty_lowering/dyn_compatibility.rs | 2 +- .../const-trait-bounds-trait-objects.rs | 2 ++ .../const-trait-bounds-trait-objects.stderr | 26 +++++++++++++++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index cb106962be18..364ad38556be 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -49,7 +49,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } = self.lower_poly_trait_ref( &trait_bound.trait_ref, trait_bound.span, - hir::BoundConstness::Never, + trait_bound.modifiers.constness, hir::BoundPolarity::Positive, dummy_self, &mut user_written_bounds, diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs index ece87529c3e3..1d1da9b0e3df 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs @@ -14,5 +14,7 @@ fn main() { trait NonConst {} const fn handle(_: &dyn const NonConst) {} //~^ ERROR const trait bounds are not allowed in trait object types +//~| ERROR `const` can only be applied to `#[const_trait]` traits const fn take(_: &dyn [const] NonConst) {} //~^ ERROR `[const]` is not allowed here +//~| ERROR `[const]` can only be applied to `#[const_trait]` traits diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr index 090555c63779..06e0493024c1 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr @@ -19,12 +19,34 @@ LL | const fn handle(_: &dyn const NonConst) {} | ^^^^^^^^^^^^^^ error: `[const]` is not allowed here - --> $DIR/const-trait-bounds-trait-objects.rs:17:23 + --> $DIR/const-trait-bounds-trait-objects.rs:18:23 | LL | const fn take(_: &dyn [const] NonConst) {} | ^^^^^^^ | = note: trait objects cannot have `[const]` trait bounds -error: aborting due to 4 previous errors +error: `const` can only be applied to `#[const_trait]` traits + --> $DIR/const-trait-bounds-trait-objects.rs:15:25 + | +LL | const fn handle(_: &dyn const NonConst) {} + | ^^^^^ can't be applied to `NonConst` + | +help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait NonConst {} + | ++++++++++++++ + +error: `[const]` can only be applied to `#[const_trait]` traits + --> $DIR/const-trait-bounds-trait-objects.rs:18:23 + | +LL | const fn take(_: &dyn [const] NonConst) {} + | ^^^^^^^ can't be applied to `NonConst` + | +help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait NonConst {} + | ++++++++++++++ + +error: aborting due to 6 previous errors From 553074431875701f66107049339dc1e67f0cdeba Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Thu, 10 Jul 2025 18:36:22 -0400 Subject: [PATCH 150/363] Reword mismatched-lifetime-syntaxes text based on feedback Key changes include: - Removal of the word "syntax" from the lint message. More accurately, it could have been something like "syntax group" or "syntax category", but avoiding it completely is easier. - The primary lint message now reflects exactly which mismatch is occurring, instead of trying to be general. A new `help` line is general across the mismatch kinds. - Suggestions have been reduced to be more minimal, no longer also changing non-idiomatic but unrelated aspects. - Suggestion text no longer mentions changes when those changes don't occur in that specific suggestion. --- compiler/rustc_lint/messages.ftl | 53 +- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_lint/src/lifetime_syntax.rs | 149 ++++-- compiler/rustc_lint/src/lints.rs | 72 ++- src/tools/clippy/tests/ui/ptr_arg.rs | 2 +- src/tools/clippy/tests/ui/ptr_arg.stderr | 11 +- .../type-dependent/issue-71348.full.stderr | 11 +- .../type-dependent/issue-71348.rs | 2 +- .../rpit-assoc-pair-with-lifetime.rs | 2 +- .../rpit-assoc-pair-with-lifetime.stderr | 7 +- .../example-from-issue48686.rs | 2 +- .../example-from-issue48686.stderr | 9 +- .../missing-lifetime-kind.rs | 8 +- .../missing-lifetime-kind.stderr | 36 +- .../not-tied-to-crate.rs | 4 +- .../not-tied-to-crate.stderr | 18 +- .../static.rs | 8 +- .../static.stderr | 36 +- .../lifetimes/mismatched-lifetime-syntaxes.rs | 104 ++-- .../mismatched-lifetime-syntaxes.stderr | 497 ++++++++++-------- .../elision/ignore-non-reference-lifetimes.rs | 4 +- .../ignore-non-reference-lifetimes.stderr | 18 +- tests/ui/self/self_lifetime-async.rs | 4 +- tests/ui/self/self_lifetime-async.stderr | 18 +- tests/ui/self/self_lifetime.rs | 4 +- tests/ui/self/self_lifetime.stderr | 18 +- 26 files changed, 680 insertions(+), 419 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 8d9f2385b710..5fece4642703 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -508,27 +508,50 @@ lint_metavariable_still_repeating = variable `{$name}` is still repeating at thi lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator -lint_mismatched_lifetime_syntaxes = - lifetime flowing from input to output with different syntax can be confusing - .label_mismatched_lifetime_syntaxes_inputs = - {$n_inputs -> - [one] this lifetime flows - *[other] these lifetimes flow - } to the output - .label_mismatched_lifetime_syntaxes_outputs = - the {$n_outputs -> - [one] lifetime gets - *[other] lifetimes get - } resolved as `{$lifetime_name}` +lint_mismatched_lifetime_syntaxes_eliding_while_named = + eliding a lifetime that's named elsewhere is confusing + +lint_mismatched_lifetime_syntaxes_help = + the same lifetime is referred to in inconsistent ways, making the signature confusing + +lint_mismatched_lifetime_syntaxes_hiding_and_eliding_while_named = + hiding or eliding a lifetime that's named elsewhere is confusing + +lint_mismatched_lifetime_syntaxes_hiding_while_elided = + hiding a lifetime that's elided elsewhere is confusing + +lint_mismatched_lifetime_syntaxes_hiding_while_named = + hiding a lifetime that's named elsewhere is confusing + +lint_mismatched_lifetime_syntaxes_input_elided = + the lifetime is elided here + +lint_mismatched_lifetime_syntaxes_input_hidden = + the lifetime is hidden here + +lint_mismatched_lifetime_syntaxes_input_named = + the lifetime is named here + +lint_mismatched_lifetime_syntaxes_output_elided = + the same lifetime is elided here + +lint_mismatched_lifetime_syntaxes_output_hidden = + the same lifetime is hidden here + +lint_mismatched_lifetime_syntaxes_output_named = + the same lifetime is named here lint_mismatched_lifetime_syntaxes_suggestion_explicit = - one option is to consistently use `{$lifetime_name}` + consistently use `{$lifetime_name}` lint_mismatched_lifetime_syntaxes_suggestion_implicit = - one option is to consistently remove the lifetime + remove the lifetime name from references lint_mismatched_lifetime_syntaxes_suggestion_mixed = - one option is to remove the lifetime for references and use the anonymous lifetime for paths + remove the lifetime name from references and use `'_` for type paths + +lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths = + use `'_` for type paths lint_missing_unsafe_on_extern = extern blocks should be unsafe .suggestion = needs `unsafe` before the extern keyword diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 419124d5144e..f06757b3c237 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -55,7 +55,7 @@ mod invalid_from_utf8; mod late; mod let_underscore; mod levels; -mod lifetime_syntax; +pub mod lifetime_syntax; mod lints; mod macro_expr_fragment_specifier_2024_migration; mod map_unit_fn; diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 5465968e9847..2a5a34cdc6e9 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -140,43 +140,115 @@ fn report_mismatches<'tcx>( } } -fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool { - // Categorize lifetimes into source/syntax buckets. - let mut n_hidden = 0; - let mut n_elided = 0; - let mut n_named = 0; +#[derive(Debug, Copy, Clone, PartialEq)] +enum LifetimeSyntaxCategory { + Hidden, + Elided, + Named, +} - for info in input_info.iter().chain(output_info) { +impl LifetimeSyntaxCategory { + fn new(syntax_source: (hir::LifetimeSyntax, LifetimeSource)) -> Option { use LifetimeSource::*; use hir::LifetimeSyntax::*; - let syntax_source = (info.lifetime.syntax, info.lifetime.source); - match syntax_source { - // Ignore any other kind of lifetime. - (_, Other) => continue, - // E.g. `&T`. - (Implicit, Reference | OutlivesBound | PreciseCapturing) | + (Implicit, Reference) | // E.g. `&'_ T`. - (ExplicitAnonymous, Reference | OutlivesBound | PreciseCapturing) | + (ExplicitAnonymous, Reference) | // E.g. `ContainsLifetime<'_>`. - (ExplicitAnonymous, Path { .. }) => n_elided += 1, + (ExplicitAnonymous, Path { .. }) | + // E.g. `+ '_`, `+ use<'_>`. + (ExplicitAnonymous, OutlivesBound | PreciseCapturing) => { + Some(Self::Elided) + } // E.g. `ContainsLifetime`. - (Implicit, Path { .. }) => n_hidden += 1, + (Implicit, Path { .. }) => { + Some(Self::Hidden) + } // E.g. `&'a T`. - (ExplicitBound, Reference | OutlivesBound | PreciseCapturing) | + (ExplicitBound, Reference) | // E.g. `ContainsLifetime<'a>`. - (ExplicitBound, Path { .. }) => n_named += 1, - }; + (ExplicitBound, Path { .. }) | + // E.g. `+ 'a`, `+ use<'a>`. + (ExplicitBound, OutlivesBound | PreciseCapturing) => { + Some(Self::Named) + } + + (Implicit, OutlivesBound | PreciseCapturing) | + (_, Other) => { + None + } + } + } +} + +#[derive(Debug, Default)] +pub struct LifetimeSyntaxCategories { + pub hidden: T, + pub elided: T, + pub named: T, +} + +impl LifetimeSyntaxCategories { + fn select(&mut self, category: LifetimeSyntaxCategory) -> &mut T { + use LifetimeSyntaxCategory::*; + + match category { + Elided => &mut self.elided, + Hidden => &mut self.hidden, + Named => &mut self.named, + } + } +} + +impl LifetimeSyntaxCategories> { + pub fn len(&self) -> LifetimeSyntaxCategories { + LifetimeSyntaxCategories { + hidden: self.hidden.len(), + elided: self.elided.len(), + named: self.named.len(), + } + } + + pub fn flatten(&self) -> impl Iterator { + let Self { hidden, elided, named } = self; + [hidden.iter(), elided.iter(), named.iter()].into_iter().flatten() + } +} + +impl std::ops::Add for LifetimeSyntaxCategories { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self { + hidden: self.hidden + rhs.hidden, + elided: self.elided + rhs.elided, + named: self.named + rhs.named, + } + } +} + +fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool { + let mut syntax_counts = LifetimeSyntaxCategories::::default(); + + for info in input_info.iter().chain(output_info) { + if let Some(category) = info.lifetime_syntax_category() { + *syntax_counts.select(category) += 1; + } } - let syntax_counts = (n_hidden, n_elided, n_named); tracing::debug!(?syntax_counts); - matches!(syntax_counts, (_, 0, 0) | (0, _, 0) | (0, 0, _)) + matches!( + syntax_counts, + LifetimeSyntaxCategories { hidden: _, elided: 0, named: 0 } + | LifetimeSyntaxCategories { hidden: 0, elided: _, named: 0 } + | LifetimeSyntaxCategories { hidden: 0, elided: 0, named: _ } + ) } fn emit_mismatch_diagnostic<'tcx>( @@ -238,7 +310,7 @@ fn emit_mismatch_diagnostic<'tcx>( use LifetimeSource::*; use hir::LifetimeSyntax::*; - let syntax_source = (info.lifetime.syntax, info.lifetime.source); + let syntax_source = info.syntax_source(); if let (_, Other) = syntax_source { // Ignore any other kind of lifetime. @@ -259,7 +331,6 @@ fn emit_mismatch_diagnostic<'tcx>( // E.g. `&'_ T`. (ExplicitAnonymous, Reference) => { suggest_change_to_implicit.push(info); - suggest_change_to_mixed_implicit.push(info); suggest_change_to_explicit_bound.push(info); } @@ -319,12 +390,22 @@ fn emit_mismatch_diagnostic<'tcx>( } } + let categorize = |infos: &[Info<'_>]| { + let mut categories = LifetimeSyntaxCategories::>::default(); + for info in infos { + if let Some(category) = info.lifetime_syntax_category() { + categories.select(category).push(info.reporting_span()); + } + } + categories + }; + + let inputs = categorize(input_info); + let outputs = categorize(output_info); + let make_implicit_suggestions = |infos: &[&Info<'_>]| infos.iter().map(|i| i.removing_span()).collect::>(); - let inputs = input_info.iter().map(|info| info.reporting_span()).collect(); - let outputs = output_info.iter().map(|info| info.reporting_span()).collect(); - let explicit_bound_suggestion = bound_lifetime.map(|info| { build_mismatch_suggestion(info.lifetime_name(), &suggest_change_to_explicit_bound) }); @@ -399,8 +480,6 @@ fn emit_mismatch_diagnostic<'tcx>( ?explicit_anonymous_suggestion, ); - let lifetime_name = bound_lifetime.map(|info| info.lifetime_name()).unwrap_or("'_").to_owned(); - // We can produce a number of suggestions which may overwhelm // the user. Instead, we order the suggestions based on Rust // idioms. The "best" choice is shown to the user and the @@ -413,8 +492,8 @@ fn emit_mismatch_diagnostic<'tcx>( cx.emit_span_lint( MISMATCHED_LIFETIME_SYNTAXES, - Vec::clone(&inputs), - lints::MismatchedLifetimeSyntaxes { lifetime_name, inputs, outputs, suggestions }, + inputs.flatten().copied().collect::>(), + lints::MismatchedLifetimeSyntaxes { inputs, outputs, suggestions }, ); } @@ -422,12 +501,12 @@ fn build_mismatch_suggestion( lifetime_name: &str, infos: &[&Info<'_>], ) -> lints::MismatchedLifetimeSyntaxesSuggestion { - let lifetime_name_sugg = lifetime_name.to_owned(); + let lifetime_name = lifetime_name.to_owned(); let suggestions = infos.iter().map(|info| info.suggestion(&lifetime_name)).collect(); lints::MismatchedLifetimeSyntaxesSuggestion::Explicit { - lifetime_name_sugg, + lifetime_name, suggestions, tool_only: false, } @@ -441,6 +520,14 @@ struct Info<'tcx> { } impl<'tcx> Info<'tcx> { + fn syntax_source(&self) -> (hir::LifetimeSyntax, LifetimeSource) { + (self.lifetime.syntax, self.lifetime.source) + } + + fn lifetime_syntax_category(&self) -> Option { + LifetimeSyntaxCategory::new(self.syntax_source()) + } + fn lifetime_name(&self) -> &str { self.lifetime.ident.as_str() } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 21148833eaf7..ef18b0ac20b9 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -21,6 +21,7 @@ use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym}; use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds}; use crate::errors::{OverruledAttributeSub, RequestedLevel}; +use crate::lifetime_syntax::LifetimeSyntaxCategories; use crate::{LateContext, fluent_generated as fluent}; // array_into_iter.rs @@ -3194,30 +3195,59 @@ pub(crate) struct ReservedMultihash { #[derive(Debug)] pub(crate) struct MismatchedLifetimeSyntaxes { - pub lifetime_name: String, - pub inputs: Vec, - pub outputs: Vec, + pub inputs: LifetimeSyntaxCategories>, + pub outputs: LifetimeSyntaxCategories>, pub suggestions: Vec, } impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSyntaxes { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) { - diag.primary_message(fluent::lint_mismatched_lifetime_syntaxes); + let counts = self.inputs.len() + self.outputs.len(); + let message = match counts { + LifetimeSyntaxCategories { hidden: 0, elided: 0, named: 0 } => { + panic!("No lifetime mismatch detected") + } - diag.arg("lifetime_name", self.lifetime_name); + LifetimeSyntaxCategories { hidden: _, elided: _, named: 0 } => { + fluent::lint_mismatched_lifetime_syntaxes_hiding_while_elided + } - diag.arg("n_inputs", self.inputs.len()); - for input in self.inputs { - let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_inputs); - diag.span_label(input, a); + LifetimeSyntaxCategories { hidden: _, elided: 0, named: _ } => { + fluent::lint_mismatched_lifetime_syntaxes_hiding_while_named + } + + LifetimeSyntaxCategories { hidden: 0, elided: _, named: _ } => { + fluent::lint_mismatched_lifetime_syntaxes_eliding_while_named + } + + LifetimeSyntaxCategories { hidden: _, elided: _, named: _ } => { + fluent::lint_mismatched_lifetime_syntaxes_hiding_and_eliding_while_named + } + }; + diag.primary_message(message); + + for s in self.inputs.hidden { + diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_hidden); + } + for s in self.inputs.elided { + diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_elided); + } + for s in self.inputs.named { + diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_named); } - diag.arg("n_outputs", self.outputs.len()); - for output in self.outputs { - let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_outputs); - diag.span_label(output, a); + for s in self.outputs.hidden { + diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_hidden); } + for s in self.outputs.elided { + diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_elided); + } + for s in self.outputs.named { + diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_named); + } + + diag.help(fluent::lint_mismatched_lifetime_syntaxes_help); let mut suggestions = self.suggestions.into_iter(); if let Some(s) = suggestions.next() { @@ -3245,7 +3275,7 @@ pub(crate) enum MismatchedLifetimeSyntaxesSuggestion { }, Explicit { - lifetime_name_sugg: String, + lifetime_name: String, suggestions: Vec<(Span, String)>, tool_only: bool, }, @@ -3285,6 +3315,12 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { } Mixed { implicit_suggestions, explicit_anonymous_suggestions, tool_only } => { + let message = if implicit_suggestions.is_empty() { + fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths + } else { + fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed + }; + let implicit_suggestions = implicit_suggestions.into_iter().map(|s| (s, String::new())); @@ -3292,19 +3328,19 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { implicit_suggestions.chain(explicit_anonymous_suggestions).collect(); diag.multipart_suggestion_with_style( - fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed, + message, suggestions, Applicability::MaybeIncorrect, style(tool_only), ); } - Explicit { lifetime_name_sugg, suggestions, tool_only } => { - diag.arg("lifetime_name_sugg", lifetime_name_sugg); + Explicit { lifetime_name, suggestions, tool_only } => { + diag.arg("lifetime_name", lifetime_name); let msg = diag.eagerly_translate( fluent::lint_mismatched_lifetime_syntaxes_suggestion_explicit, ); - diag.remove_arg("lifetime_name_sugg"); + diag.remove_arg("lifetime_name"); diag.multipart_suggestion_with_style( msg, suggestions, diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs index 65f3f05d6cb0..578641e910dc 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.rs +++ b/src/tools/clippy/tests/ui/ptr_arg.rs @@ -312,7 +312,7 @@ mod issue_9218 { // Inferred to be `&'a str`, afaik. fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { - //~^ ERROR: lifetime flowing from input to output with different syntax + //~^ ERROR: eliding a lifetime that's named elsewhere is confusing todo!() } } diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 600343754e18..fd9ceddfe11c 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -231,18 +231,19 @@ error: writing `&String` instead of `&str` involves a new object where a slice w LL | fn good(v1: &String, v2: &String) { | ^^^^^^^ help: change this to: `&str` -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> tests/ui/ptr_arg.rs:314:36 | LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { - | ^^ ^^ ---- the lifetime gets resolved as `'a` + | ^^ ^^ ---- the same lifetime is elided here | | | - | | these lifetimes flow to the output - | these lifetimes flow to the output + | | the lifetime is named here + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `-D mismatched-lifetime-syntaxes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(mismatched_lifetime_syntaxes)]` -help: one option is to consistently use `'a` +help: consistently use `'a` | LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &'a str { | ++ diff --git a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr index f68fdb3b6515..32fa46b92b30 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr +++ b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr @@ -1,14 +1,15 @@ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: hiding a lifetime that's named elsewhere is confusing --> $DIR/issue-71348.rs:18:40 | LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target - | ^^ -- ------------------------ the lifetimes get resolved as `'a` + | ^^ -- ------------------------ the same lifetime is hidden here | | | - | | the lifetimes get resolved as `'a` - | this lifetime flows to the output + | | the same lifetime is named here + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default -help: one option is to consistently use `'a` +help: consistently use `'a` | LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target | +++ diff --git a/tests/ui/const-generics/type-dependent/issue-71348.rs b/tests/ui/const-generics/type-dependent/issue-71348.rs index c6563c803059..9053f362ce4c 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.rs +++ b/tests/ui/const-generics/type-dependent/issue-71348.rs @@ -17,7 +17,7 @@ trait Get<'a, const N: &'static str> { impl Foo { fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target //[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter - //[full]~^^ WARNING lifetime flowing from input to output with different syntax + //[full]~^^ WARNING hiding a lifetime that's named elsewhere is confusing where Self: Get<'a, N>, { diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs index 1ac3c593dbe5..1b8a5d4ca99b 100644 --- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs +++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs @@ -1,7 +1,7 @@ //@ check-pass pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator { - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing v.into_iter() } diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr index b9d8674992ca..3651226e0c39 100644 --- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr +++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr @@ -1,11 +1,12 @@ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:31 | LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator { - | ^^ this lifetime flows to the output ---- the lifetime gets resolved as `'a` + | ^^ the lifetime is named here ---- the same lifetime is elided here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default -help: one option is to consistently use `'a` +help: consistently use `'a` | LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator { | ++ diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs index 1804003d3672..9162a38f5109 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs @@ -4,7 +4,7 @@ struct Foo; impl Foo { pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing unsafe { &mut *(x as *mut _) } } } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr index 7c7411651d03..5a7a5a6ebf95 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr @@ -1,17 +1,18 @@ -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> $DIR/example-from-issue48686.rs:6:21 | LL | pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { - | ^^^^^^^ ------- the lifetime gets resolved as `'static` + | ^^^^^^^ ------- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing note: the lint level is defined here --> $DIR/example-from-issue48686.rs:1:9 | LL | #![deny(mismatched_lifetime_syntaxes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: one option is to consistently use `'static` +help: consistently use `'static` | LL | pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 { | +++++++ diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs index 3d5aab5c8295..ecc790be5a01 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs @@ -1,26 +1,26 @@ #![deny(mismatched_lifetime_syntaxes)] fn ampersand<'a>(x: &'a u8) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing x } struct Brackets<'a>(&'a u8); fn brackets<'a>(x: &'a u8) -> Brackets { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing Brackets(x) } struct Comma<'a, T>(&'a T); fn comma<'a>(x: &'a u8) -> Comma { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing Comma(x) } fn underscore<'a>(x: &'a u8) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing x } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr index 681b3c970526..af56a0a0ea5a 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr @@ -1,56 +1,60 @@ -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> $DIR/missing-lifetime-kind.rs:3:22 | LL | fn ampersand<'a>(x: &'a u8) -> &u8 { - | ^^ --- the lifetime gets resolved as `'a` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing note: the lint level is defined here --> $DIR/missing-lifetime-kind.rs:1:9 | LL | #![deny(mismatched_lifetime_syntaxes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: one option is to consistently use `'a` +help: consistently use `'a` | LL | fn ampersand<'a>(x: &'a u8) -> &'a u8 { | ++ -error: lifetime flowing from input to output with different syntax can be confusing +error: hiding a lifetime that's named elsewhere is confusing --> $DIR/missing-lifetime-kind.rs:10:21 | LL | fn brackets<'a>(x: &'a u8) -> Brackets { - | ^^ -------- the lifetime gets resolved as `'a` + | ^^ -------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn brackets<'a>(x: &'a u8) -> Brackets<'a> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing +error: hiding a lifetime that's named elsewhere is confusing --> $DIR/missing-lifetime-kind.rs:17:18 | LL | fn comma<'a>(x: &'a u8) -> Comma { - | ^^ --------- the lifetime gets resolved as `'a` + | ^^ --------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn comma<'a>(x: &'a u8) -> Comma<'a, u8> { | +++ -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> $DIR/missing-lifetime-kind.rs:22:23 | LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn underscore<'a>(x: &'a u8) -> &'_ u8 { LL + fn underscore<'a>(x: &'a u8) -> &'a u8 { diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs index cc398ab78883..449b2a3c0a87 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs @@ -6,13 +6,13 @@ #[warn(mismatched_lifetime_syntaxes)] mod foo { fn bar(x: &'static u8) -> &u8 { - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing x } #[deny(mismatched_lifetime_syntaxes)] fn baz(x: &'static u8) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing x } } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr index da691225c176..cf0a29678fad 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr @@ -1,35 +1,37 @@ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/not-tied-to-crate.rs:8:16 | LL | fn bar(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the lifetime gets resolved as `'static` + | ^^^^^^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing note: the lint level is defined here --> $DIR/not-tied-to-crate.rs:6:8 | LL | #[warn(mismatched_lifetime_syntaxes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: one option is to consistently use `'static` +help: consistently use `'static` | LL | fn bar(x: &'static u8) -> &'static u8 { | +++++++ -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> $DIR/not-tied-to-crate.rs:14:16 | LL | fn baz(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the lifetime gets resolved as `'static` + | ^^^^^^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing note: the lint level is defined here --> $DIR/not-tied-to-crate.rs:13:12 | LL | #[deny(mismatched_lifetime_syntaxes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: one option is to consistently use `'static` +help: consistently use `'static` | LL | fn baz(x: &'static u8) -> &'static u8 { | +++++++ diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs index 47ae258f138f..c41cf44e1c5f 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs @@ -14,26 +14,26 @@ impl Trait for () { } fn ampersand(x: &'static u8) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing x } struct Brackets<'a>(&'a u8); fn brackets(x: &'static u8) -> Brackets { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing Brackets(x) } struct Comma<'a, T>(&'a T); fn comma(x: &'static u8) -> Comma { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing Comma(x) } fn underscore(x: &'static u8) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing x } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr index 5b9a986bcbea..d60bec6f7e49 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr @@ -1,56 +1,60 @@ -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> $DIR/static.rs:16:18 | LL | fn ampersand(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the lifetime gets resolved as `'static` + | ^^^^^^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing note: the lint level is defined here --> $DIR/static.rs:1:9 | LL | #![deny(mismatched_lifetime_syntaxes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: one option is to consistently use `'static` +help: consistently use `'static` | LL | fn ampersand(x: &'static u8) -> &'static u8 { | +++++++ -error: lifetime flowing from input to output with different syntax can be confusing +error: hiding a lifetime that's named elsewhere is confusing --> $DIR/static.rs:23:17 | LL | fn brackets(x: &'static u8) -> Brackets { - | ^^^^^^^ -------- the lifetime gets resolved as `'static` + | ^^^^^^^ -------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL | fn brackets(x: &'static u8) -> Brackets<'static> { | +++++++++ -error: lifetime flowing from input to output with different syntax can be confusing +error: hiding a lifetime that's named elsewhere is confusing --> $DIR/static.rs:30:14 | LL | fn comma(x: &'static u8) -> Comma { - | ^^^^^^^ --------- the lifetime gets resolved as `'static` + | ^^^^^^^ --------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL | fn comma(x: &'static u8) -> Comma<'static, u8> { | ++++++++ -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> $DIR/static.rs:35:19 | LL | fn underscore(x: &'static u8) -> &'_ u8 { - | ^^^^^^^ -- the lifetime gets resolved as `'static` + | ^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL - fn underscore(x: &'static u8) -> &'_ u8 { LL + fn underscore(x: &'static u8) -> &'static u8 { diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs index b98423afb174..f6260c472029 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs @@ -5,109 +5,111 @@ struct ContainsLifetime<'a>(&'a u8); struct S(u8); +// ref to ref + fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } -// --- +// path to path fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing v } fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing v } fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing v } fn explicit_bound_path_to_explicit_anonymous_path<'a>( v: ContainsLifetime<'a>, - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing ) -> ContainsLifetime<'_> { v } -// --- +// ref to path fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(v) } fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(v) } fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing ContainsLifetime(v) } fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing ContainsLifetime(v) } -// --- +// path to ref fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing v.0 } fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing v.0 } fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v.0 } fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v.0 } impl S { fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing &self.0 } fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing &self.0 } // --- fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(&self.0) } fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing ContainsLifetime(&self.0) } fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing ContainsLifetime(&self.0) } } @@ -122,43 +124,43 @@ mod static_suggestions { struct S(u8); fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing ContainsLifetime(v) } fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing ContainsLifetime(v) } impl S { fn static_ref_to_implicit_ref(&'static self) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing &self.0 } fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing &self.0 } fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing ContainsLifetime(&self.0) } fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing ContainsLifetime(&self.0) } } @@ -170,23 +172,23 @@ mod impl_trait { struct ContainsLifetime<'a>(&'a u8); fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing move || _ = v } fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing move || _ = v } fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing move || _ = v } fn explicit_bound_path_to_impl_trait_precise_capture<'a>( v: ContainsLifetime<'a>, - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing ) -> impl FnOnce() + use<'_> { move || _ = v } @@ -200,13 +202,13 @@ mod dyn_trait { struct ContainsLifetime<'a>(&'a u8); fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box + '_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing Box::new(iter::once(v)) } fn explicit_bound_path_to_dyn_trait_bound<'a>( v: ContainsLifetime<'a>, - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing ) -> Box + '_> { Box::new(iter::once(v)) } @@ -214,10 +216,28 @@ mod dyn_trait { /// These tests serve to exercise edge cases of the lint formatting mod diagnostic_output { + #[derive(Copy, Clone)] + struct ContainsLifetime<'a>(&'a u8); + + fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 { + //~^ ERROR eliding a lifetime that's named elsewhere is confusing + v.0 + } + fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing (v, v) } + + fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) { + //~^ ERROR hiding or eliding a lifetime that's named elsewhere is confusing + (v.0, v) + } + + fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) { + //~^ ERROR eliding a lifetime that's named elsewhere is confusing + (v, v, ContainsLifetime(v)) + } } /// Trait functions are represented differently in the HIR. Make sure @@ -228,20 +248,20 @@ mod trait_functions { trait TheTrait { fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime; - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing } impl TheTrait for &u8 { fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(v) } fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(self) } } @@ -255,7 +275,7 @@ mod foreign_functions { extern "Rust" { fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing } } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr index 108b3f14169a..20b7561c594c 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr @@ -1,538 +1,613 @@ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:8:47 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:10:47 | LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 { - | ^^ --- the lifetime gets resolved as `'a` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing note: the lint level is defined here --> $DIR/mismatched-lifetime-syntaxes.rs:1:9 | LL | #![deny(mismatched_lifetime_syntaxes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: one option is to consistently use `'a` +help: consistently use `'a` | LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &'a u8 { | ++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:13:57 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:15:57 | LL | fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { LL + fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'a u8 { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:20:48 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:22:48 | LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> { - | ^^^^^^^^^^^^^^^^ -- the lifetime gets resolved as `'_` + | ^^^^^^^^^^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is hidden here | -help: one option is to consistently use `'_` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'_` | LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:25:65 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:27:65 | LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime { - | ^^ ---------------- the lifetime gets resolved as `'_` + | ^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to consistently use `'_` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'_` | LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:30:65 +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:32:65 | LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime { - | ^^ ---------------- the lifetime gets resolved as `'a` + | ^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'a> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:36:25 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:38:25 | LL | v: ContainsLifetime<'a>, - | ^^ this lifetime flows to the output + | ^^ the lifetime is named here LL | LL | ) -> ContainsLifetime<'_> { - | -- the lifetime gets resolved as `'a` + | -- the same lifetime is elided here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - ) -> ContainsLifetime<'_> { LL + ) -> ContainsLifetime<'a> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:44:37 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:46:37 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - | ^^^ ---------------- the lifetime gets resolved as `'_` + | ^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:49:48 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:51:48 | LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { - | ^^ ---------------- the lifetime gets resolved as `'_` + | ^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths - | -LL - fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { -LL + fn explicit_anonymous_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> { + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | +LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime<'_> { + | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:54:48 +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:56:48 | LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime { - | ^^ ---------------- the lifetime gets resolved as `'a` + | ^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime<'a> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:59:58 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:61:58 | LL | fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { LL + fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'a> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:66:37 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:68:37 | LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 { - | ^^^^^^^^^^^^^^^^ --- the lifetime gets resolved as `'_` + | ^^^^^^^^^^^^^^^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is hidden here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime<'_>) -> &u8 { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:71:47 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:73:47 | LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { - | ^^^^^^^^^^^^^^^^ -- the lifetime gets resolved as `'_` + | ^^^^^^^^^^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is hidden here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths - | -LL - fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { -LL + fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &u8 { + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | +LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &'_ u8 { + | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:76:64 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:78:64 | LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 { - | ^^ --- the lifetime gets resolved as `'a` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 { | ++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:81:74 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:83:74 | LL | fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { LL + fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:87:55 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:89:55 | LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 { - | ^^ --- the lifetime gets resolved as `'a` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &'a u8 { | ++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:92:65 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:94:65 | LL | fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { LL + fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'a u8 { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:99:56 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:101:56 | LL | fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { - | ^^ ---------------- the lifetime gets resolved as `'_` + | ^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths - | -LL - fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { -LL + fn method_explicit_anonymous_ref_to_implicit_path(&self) -> ContainsLifetime<'_> { + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | +LL | fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime<'_> { + | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:104:56 +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:106:56 | LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime { - | ^^ ---------------- the lifetime gets resolved as `'a` + | ^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime<'a> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:109:66 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:111:66 | LL | fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { LL + fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'a> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:124:39 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:126:39 | LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 { - | ^^^^^^^ --- the lifetime gets resolved as `'static` + | ^^^^^^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &'static u8 { | +++++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:129:49 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:131:49 | LL | fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { - | ^^^^^^^ -- the lifetime gets resolved as `'static` + | ^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL - fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { LL + fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'static u8 { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:134:40 +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:136:40 | LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime { - | ^^^^^^^ ---------------- the lifetime gets resolved as `'static` + | ^^^^^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime<'static> { | +++++++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:139:50 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:141:50 | LL | fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { - | ^^^^^^^ -- the lifetime gets resolved as `'static` + | ^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL - fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { LL + fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'static> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:145:40 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:147:40 | LL | fn static_ref_to_implicit_ref(&'static self) -> &u8 { - | ^^^^^^^ --- the lifetime gets resolved as `'static` + | ^^^^^^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL | fn static_ref_to_implicit_ref(&'static self) -> &'static u8 { | +++++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:150:50 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:152:50 | LL | fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { - | ^^^^^^^ -- the lifetime gets resolved as `'static` + | ^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL - fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { LL + fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'static u8 { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:155:41 +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:157:41 | LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime { - | ^^^^^^^ ---------------- the lifetime gets resolved as `'static` + | ^^^^^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime<'static> { | +++++++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:160:51 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:162:51 | LL | fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { - | ^^^^^^^ -- the lifetime gets resolved as `'static` + | ^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL - fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { LL + fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'static> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:172:55 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:174:55 | LL | fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { LL + fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + 'a { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:177:65 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:179:65 | LL | fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { - | ^^ -- the lifetime gets resolved as `'a` - | | - | this lifetime flows to the output + | ^^ the lifetime is named here -- the same lifetime is elided here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { LL + fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'a> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:182:72 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:184:72 | LL | fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { LL + fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + 'a { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:188:29 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:190:29 | LL | v: ContainsLifetime<'a>, - | ^^ this lifetime flows to the output + | ^^ the lifetime is named here LL | LL | ) -> impl FnOnce() + use<'_> { - | -- the lifetime gets resolved as `'a` + | -- the same lifetime is elided here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - ) -> impl FnOnce() + use<'_> { LL + ) -> impl FnOnce() + use<'a> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:202:54 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:204:54 | LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box + '_> { - | ^^ --- -- the lifetimes get resolved as `'a` - | | | - | | the lifetimes get resolved as `'a` - | this lifetime flows to the output + | ^^ the lifetime is named here --- the same lifetime is elided here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box + '_> { | ++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:208:29 +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:210:29 | LL | v: ContainsLifetime<'a>, - | ^^ this lifetime flows to the output + | ^^ the lifetime is named here LL | LL | ) -> Box + '_> { - | ---------------- -- the lifetimes get resolved as `'a` - | | - | the lifetimes get resolved as `'a` + | ---------------- the same lifetime is hidden here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | ) -> Box> + '_> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:217:33 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:222:33 + | +LL | fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 { + | ^^ ^^ --- the same lifetime is elided here + | | | + | | the lifetime is named here + | the lifetime is named here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` + | +LL | fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &'a u8 { + | ++ + +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:227:33 | LL | fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { - | ^^ --- --- the lifetimes get resolved as `'a` + | ^^ --- --- the same lifetime is elided here | | | - | | the lifetimes get resolved as `'a` - | this lifetime flows to the output + | | the same lifetime is elided here + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn multiple_outputs<'a>(v: &'a u8) -> (&'a u8, &'a u8) { | ++ ++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:230:45 +error: hiding or eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:232:53 + | +LL | fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) { + | ^^ --- ---------------- the same lifetime is hidden here + | | | + | | the same lifetime is elided here + | the lifetime is named here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` + | +LL | fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&'a u8, ContainsLifetime<'a>) { + | ++ ++++ + +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:237:38 + | +LL | fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) { + | ^^ --- -- -- the same lifetime is named here + | | | | + | | | the same lifetime is named here + | | the same lifetime is elided here + | the lifetime is named here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` + | +LL | fn explicit_bound_output<'a>(v: &'a u8) -> (&'a u8, &'a u8, ContainsLifetime<'a>) { + | ++ + +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:250:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - | ^^^ ---------------- the lifetime gets resolved as `'_` + | ^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_>; | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:233:49 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:253:49 | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime; - | ^^^^^ ---------------- the lifetime gets resolved as `'_` + | ^^^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_>; | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:238:45 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:258:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - | ^^^ ---------------- the lifetime gets resolved as `'_` + | ^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:243:49 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:263:49 | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime { - | ^^^^^ ---------------- the lifetime gets resolved as `'_` + | ^^^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:257:45 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:277:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - | ^^^ ---------------- the lifetime gets resolved as `'_` + | ^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_>; | ++++ -error: aborting due to 39 previous errors +error: aborting due to 42 previous errors diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs index ecd669059ed3..ce2fb8235cc6 100644 --- a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs +++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs @@ -4,11 +4,11 @@ struct Foo<'a>(&'a str); impl<'b> Foo<'b> { fn a<'a>(self: Self, a: &'a str) -> &str { - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing a } fn b<'a>(self: Foo<'b>, a: &'a str) -> &str { - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing a } } diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr index 5351bf3c94cf..7108fa1a2908 100644 --- a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr +++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr @@ -1,26 +1,28 @@ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/ignore-non-reference-lifetimes.rs:6:30 | LL | fn a<'a>(self: Self, a: &'a str) -> &str { - | ^^ ---- the lifetime gets resolved as `'a` + | ^^ ---- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default -help: one option is to consistently use `'a` +help: consistently use `'a` | LL | fn a<'a>(self: Self, a: &'a str) -> &'a str { | ++ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/ignore-non-reference-lifetimes.rs:10:33 | LL | fn b<'a>(self: Foo<'b>, a: &'a str) -> &str { - | ^^ ---- the lifetime gets resolved as `'a` + | ^^ ---- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn b<'a>(self: Foo<'b>, a: &'a str) -> &'a str { | ++ diff --git a/tests/ui/self/self_lifetime-async.rs b/tests/ui/self/self_lifetime-async.rs index f839ab03a607..0093971fee42 100644 --- a/tests/ui/self/self_lifetime-async.rs +++ b/tests/ui/self/self_lifetime-async.rs @@ -4,13 +4,13 @@ struct Foo<'a>(&'a ()); impl<'a> Foo<'a> { async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing } type Alias = Foo<'static>; impl Alias { async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing } fn main() {} diff --git a/tests/ui/self/self_lifetime-async.stderr b/tests/ui/self/self_lifetime-async.stderr index a9c1be2e808b..43dc96abdc2e 100644 --- a/tests/ui/self/self_lifetime-async.stderr +++ b/tests/ui/self/self_lifetime-async.stderr @@ -1,26 +1,28 @@ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/self_lifetime-async.rs:6:29 | LL | async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | ^^ --- the lifetime gets resolved as `'b` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default -help: one option is to consistently use `'b` +help: consistently use `'b` | LL | async fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } | ++ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/self_lifetime-async.rs:12:42 | LL | async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | ^^ --- the lifetime gets resolved as `'a` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | async fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg } | ++ diff --git a/tests/ui/self/self_lifetime.rs b/tests/ui/self/self_lifetime.rs index aaa31f85ad5b..190809af22f9 100644 --- a/tests/ui/self/self_lifetime.rs +++ b/tests/ui/self/self_lifetime.rs @@ -5,13 +5,13 @@ struct Foo<'a>(&'a ()); impl<'a> Foo<'a> { fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing } type Alias = Foo<'static>; impl Alias { fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing } fn main() {} diff --git a/tests/ui/self/self_lifetime.stderr b/tests/ui/self/self_lifetime.stderr index ec676e69cf63..4f9b2fcd2ad0 100644 --- a/tests/ui/self/self_lifetime.stderr +++ b/tests/ui/self/self_lifetime.stderr @@ -1,26 +1,28 @@ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/self_lifetime.rs:7:23 | LL | fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | ^^ --- the lifetime gets resolved as `'b` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default -help: one option is to consistently use `'b` +help: consistently use `'b` | LL | fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } | ++ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/self_lifetime.rs:13:36 | LL | fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | ^^ --- the lifetime gets resolved as `'a` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg } | ++ From 1b8d65ed29e17e24d0acecf1986ab320c5747a85 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Mon, 14 Jul 2025 18:10:41 +0200 Subject: [PATCH 151/363] rustc_type_ir/walk: move docstring to `TypeWalker` itself having it on the impl block is a bit weird imo --- compiler/rustc_type_ir/src/walk.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_type_ir/src/walk.rs b/compiler/rustc_type_ir/src/walk.rs index 737550eb73e9..9912fad1756e 100644 --- a/compiler/rustc_type_ir/src/walk.rs +++ b/compiler/rustc_type_ir/src/walk.rs @@ -12,12 +12,6 @@ use crate::{self as ty, Interner}; // avoid heap allocations. type TypeWalkerStack = SmallVec<[::GenericArg; 8]>; -pub struct TypeWalker { - stack: TypeWalkerStack, - last_subtree: usize, - pub visited: SsoHashSet, -} - /// An iterator for walking the type tree. /// /// It's very easy to produce a deeply @@ -26,6 +20,12 @@ pub struct TypeWalker { /// in this situation walker only visits each type once. /// It maintains a set of visited types and /// skips any types that are already there. +pub struct TypeWalker { + stack: TypeWalkerStack, + last_subtree: usize, + pub visited: SsoHashSet, +} + impl TypeWalker { pub fn new(root: I::GenericArg) -> Self { Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() } From ae1b1b4f8a9a1cd012cd7db944bbfa2adae703cb Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Tue, 10 Jun 2025 18:36:22 +0200 Subject: [PATCH 152/363] tests: Fix duplicated-path-in-error fail with musl musl's dlopen returns a different error than glibc, which contains the name of the file. This would cause the test to fail, since the filename would appear twice in the output (once in the error from rustc, once in the error message from musl). Split the expected test outputs for the different libc implementations. Signed-off-by: Jens Reidel --- src/tools/compiletest/src/directives.rs | 1 + ...in-error.stderr => duplicated-path-in-error.gnu.stderr} | 0 tests/ui/codegen/duplicated-path-in-error.musl.stderr | 2 ++ tests/ui/codegen/duplicated-path-in-error.rs | 7 +++++++ 4 files changed, 10 insertions(+) rename tests/ui/codegen/{duplicated-path-in-error.stderr => duplicated-path-in-error.gnu.stderr} (100%) create mode 100644 tests/ui/codegen/duplicated-path-in-error.musl.stderr diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 215793fe947f..e31f8f43e1b9 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -973,6 +973,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-mips64", "only-msp430", "only-msvc", + "only-musl", "only-nightly", "only-nvptx64", "only-powerpc", diff --git a/tests/ui/codegen/duplicated-path-in-error.stderr b/tests/ui/codegen/duplicated-path-in-error.gnu.stderr similarity index 100% rename from tests/ui/codegen/duplicated-path-in-error.stderr rename to tests/ui/codegen/duplicated-path-in-error.gnu.stderr diff --git a/tests/ui/codegen/duplicated-path-in-error.musl.stderr b/tests/ui/codegen/duplicated-path-in-error.musl.stderr new file mode 100644 index 000000000000..2892ebffdde6 --- /dev/null +++ b/tests/ui/codegen/duplicated-path-in-error.musl.stderr @@ -0,0 +1,2 @@ +error: couldn't load codegen backend /non-existing-one.so: Error loading shared library /non-existing-one.so: No such file or directory + diff --git a/tests/ui/codegen/duplicated-path-in-error.rs b/tests/ui/codegen/duplicated-path-in-error.rs index a446395de208..fed93828ee2a 100644 --- a/tests/ui/codegen/duplicated-path-in-error.rs +++ b/tests/ui/codegen/duplicated-path-in-error.rs @@ -1,8 +1,15 @@ +//@ revisions: musl gnu //@ only-linux +//@ ignore-cross-compile because this relies on host libc behaviour //@ compile-flags: -Zcodegen-backend=/non-existing-one.so +//@[gnu] only-gnu +//@[musl] only-musl // This test ensures that the error of the "not found dylib" doesn't duplicate // the path of the dylib. +// +// glibc and musl have different dlopen error messages, so the expected error +// message differs between the two. fn main() {} From 904273c58e474877786679f89a6a7e15b75acfb1 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 8 Jul 2025 17:31:37 +0800 Subject: [PATCH 153/363] Register change tracker warning for removal of `./x suggest` --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 1f6ed8129da8..d888a7863bcb 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -476,4 +476,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "Option `tool.TOOL_NAME.features` now works on any subcommand, not just `build`.", }, + ChangeInfo { + change_id: 143630, + severity: ChangeSeverity::Warning, + summary: "The current `./x suggest` implementation has been removed due to it being quite broken and a lack of maintenance bandwidth, with no prejudice against re-implementing it in a more maintainable form.", + }, ]; From 91d064b44286d87723fc8ef2ae9d8e3d047d12f2 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 8 Jul 2025 17:52:00 +0800 Subject: [PATCH 154/363] Remove current implementation of `./x suggest` This is quite a bit of implementation complexity, yet it is quite broken, and we don't have the maintenance bandwidth to address. Remove the current implementation if only to reduce bootstrap's implementation complexity; the `suggest` flow comes with its own set of hacks. --- Cargo.lock | 8 -- Cargo.toml | 1 - src/bootstrap/src/core/build_steps/mod.rs | 1 - src/bootstrap/src/core/build_steps/suggest.rs | 68 ------------- src/bootstrap/src/core/build_steps/test.rs | 9 +- src/bootstrap/src/core/build_steps/tool.rs | 1 - src/bootstrap/src/core/builder/cargo.rs | 2 +- src/bootstrap/src/core/builder/mod.rs | 6 +- src/bootstrap/src/core/config/config.rs | 2 - src/bootstrap/src/core/config/flags.rs | 8 -- src/bootstrap/src/core/sanity.rs | 1 - src/bootstrap/src/lib.rs | 11 +-- src/bootstrap/src/utils/cc_detect.rs | 1 - src/bootstrap/src/utils/metrics.rs | 2 +- src/tools/suggest-tests/Cargo.toml | 8 -- .../suggest-tests/src/dynamic_suggestions.rs | 32 ------- src/tools/suggest-tests/src/lib.rs | 96 ------------------- src/tools/suggest-tests/src/main.rs | 40 -------- .../suggest-tests/src/static_suggestions.rs | 40 -------- src/tools/suggest-tests/src/tests.rs | 21 ---- 20 files changed, 10 insertions(+), 348 deletions(-) delete mode 100644 src/bootstrap/src/core/build_steps/suggest.rs delete mode 100644 src/tools/suggest-tests/Cargo.toml delete mode 100644 src/tools/suggest-tests/src/dynamic_suggestions.rs delete mode 100644 src/tools/suggest-tests/src/lib.rs delete mode 100644 src/tools/suggest-tests/src/main.rs delete mode 100644 src/tools/suggest-tests/src/static_suggestions.rs delete mode 100644 src/tools/suggest-tests/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index a6c36b4bdfa7..ff2b21c64b0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5188,14 +5188,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "suggest-tests" -version = "0.1.0" -dependencies = [ - "build_helper", - "glob", -] - [[package]] name = "syn" version = "1.0.109" diff --git a/Cargo.toml b/Cargo.toml index 6d3425f4115a..67c7a9d67edc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,6 @@ members = [ "src/tools/rustdoc-gui-test", "src/tools/rustdoc-themes", "src/tools/rustfmt", - "src/tools/suggest-tests", "src/tools/test-float-parse", "src/tools/tidy", "src/tools/tier-check", diff --git a/src/bootstrap/src/core/build_steps/mod.rs b/src/bootstrap/src/core/build_steps/mod.rs index fcb6abea4347..c2ad9a4df597 100644 --- a/src/bootstrap/src/core/build_steps/mod.rs +++ b/src/bootstrap/src/core/build_steps/mod.rs @@ -11,7 +11,6 @@ pub(crate) mod llvm; pub(crate) mod perf; pub(crate) mod run; pub(crate) mod setup; -pub(crate) mod suggest; pub(crate) mod synthetic_targets; pub(crate) mod test; pub(crate) mod tool; diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs deleted file mode 100644 index fd4918961adb..000000000000 --- a/src/bootstrap/src/core/build_steps/suggest.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Attempt to magically identify good tests to run - -use std::path::PathBuf; -use std::str::FromStr; - -use clap::Parser; - -use crate::core::build_steps::tool::Tool; -use crate::core::builder::Builder; - -/// Suggests a list of possible `x.py` commands to run based on modified files in branch. -pub fn suggest(builder: &Builder<'_>, run: bool) { - let git_config = builder.config.git_config(); - let suggestions = builder - .tool_cmd(Tool::SuggestTests) - .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch) - .env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL", git_config.git_merge_commit_email) - .run_capture_stdout(builder) - .stdout(); - - let suggestions = suggestions - .lines() - .map(|line| { - let mut sections = line.split_ascii_whitespace(); - - // this code expects one suggestion per line in the following format: - // {some number of flags} [optional stage number] - let cmd = sections.next().unwrap(); - let stage = sections.next_back().and_then(|s| str::parse(s).ok()); - let paths: Vec = sections.map(|p| PathBuf::from_str(p).unwrap()).collect(); - - (cmd, stage, paths) - }) - .collect::>(); - - if !suggestions.is_empty() { - println!("==== SUGGESTIONS ===="); - for sug in &suggestions { - print!("x {} ", sug.0); - if let Some(stage) = sug.1 { - print!("--stage {stage} "); - } - - for path in &sug.2 { - print!("{} ", path.display()); - } - println!(); - } - println!("====================="); - } else { - println!("No suggestions found!"); - return; - } - - if run { - for sug in suggestions { - let mut build: crate::Build = builder.build.clone(); - build.config.paths = sug.2; - build.config.cmd = crate::core::config::flags::Flags::parse_from(["x.py", sug.0]).cmd; - if let Some(stage) = sug.1 { - build.config.stage = stage; - } - build.build(); - } - } else { - println!("HELP: consider using the `--run` flag to automatically run suggested tests"); - } -} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 757eac1475c1..9e7ea5c115f1 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -47,12 +47,11 @@ impl Step for CrateBootstrap { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - // This step is responsible for several different tool paths. By default - // it will test all of them, but requesting specific tools on the - // command-line (e.g. `./x test suggest-tests`) will test only the - // specified tools. + // This step is responsible for several different tool paths. + // + // By default, it will test all of them, but requesting specific tools on the command-line + // (e.g. `./x test src/tools/coverage-dump`) will test only the specified tools. run.path("src/tools/jsondoclint") - .path("src/tools/suggest-tests") .path("src/tools/replace-version-placeholder") .path("src/tools/coverage-dump") // We want `./x test tidy` to _run_ the tidy tool, not its tests. diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 814a44b9a13b..1c994b0ccfc8 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -517,7 +517,6 @@ bootstrap_tool!( ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder"; CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata"; GenerateCopyright, "src/tools/generate-copyright", "generate-copyright"; - SuggestTests, "src/tools/suggest-tests", "suggest-tests"; GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys"; // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features. RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES; diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index d5a290d804c5..a3b471ca56eb 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -113,7 +113,7 @@ impl Cargo { match cmd_kind { // No need to configure the target linker for these command types. - Kind::Clean | Kind::Check | Kind::Suggest | Kind::Format | Kind::Setup => {} + Kind::Clean | Kind::Check | Kind::Format | Kind::Setup => {} _ => { cargo.configure_linker(builder, mode); } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 7115c5a1cbe7..1b75d00b30e4 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -845,7 +845,6 @@ pub enum Kind { #[value(alias = "r")] Run, Setup, - Suggest, Vendor, Perf, } @@ -869,7 +868,6 @@ impl Kind { Kind::Install => "install", Kind::Run => "run", Kind::Setup => "setup", - Kind::Suggest => "suggest", Kind::Vendor => "vendor", Kind::Perf => "perf", } @@ -881,7 +879,6 @@ impl Kind { Kind::Bench => "Benchmarking", Kind::Doc => "Documenting", Kind::Run => "Running", - Kind::Suggest => "Suggesting", Kind::Clippy => "Linting", Kind::Perf => "Profiling & benchmarking", _ => { @@ -1201,7 +1198,7 @@ impl<'a> Builder<'a> { Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), Kind::Vendor => describe!(vendor::Vendor), // special-cased in Build::build() - Kind::Format | Kind::Suggest | Kind::Perf => vec![], + Kind::Format | Kind::Perf => vec![], Kind::MiriTest | Kind::MiriSetup => unreachable!(), } } @@ -1269,7 +1266,6 @@ impl<'a> Builder<'a> { Subcommand::Run { .. } => (Kind::Run, &paths[..]), Subcommand::Clean { .. } => (Kind::Clean, &paths[..]), Subcommand::Format { .. } => (Kind::Format, &[][..]), - Subcommand::Suggest { .. } => (Kind::Suggest, &[][..]), Subcommand::Setup { profile: ref path } => ( Kind::Setup, path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)), diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 0039d44785c3..28958b60fc32 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1050,7 +1050,6 @@ impl Config { | Subcommand::Run { .. } | Subcommand::Setup { .. } | Subcommand::Format { .. } - | Subcommand::Suggest { .. } | Subcommand::Vendor { .. } => flags_stage.unwrap_or(0), }; @@ -1098,7 +1097,6 @@ impl Config { | Subcommand::Run { .. } | Subcommand::Setup { .. } | Subcommand::Format { .. } - | Subcommand::Suggest { .. } | Subcommand::Vendor { .. } | Subcommand::Perf { .. } => {} } diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 155b6f587589..1547ca444943 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -481,13 +481,6 @@ Arguments: #[arg(value_name = "|hook|editor|link")] profile: Option, }, - /// Suggest a subset of tests to run, based on modified files - #[command(long_about = "\n")] - Suggest { - /// run suggested tests - #[arg(long)] - run: bool, - }, /// Vendor dependencies Vendor { /// Additional `Cargo.toml` to sync and vendor @@ -518,7 +511,6 @@ impl Subcommand { Subcommand::Install => Kind::Install, Subcommand::Run { .. } => Kind::Run, Subcommand::Setup { .. } => Kind::Setup, - Subcommand::Suggest { .. } => Kind::Suggest, Subcommand::Vendor { .. } => Kind::Vendor, Subcommand::Perf { .. } => Kind::Perf, } diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index f2119e84cce7..b39d464493e5 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -216,7 +216,6 @@ than building it. build.config.cmd, Subcommand::Clean { .. } | Subcommand::Check { .. } - | Subcommand::Suggest { .. } | Subcommand::Format { .. } | Subcommand::Setup { .. } ); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 66a164703b7f..44be51815c7c 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -651,11 +651,9 @@ impl Build { // Handle hard-coded subcommands. { #[cfg(feature = "tracing")] - let _hardcoded_span = span!( - tracing::Level::DEBUG, - "handling hardcoded subcommands (Format, Suggest, Perf)" - ) - .entered(); + let _hardcoded_span = + span!(tracing::Level::DEBUG, "handling hardcoded subcommands (Format, Perf)") + .entered(); match &self.config.cmd { Subcommand::Format { check, all } => { @@ -666,9 +664,6 @@ impl Build { &self.config.paths, ); } - Subcommand::Suggest { run } => { - return core::build_steps::suggest::suggest(&builder::Builder::new(self), *run); - } Subcommand::Perf(args) => { return core::build_steps::perf::perf(&builder::Builder::new(self), args); } diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index dcafeb80f90c..778591189a3c 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -67,7 +67,6 @@ pub fn fill_compilers(build: &mut Build) { // We don't need to check cross targets for these commands. crate::Subcommand::Clean { .. } | crate::Subcommand::Check { .. } - | crate::Subcommand::Suggest { .. } | crate::Subcommand::Format { .. } | crate::Subcommand::Setup { .. } => { build.hosts.iter().cloned().chain(iter::once(build.host_target)).collect() diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs index 862c44496241..9b1ccc32cb61 100644 --- a/src/bootstrap/src/utils/metrics.rs +++ b/src/bootstrap/src/utils/metrics.rs @@ -43,7 +43,7 @@ pub(crate) struct BuildMetrics { state: RefCell, } -/// NOTE: this isn't really cloning anything, but `x suggest` doesn't need metrics so this is probably ok. +// NOTE: this isn't really cloning anything, but necessary for `Build: Clone`. impl Clone for BuildMetrics { fn clone(&self) -> Self { Self::init() diff --git a/src/tools/suggest-tests/Cargo.toml b/src/tools/suggest-tests/Cargo.toml deleted file mode 100644 index d6f86078d7ef..000000000000 --- a/src/tools/suggest-tests/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "suggest-tests" -version = "0.1.0" -edition = "2021" - -[dependencies] -glob = "0.3.0" -build_helper = { version = "0.1.0", path = "../../build_helper" } diff --git a/src/tools/suggest-tests/src/dynamic_suggestions.rs b/src/tools/suggest-tests/src/dynamic_suggestions.rs deleted file mode 100644 index f09720f1c91f..000000000000 --- a/src/tools/suggest-tests/src/dynamic_suggestions.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::path::Path; - -use crate::Suggestion; - -type DynamicSuggestion = fn(&Path) -> Vec; - -pub(crate) const DYNAMIC_SUGGESTIONS: &[DynamicSuggestion] = &[ - |path: &Path| -> Vec { - if path.starts_with("compiler/") || path.starts_with("library/") { - let path = path.components().take(2).collect::>(); - - vec![Suggestion::with_single_path( - "test", - None, - &format!( - "{}/{}", - path[0].as_os_str().to_str().unwrap(), - path[1].as_os_str().to_str().unwrap() - ), - )] - } else { - Vec::new() - } - }, - |path: &Path| -> Vec { - if path.starts_with("compiler/rustc_pattern_analysis") { - vec![Suggestion::new("test", None, &["tests/ui", "--test-args", "pattern"])] - } else { - Vec::new() - } - }, -]; diff --git a/src/tools/suggest-tests/src/lib.rs b/src/tools/suggest-tests/src/lib.rs deleted file mode 100644 index cc1288c6b72e..000000000000 --- a/src/tools/suggest-tests/src/lib.rs +++ /dev/null @@ -1,96 +0,0 @@ -use std::fmt::{self, Display}; -use std::path::Path; - -use dynamic_suggestions::DYNAMIC_SUGGESTIONS; -use glob::Pattern; -use static_suggestions::static_suggestions; - -mod dynamic_suggestions; -mod static_suggestions; - -#[cfg(test)] -mod tests; - -macro_rules! sug { - ($cmd:expr) => { - Suggestion::new($cmd, None, &[]) - }; - - ($cmd:expr, $paths:expr) => { - Suggestion::new($cmd, None, $paths.as_slice()) - }; - - ($cmd:expr, $stage:expr, $paths:expr) => { - Suggestion::new($cmd, Some($stage), $paths.as_slice()) - }; -} - -pub(crate) use sug; - -pub fn get_suggestions>(modified_files: &[T]) -> Vec { - let mut suggestions = Vec::new(); - - // static suggestions - for (globs, sugs) in static_suggestions().iter() { - let globs = globs - .iter() - .map(|glob| Pattern::new(glob).expect("Found invalid glob pattern!")) - .collect::>(); - let matches_some_glob = |file: &str| globs.iter().any(|glob| glob.matches(file)); - - if modified_files.iter().map(AsRef::as_ref).any(matches_some_glob) { - suggestions.extend_from_slice(sugs); - } - } - - // dynamic suggestions - for sug in DYNAMIC_SUGGESTIONS { - for file in modified_files { - let sugs = sug(Path::new(file.as_ref())); - - suggestions.extend_from_slice(&sugs); - } - } - - suggestions.sort(); - suggestions.dedup(); - - suggestions -} - -#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug)] -pub struct Suggestion { - pub cmd: String, - pub stage: Option, - pub paths: Vec, -} - -impl Suggestion { - pub fn new(cmd: &str, stage: Option, paths: &[&str]) -> Self { - Self { cmd: cmd.to_owned(), stage, paths: paths.iter().map(|p| p.to_string()).collect() } - } - - pub fn with_single_path(cmd: &str, stage: Option, path: &str) -> Self { - Self::new(cmd, stage, &[path]) - } -} - -impl Display for Suggestion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - write!(f, "{} ", self.cmd)?; - - for path in &self.paths { - write!(f, "{} ", path)?; - } - - if let Some(stage) = self.stage { - write!(f, "{}", stage)?; - } else { - // write a sentinel value here (in place of a stage) to be consumed - // by the shim in bootstrap, it will be read and ignored. - write!(f, "N/A")?; - } - - Ok(()) - } -} diff --git a/src/tools/suggest-tests/src/main.rs b/src/tools/suggest-tests/src/main.rs deleted file mode 100644 index d84f8e9fa1ba..000000000000 --- a/src/tools/suggest-tests/src/main.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::process::ExitCode; - -use build_helper::git::{GitConfig, get_git_modified_files}; -use suggest_tests::get_suggestions; - -fn main() -> ExitCode { - let modified_files = get_git_modified_files( - &GitConfig { - nightly_branch: &env("SUGGEST_TESTS_NIGHTLY_BRANCH"), - git_merge_commit_email: &env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL"), - }, - None, - &Vec::new(), - ); - let modified_files = match modified_files { - Ok(files) => files, - Err(err) => { - eprintln!("Could not get modified files from git: \"{err}\""); - return ExitCode::FAILURE; - } - }; - - let suggestions = get_suggestions(&modified_files); - - for sug in &suggestions { - println!("{sug}"); - } - - ExitCode::SUCCESS -} - -fn env(key: &str) -> String { - match std::env::var(key) { - Ok(var) => var, - Err(err) => { - eprintln!("suggest-tests: failed to read environment variable {key}: {err}"); - std::process::exit(1); - } - } -} diff --git a/src/tools/suggest-tests/src/static_suggestions.rs b/src/tools/suggest-tests/src/static_suggestions.rs deleted file mode 100644 index d363d583b546..000000000000 --- a/src/tools/suggest-tests/src/static_suggestions.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::sync::OnceLock; - -use crate::{Suggestion, sug}; - -// FIXME: perhaps this could use `std::lazy` when it is stabilized -macro_rules! static_suggestions { - ($( [ $( $glob:expr ),* $(,)? ] => [ $( $suggestion:expr ),* $(,)? ] ),* $(,)? ) => { - pub(crate) fn static_suggestions() -> &'static [(Vec<&'static str>, Vec)] - { - static S: OnceLock, Vec)>> = OnceLock::new(); - S.get_or_init(|| vec![ $( (vec![ $($glob),* ], vec![ $($suggestion),* ]) ),*]) - } - } -} - -static_suggestions! { - ["*.md"] => [ - sug!("test", 0, ["linkchecker"]), - ], - - ["compiler/*"] => [ - sug!("check"), - sug!("test", 1, ["tests/ui", "tests/run-make"]), - ], - - ["compiler/rustc_mir_transform/*"] => [ - sug!("test", 1, ["mir-opt"]), - ], - - [ - "compiler/rustc_mir_transform/src/coverage/*", - "compiler/rustc_codegen_llvm/src/coverageinfo/*", - ] => [ - sug!("test", 1, ["coverage"]), - ], - - ["src/librustdoc/*"] => [ - sug!("test", 1, ["rustdoc"]), - ], -} diff --git a/src/tools/suggest-tests/src/tests.rs b/src/tools/suggest-tests/src/tests.rs deleted file mode 100644 index b4149136fa30..000000000000 --- a/src/tools/suggest-tests/src/tests.rs +++ /dev/null @@ -1,21 +0,0 @@ -macro_rules! sugg_test { - ( $( $name:ident: $paths:expr => $suggestions:expr ),* ) => { - $( - #[test] - fn $name() { - let suggestions = crate::get_suggestions(&$paths).into_iter().map(|s| s.to_string()).collect::>(); - assert_eq!(suggestions, $suggestions); - } - )* - }; -} - -sugg_test! { - test_error_code_docs: ["compiler/rustc_error_codes/src/error_codes/E0000.md"] => - ["check N/A", "test compiler/rustc_error_codes N/A", "test linkchecker 0", "test tests/ui tests/run-make 1"], - - test_rustdoc: ["src/librustdoc/src/lib.rs"] => ["test rustdoc 1"], - - test_rustdoc_and_libstd: ["src/librustdoc/src/lib.rs", "library/std/src/lib.rs"] => - ["test library/std N/A", "test rustdoc 1"] -} From 647c051feca0a8b2e7e63bd1009917ea963b8bc7 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 8 Jul 2025 17:53:58 +0800 Subject: [PATCH 155/363] Regenerate completions after removing `./x suggest` --- src/etc/completions/x.fish | 37 ------- src/etc/completions/x.ps1 | 44 -------- src/etc/completions/x.py.fish | 37 ------- src/etc/completions/x.py.ps1 | 44 -------- src/etc/completions/x.py.sh | 191 +--------------------------------- src/etc/completions/x.py.zsh | 51 --------- src/etc/completions/x.sh | 191 +--------------------------------- src/etc/completions/x.zsh | 51 --------- 8 files changed, 2 insertions(+), 644 deletions(-) diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index d3da1f353e24..28a228d54645 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -73,7 +73,6 @@ complete -c x -n "__fish_x_needs_command" -a "dist" -d 'Build distribution artif complete -c x -n "__fish_x_needs_command" -a "install" -d 'Install distribution artifacts' complete -c x -n "__fish_x_needs_command" -a "run" -d 'Run tools contained in this repository' complete -c x -n "__fish_x_needs_command" -a "setup" -d 'Set up the environment for development' -complete -c x -n "__fish_x_needs_command" -a "suggest" -d 'Suggest a subset of tests to run, based on modified files' complete -c x -n "__fish_x_needs_command" -a "vendor" -d 'Vendor dependencies' complete -c x -n "__fish_x_needs_command" -a "perf" -d 'Perform profiling and benchmarking of the compiler using `rustc-perf`' complete -c x -n "__fish_x_using_subcommand build" -l config -d 'TOML configuration file for build' -r -F @@ -599,42 +598,6 @@ complete -c x -n "__fish_x_using_subcommand setup" -l enable-bolt-settings -d 'E complete -c x -n "__fish_x_using_subcommand setup" -l skip-stage0-validation -d 'Skip stage0 compiler validation' complete -c x -n "__fish_x_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c x -n "__fish_x_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand suggest" -l build -d 'host target of the stage0 compiler' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l host -d 'host targets to build' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l target -d 'target targets to build' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l exclude -d 'build paths to exclude' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l skip -d 'build paths to skip' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l rustc-error-format -d 'rustc error format' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" -complete -c x -n "__fish_x_using_subcommand suggest" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand suggest" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny\t'',warn\t'',default\t''}" -complete -c x -n "__fish_x_using_subcommand suggest" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always\t'',never\t'',auto\t''}" -complete -c x -n "__fish_x_using_subcommand suggest" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r -complete -c x -n "__fish_x_using_subcommand suggest" -l set -d 'override options in bootstrap.toml' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" -complete -c x -n "__fish_x_using_subcommand suggest" -l run -d 'run suggested tests' -complete -c x -n "__fish_x_using_subcommand suggest" -s v -l verbose -d 'use verbose output (-vv for very verbose)' -complete -c x -n "__fish_x_using_subcommand suggest" -s i -l incremental -d 'use incremental compilation' -complete -c x -n "__fish_x_using_subcommand suggest" -l include-default-paths -d 'include default paths in addition to the provided ones' -complete -c x -n "__fish_x_using_subcommand suggest" -l dry-run -d 'dry run; don\'t build anything' -complete -c x -n "__fish_x_using_subcommand suggest" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims' -complete -c x -n "__fish_x_using_subcommand suggest" -l json-output -d 'use message-format=json' -complete -c x -n "__fish_x_using_subcommand suggest" -l compile-time-deps -d 'only build proc-macros and build scripts (for rust-analyzer)' -complete -c x -n "__fish_x_using_subcommand suggest" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)' -complete -c x -n "__fish_x_using_subcommand suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' -complete -c x -n "__fish_x_using_subcommand suggest" -l enable-bolt-settings -d 'Enable BOLT link flags' -complete -c x -n "__fish_x_using_subcommand suggest" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' -complete -c x -n "__fish_x_using_subcommand suggest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F complete -c x -n "__fish_x_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand vendor" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index b5b59c58bbae..0c9b38282731 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -74,7 +74,6 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('install', 'install', [CompletionResultType]::ParameterValue, 'Install distribution artifacts') [CompletionResult]::new('run', 'run', [CompletionResultType]::ParameterValue, 'Run tools contained in this repository') [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development') - [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files') [CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies') [CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using `rustc-perf`') break @@ -700,49 +699,6 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break } - 'x;suggest' { - [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') - [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') - [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') - [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') - [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') - [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') - [CompletionResult]::new('--rustc-error-format', '--rustc-error-format', [CompletionResultType]::ParameterName, 'rustc error format') - [CompletionResult]::new('--on-fail', '--on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') - [CompletionResult]::new('--stage', '--stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') - [CompletionResult]::new('--keep-stage', '--keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') - [CompletionResult]::new('--keep-stage-std', '--keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') - [CompletionResult]::new('--src', '--src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') - [CompletionResult]::new('-j', '-j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') - [CompletionResult]::new('--jobs', '--jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') - [CompletionResult]::new('--warnings', '--warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') - [CompletionResult]::new('--color', '--color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') - [CompletionResult]::new('--rust-profile-generate', '--rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') - [CompletionResult]::new('--rust-profile-use', '--rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') - [CompletionResult]::new('--llvm-profile-use', '--llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') - [CompletionResult]::new('--reproducible-artifact', '--reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive') - [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') - [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') - [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'run suggested tests') - [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') - [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') - [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') - [CompletionResult]::new('--incremental', '--incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') - [CompletionResult]::new('--include-default-paths', '--include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') - [CompletionResult]::new('--dry-run', '--dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') - [CompletionResult]::new('--dump-bootstrap-shims', '--dump-bootstrap-shims', [CompletionResultType]::ParameterName, 'Indicates whether to dump the work done from bootstrap shims') - [CompletionResult]::new('--json-output', '--json-output', [CompletionResultType]::ParameterName, 'use message-format=json') - [CompletionResult]::new('--compile-time-deps', '--compile-time-deps', [CompletionResultType]::ParameterName, 'only build proc-macros and build scripts (for rust-analyzer)') - [CompletionResult]::new('--bypass-bootstrap-lock', '--bypass-bootstrap-lock', [CompletionResultType]::ParameterName, 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)') - [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') - [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') - [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') - break - } 'x;vendor' { [CompletionResult]::new('--sync', '--sync', [CompletionResultType]::ParameterName, 'Additional `Cargo.toml` to sync and vendor') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index da7680a879de..43ae7424e27b 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -73,7 +73,6 @@ complete -c x.py -n "__fish_x.py_needs_command" -a "dist" -d 'Build distribution complete -c x.py -n "__fish_x.py_needs_command" -a "install" -d 'Install distribution artifacts' complete -c x.py -n "__fish_x.py_needs_command" -a "run" -d 'Run tools contained in this repository' complete -c x.py -n "__fish_x.py_needs_command" -a "setup" -d 'Set up the environment for development' -complete -c x.py -n "__fish_x.py_needs_command" -a "suggest" -d 'Suggest a subset of tests to run, based on modified files' complete -c x.py -n "__fish_x.py_needs_command" -a "vendor" -d 'Vendor dependencies' complete -c x.py -n "__fish_x.py_needs_command" -a "perf" -d 'Perform profiling and benchmarking of the compiler using `rustc-perf`' complete -c x.py -n "__fish_x.py_using_subcommand build" -l config -d 'TOML configuration file for build' -r -F @@ -599,42 +598,6 @@ complete -c x.py -n "__fish_x.py_using_subcommand setup" -l enable-bolt-settings complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-stage0-validation -d 'Skip stage0 compiler validation' complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build -d 'host target of the stage0 compiler' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l host -d 'host targets to build' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l target -d 'target targets to build' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l exclude -d 'build paths to exclude' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip -d 'build paths to skip' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l rustc-error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny\t'',warn\t'',default\t''}" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always\t'',never\t'',auto\t''}" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l set -d 'override options in bootstrap.toml' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l run -d 'run suggested tests' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s v -l verbose -d 'use verbose output (-vv for very verbose)' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s i -l incremental -d 'use incremental compilation' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l include-default-paths -d 'include default paths in addition to the provided ones' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l dry-run -d 'dry run; don\'t build anything' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l json-output -d 'use message-format=json' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l compile-time-deps -d 'only build proc-macros and build scripts (for rust-analyzer)' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l enable-bolt-settings -d 'Enable BOLT link flags' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index 3fc8e7d5bbd9..4311e383d640 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -74,7 +74,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('install', 'install', [CompletionResultType]::ParameterValue, 'Install distribution artifacts') [CompletionResult]::new('run', 'run', [CompletionResultType]::ParameterValue, 'Run tools contained in this repository') [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development') - [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files') [CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies') [CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using `rustc-perf`') break @@ -700,49 +699,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break } - 'x.py;suggest' { - [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') - [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') - [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') - [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') - [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') - [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') - [CompletionResult]::new('--rustc-error-format', '--rustc-error-format', [CompletionResultType]::ParameterName, 'rustc error format') - [CompletionResult]::new('--on-fail', '--on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') - [CompletionResult]::new('--stage', '--stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') - [CompletionResult]::new('--keep-stage', '--keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') - [CompletionResult]::new('--keep-stage-std', '--keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') - [CompletionResult]::new('--src', '--src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') - [CompletionResult]::new('-j', '-j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') - [CompletionResult]::new('--jobs', '--jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') - [CompletionResult]::new('--warnings', '--warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') - [CompletionResult]::new('--color', '--color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') - [CompletionResult]::new('--rust-profile-generate', '--rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') - [CompletionResult]::new('--rust-profile-use', '--rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') - [CompletionResult]::new('--llvm-profile-use', '--llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') - [CompletionResult]::new('--reproducible-artifact', '--reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive') - [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') - [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') - [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'run suggested tests') - [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') - [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') - [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') - [CompletionResult]::new('--incremental', '--incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') - [CompletionResult]::new('--include-default-paths', '--include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') - [CompletionResult]::new('--dry-run', '--dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') - [CompletionResult]::new('--dump-bootstrap-shims', '--dump-bootstrap-shims', [CompletionResultType]::ParameterName, 'Indicates whether to dump the work done from bootstrap shims') - [CompletionResult]::new('--json-output', '--json-output', [CompletionResultType]::ParameterName, 'use message-format=json') - [CompletionResult]::new('--compile-time-deps', '--compile-time-deps', [CompletionResultType]::ParameterName, 'only build proc-macros and build scripts (for rust-analyzer)') - [CompletionResult]::new('--bypass-bootstrap-lock', '--bypass-bootstrap-lock', [CompletionResultType]::ParameterName, 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)') - [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') - [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') - [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') - break - } 'x.py;vendor' { [CompletionResult]::new('--sync', '--sync', [CompletionResultType]::ParameterName, 'Additional `Cargo.toml` to sync and vendor') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 8f13de282fb7..f31bdb58dc44 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -54,9 +54,6 @@ _x.py() { x.py,setup) cmd="x.py__setup" ;; - x.py,suggest) - cmd="x.py__suggest" - ;; x.py,test) cmd="x.py__test" ;; @@ -85,7 +82,7 @@ _x.py() { case "${cmd}" in x.py) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup vendor perf" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3877,192 +3874,6 @@ _x.py() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - x.py__suggest) - opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --config) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --build-dir) - COMPREPLY=() - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o plusdirs - fi - return 0 - ;; - --build) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --host) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --target) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --exclude) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --skip) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --rustc-error-format) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --on-fail) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --stage) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --keep-stage) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --keep-stage-std) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --src) - COMPREPLY=() - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o plusdirs - fi - return 0 - ;; - --jobs) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - -j) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --warnings) - COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) - return 0 - ;; - --color) - COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) - return 0 - ;; - --rust-profile-generate) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --rust-profile-use) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --llvm-profile-use) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --reproducible-artifact) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --set) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --ci) - COMPREPLY=($(compgen -W "true false" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; x.py__test) opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 60ce90021162..aff35b31e212 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -715,51 +715,6 @@ _arguments "${_arguments_options[@]}" : \ '*::paths -- paths for the subcommand:_files' \ && ret=0 ;; -(suggest) -_arguments "${_arguments_options[@]}" : \ -'--config=[TOML configuration file for build]:FILE:_files' \ -'--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[host target of the stage0 compiler]:BUILD:' \ -'--host=[host targets to build]:HOST:' \ -'--target=[target targets to build]:TARGET:' \ -'*--exclude=[build paths to exclude]:PATH:_files' \ -'*--skip=[build paths to skip]:PATH:_files' \ -'--rustc-error-format=[rustc error format]:RUSTC_ERROR_FORMAT:' \ -'--on-fail=[command to run on failure]:CMD:_cmdstring' \ -'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:' \ -'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \ -'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \ -'--src=[path to the root of the rust checkout]:DIR:_files -/' \ -'-j+[number of jobs to run in parallel]:JOBS:' \ -'--jobs=[number of jobs to run in parallel]:JOBS:' \ -'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ -'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ -'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ -'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ -'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ -'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT:_default' \ -'*--set=[override options in bootstrap.toml]:section.option=value:' \ -'--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ -'--run[run suggested tests]' \ -'*-v[use verbose output (-vv for very verbose)]' \ -'*--verbose[use verbose output (-vv for very verbose)]' \ -'-i[use incremental compilation]' \ -'--incremental[use incremental compilation]' \ -'--include-default-paths[include default paths in addition to the provided ones]' \ -'--dry-run[dry run; don'\''t build anything]' \ -'--dump-bootstrap-shims[Indicates whether to dump the work done from bootstrap shims]' \ -'--json-output[use message-format=json]' \ -'--compile-time-deps[only build proc-macros and build scripts (for rust-analyzer)]' \ -'--bypass-bootstrap-lock[Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)]' \ -'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ -'--enable-bolt-settings[Enable BOLT link flags]' \ -'--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::paths -- paths for the subcommand:_files' \ -&& ret=0 -;; (vendor) _arguments "${_arguments_options[@]}" : \ '*--sync=[Additional \`Cargo.toml\` to sync and vendor]:SYNC:_files' \ @@ -1120,7 +1075,6 @@ _x.py_commands() { 'install:Install distribution artifacts' \ 'run:Run tools contained in this repository' \ 'setup:Set up the environment for development' \ -'suggest:Suggest a subset of tests to run, based on modified files' \ 'vendor:Vendor dependencies' \ 'perf:Perform profiling and benchmarking of the compiler using \`rustc-perf\`' \ ) @@ -1227,11 +1181,6 @@ _x.py__setup_commands() { local commands; commands=() _describe -t commands 'x.py setup commands' commands "$@" } -(( $+functions[_x.py__suggest_commands] )) || -_x.py__suggest_commands() { - local commands; commands=() - _describe -t commands 'x.py suggest commands' commands "$@" -} (( $+functions[_x.py__test_commands] )) || _x.py__test_commands() { local commands; commands=() diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh index f6ecf4cebf49..927d8f7661cd 100644 --- a/src/etc/completions/x.sh +++ b/src/etc/completions/x.sh @@ -54,9 +54,6 @@ _x() { x,setup) cmd="x__setup" ;; - x,suggest) - cmd="x__suggest" - ;; x,test) cmd="x__test" ;; @@ -85,7 +82,7 @@ _x() { case "${cmd}" in x) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup vendor perf" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3877,192 +3874,6 @@ _x() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - x__suggest) - opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --config) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --build-dir) - COMPREPLY=() - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o plusdirs - fi - return 0 - ;; - --build) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --host) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --target) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --exclude) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --skip) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --rustc-error-format) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --on-fail) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --stage) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --keep-stage) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --keep-stage-std) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --src) - COMPREPLY=() - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o plusdirs - fi - return 0 - ;; - --jobs) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - -j) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --warnings) - COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) - return 0 - ;; - --color) - COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) - return 0 - ;; - --rust-profile-generate) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --rust-profile-use) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --llvm-profile-use) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --reproducible-artifact) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --set) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --ci) - COMPREPLY=($(compgen -W "true false" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; x__test) opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index 452a26fef07e..28ad00f3a0de 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -715,51 +715,6 @@ _arguments "${_arguments_options[@]}" : \ '*::paths -- paths for the subcommand:_files' \ && ret=0 ;; -(suggest) -_arguments "${_arguments_options[@]}" : \ -'--config=[TOML configuration file for build]:FILE:_files' \ -'--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[host target of the stage0 compiler]:BUILD:' \ -'--host=[host targets to build]:HOST:' \ -'--target=[target targets to build]:TARGET:' \ -'*--exclude=[build paths to exclude]:PATH:_files' \ -'*--skip=[build paths to skip]:PATH:_files' \ -'--rustc-error-format=[rustc error format]:RUSTC_ERROR_FORMAT:' \ -'--on-fail=[command to run on failure]:CMD:_cmdstring' \ -'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:' \ -'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \ -'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \ -'--src=[path to the root of the rust checkout]:DIR:_files -/' \ -'-j+[number of jobs to run in parallel]:JOBS:' \ -'--jobs=[number of jobs to run in parallel]:JOBS:' \ -'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ -'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ -'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ -'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ -'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ -'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT:_default' \ -'*--set=[override options in bootstrap.toml]:section.option=value:' \ -'--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ -'--run[run suggested tests]' \ -'*-v[use verbose output (-vv for very verbose)]' \ -'*--verbose[use verbose output (-vv for very verbose)]' \ -'-i[use incremental compilation]' \ -'--incremental[use incremental compilation]' \ -'--include-default-paths[include default paths in addition to the provided ones]' \ -'--dry-run[dry run; don'\''t build anything]' \ -'--dump-bootstrap-shims[Indicates whether to dump the work done from bootstrap shims]' \ -'--json-output[use message-format=json]' \ -'--compile-time-deps[only build proc-macros and build scripts (for rust-analyzer)]' \ -'--bypass-bootstrap-lock[Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)]' \ -'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ -'--enable-bolt-settings[Enable BOLT link flags]' \ -'--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::paths -- paths for the subcommand:_files' \ -&& ret=0 -;; (vendor) _arguments "${_arguments_options[@]}" : \ '*--sync=[Additional \`Cargo.toml\` to sync and vendor]:SYNC:_files' \ @@ -1120,7 +1075,6 @@ _x_commands() { 'install:Install distribution artifacts' \ 'run:Run tools contained in this repository' \ 'setup:Set up the environment for development' \ -'suggest:Suggest a subset of tests to run, based on modified files' \ 'vendor:Vendor dependencies' \ 'perf:Perform profiling and benchmarking of the compiler using \`rustc-perf\`' \ ) @@ -1227,11 +1181,6 @@ _x__setup_commands() { local commands; commands=() _describe -t commands 'x setup commands' commands "$@" } -(( $+functions[_x__suggest_commands] )) || -_x__suggest_commands() { - local commands; commands=() - _describe -t commands 'x suggest commands' commands "$@" -} (( $+functions[_x__test_commands] )) || _x__test_commands() { local commands; commands=() From 186afbb911b561d7f10efa9c5a729715f2db4131 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 8 Jul 2025 17:58:49 +0800 Subject: [PATCH 156/363] Remove mentions of `./x suggest` and `suggest-tests` in rustc-dev-guide --- src/doc/rustc-dev-guide/src/SUMMARY.md | 1 - .../src/building/quickstart.md | 3 - .../rustc-dev-guide/src/building/suggested.md | 17 ------ .../src/tests/suggest-tests.md | 59 ------------------- 4 files changed, 80 deletions(-) delete mode 100644 src/doc/rustc-dev-guide/src/tests/suggest-tests.md diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 7f2f32c62ffb..651e2925ad50 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -35,7 +35,6 @@ - [Cranelift codegen backend](./tests/codegen-backend-tests/cg_clif.md) - [GCC codegen backend](./tests/codegen-backend-tests/cg_gcc.md) - [Performance testing](./tests/perf.md) - - [Suggest tests tool](./tests/suggest-tests.md) - [Misc info](./tests/misc.md) - [Debugging the compiler](./compiler-debugging.md) - [Using the tracing/logging instrumentation](./tracing.md) diff --git a/src/doc/rustc-dev-guide/src/building/quickstart.md b/src/doc/rustc-dev-guide/src/building/quickstart.md index 9a8ab353e029..97314d803695 100644 --- a/src/doc/rustc-dev-guide/src/building/quickstart.md +++ b/src/doc/rustc-dev-guide/src/building/quickstart.md @@ -61,9 +61,6 @@ and check the output. Use `--bless` if you've made a change and want to update the `.stderr` files with the new output. -> `./x suggest` can also be helpful for suggesting which tests to run after a -> change. - Congrats, you are now ready to make a change to the compiler! If you have more questions, [the full chapter](./how-to-build-and-run.md) might contain the answers, and if it doesn't, feel free to ask for help on diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index bfb2f4d1084a..7f626314f718 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -270,23 +270,6 @@ run the tests at some later time. You can then use `git bisect` to track down is that you are left with a fairly fine-grained set of commits at the end, all of which build and pass tests. This often helps reviewing. -## `x suggest` - -The `x suggest` subcommand suggests (and runs) a subset of the extensive -`rust-lang/rust` tests based on files you have changed. This is especially -useful for new contributors who have not mastered the arcane `x` flags yet and -more experienced contributors as a shorthand for reducing mental effort. In all -cases it is useful not to run the full tests (which can take on the order of -tens of minutes) and just run a subset which are relevant to your changes. For -example, running `tidy` and `linkchecker` is useful when editing Markdown files, -whereas UI tests are much less likely to be helpful. While `x suggest` is a -useful tool, it does not guarantee perfect coverage (just as PR CI isn't a -substitute for bors). See the [dedicated chapter](../tests/suggest-tests.md) for -more information and contribution instructions. - -Please note that `x suggest` is in a beta state currently and the tests that it -will suggest are limited. - ## Configuring `rustup` to use nightly Some parts of the bootstrap process uses pinned, nightly versions of tools like diff --git a/src/doc/rustc-dev-guide/src/tests/suggest-tests.md b/src/doc/rustc-dev-guide/src/tests/suggest-tests.md deleted file mode 100644 index 663e8a5af3b9..000000000000 --- a/src/doc/rustc-dev-guide/src/tests/suggest-tests.md +++ /dev/null @@ -1,59 +0,0 @@ -# Suggest tests tool - -This chapter is about the internals of and contribution instructions for the -`suggest-tests` tool. For a high-level overview of the tool, see [this -section](../building/suggested.md#x-suggest). This tool is currently in a beta -state and is tracked by [this](https://github.com/rust-lang/rust/issues/109933) -issue on Github. Currently the number of tests it will suggest are very limited -in scope, we are looking to expand this (contributions welcome!). - -## Internals - -The tool is defined in a separate crate -([`src/tools/suggest-tests`](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests)) -which outputs suggestions which are parsed by a shim in bootstrap -([`src/bootstrap/src/core/build_steps/suggest.rs`](https://github.com/rust-lang/rust/blob/master/src/bootstrap/src/core/build_steps/suggest.rs)). -The only notable thing the bootstrap shim does is (when invoked with the `--run` -flag) use bootstrap's internal mechanisms to create a new `Builder` and uses it -to invoke the suggested commands. The `suggest-tests` crate is where the fun -happens, two kinds of suggestions are defined: "static" and "dynamic" -suggestions. - -### Static suggestions - -Defined -[here](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests/src/static_suggestions.rs). -Static suggestions are simple: they are just -[globs](https://crates.io/crates/glob) which map to a `x` command. In -`suggest-tests`, this is implemented with a simple `macro_rules` macro. - -### Dynamic suggestions - -Defined -[here](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests/src/dynamic_suggestions.rs). -These are more complicated than static suggestions and are implemented as -functions with the following signature: `fn(&Path) -> Vec`. In other -words, each suggestion takes a path to a modified file and (after running -arbitrary Rust code) can return any number of suggestions, or none. Dynamic -suggestions are useful for situations where fine-grained control over -suggestions is needed. For example, modifications to the `compiler/xyz/` path -should trigger the `x test compiler/xyz` suggestion. In the future, dynamic -suggestions might even read file contents to determine if (what) tests should -run. - -## Adding a suggestion - -The following steps should serve as a rough guide to add suggestions to -`suggest-tests` (very welcome!): - -1. Determine the rules for your suggestion. Is it simple and operates only on a - single path or does it match globs? Does it need fine-grained control over - the resulting command or does "one size fit all"? -2. Based on the previous step, decide if your suggestion should be implemented - as either static or dynamic. -3. Implement the suggestion. If it is dynamic then a test is highly recommended, - to verify that your logic is correct and to give an example of the - suggestion. See the - [tests.rs](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests/src/tests.rs) - file. -4. Open a PR implementing your suggestion. **(TODO: add example PR)** From 0a899e0e8ad99d2e7afd1dd8e8466d6a14a04787 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 8 Jul 2025 17:59:54 +0800 Subject: [PATCH 157/363] Update triagebot autolabel --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 125617fce74f..714bb8d4b974 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -506,7 +506,6 @@ trigger_files = [ "src/tools/remote-test-server", "src/tools/remote-test-client", "src/tools/rustdoc-gui-test", - "src/tools/suggest-tests", ] [autolabel."A-tidy"] From 1669ba055c1e02c459df42926f8762bc27b8ada8 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 14 Jul 2025 19:01:40 +0200 Subject: [PATCH 158/363] Update books --- src/doc/book | 2 +- src/doc/embedded-book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book b/src/doc/book index ef1ce8f87a8b..b2d1a0821e12 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit ef1ce8f87a8b18feb1b6a9cf9a4939a79bde6795 +Subproject commit b2d1a0821e12a676b496d61891b8e3d374a8e832 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index 41f688a598a5..fe88fbb68391 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit 41f688a598a5022b749e23d37f3c524f6a0b28e1 +Subproject commit fe88fbb68391a465680dd91109f0a151a1676f3e diff --git a/src/doc/nomicon b/src/doc/nomicon index 8b61acfaea82..3ff384320598 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 8b61acfaea822e9ac926190bc8f15791c33336e8 +Subproject commit 3ff384320598bbe8d8cfe5cb8f18f78a3a3e6b15 diff --git a/src/doc/reference b/src/doc/reference index e9fc99f10784..1f45bd41fa6c 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit e9fc99f107840813916f62e16b3f6d9556e1f2d8 +Subproject commit 1f45bd41fa6c17b7c048ed6bfe5f168c4311206a diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 288b4e4948ad..e386be5f44af 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 288b4e4948add43f387cad35adc7b1c54ca6fe12 +Subproject commit e386be5f44af711854207c11fdd61bb576270b04 From 9bdd3b0ee6a6fd5914fea0f56f3b754410733e53 Mon Sep 17 00:00:00 2001 From: Paul Murphy Date: Thu, 10 Jul 2025 10:58:58 -0500 Subject: [PATCH 159/363] Don't always panic if WASI_SDK_PATH is not set when detecting compilers They are not always needed when building std, as is the case when packaging on Fedora. Panic if building from CI, but warn otherwise. --- src/bootstrap/src/utils/cc_detect.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index dcafeb80f90c..2569f95e3efa 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -221,10 +221,15 @@ fn default_compiler( } t if t.contains("-wasi") => { - let root = build - .wasi_sdk_path - .as_ref() - .expect("WASI_SDK_PATH mut be configured for a -wasi target"); + let root = if let Some(path) = build.wasi_sdk_path.as_ref() { + path + } else { + if build.config.is_running_on_ci { + panic!("ERROR: WASI_SDK_PATH must be configured for a -wasi target on CI"); + } + println!("WARNING: WASI_SDK_PATH not set, using default cc/cxx compiler"); + return None; + }; let compiler = match compiler { Language::C => format!("{t}-clang"), Language::CPlusPlus => format!("{t}-clang++"), From d0153f5872c484dff2a4b0ef6cad45c1f14fa1b7 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 14 Jul 2025 11:03:16 +0200 Subject: [PATCH 160/363] update `cfg_select!` documentation and make internal terminology consistent Co-authored-by: Travis Cross --- compiler/rustc_builtin_macros/messages.ftl | 6 +++--- compiler/rustc_builtin_macros/src/cfg_select.rs | 16 ++++++++-------- compiler/rustc_parse/src/parser/cfg_select.rs | 10 ++++++---- library/core/src/macros/mod.rs | 16 +++++++--------- tests/ui/macros/cfg_select.rs | 7 +++++-- tests/ui/macros/cfg_select.stderr | 14 ++++++++++---- 6 files changed, 39 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 183927edb022..ae186d744c40 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -81,11 +81,11 @@ builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a l builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified -builtin_macros_cfg_select_no_matches = none of the rules in this `cfg_select` evaluated to true +builtin_macros_cfg_select_no_matches = none of the predicates in this `cfg_select` evaluated to true -builtin_macros_cfg_select_unreachable = unreachable rule +builtin_macros_cfg_select_unreachable = unreachable predicate .label = always matches - .label2 = this rules is never reached + .label2 = this predicate is never reached builtin_macros_coerce_pointee_requires_maybe_sized = `derive(CoercePointee)` requires `{$name}` to be marked `?Sized` diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs index 2dc387d5866a..f22d5f255c29 100644 --- a/compiler/rustc_builtin_macros/src/cfg_select.rs +++ b/compiler/rustc_builtin_macros/src/cfg_select.rs @@ -1,12 +1,12 @@ use rustc_ast::tokenstream::TokenStream; use rustc_attr_parsing as attr; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; -use rustc_parse::parser::cfg_select::{CfgSelectBranches, CfgSelectRule, parse_cfg_select}; +use rustc_parse::parser::cfg_select::{CfgSelectBranches, CfgSelectPredicate, parse_cfg_select}; use rustc_span::{Ident, Span, sym}; use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable}; -/// Selects the first arm whose rule evaluates to true. +/// Selects the first arm whose predicate evaluates to true. fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> { for (cfg, tt, arm_span) in branches.reachable { if attr::cfg_matches( @@ -30,11 +30,11 @@ pub(super) fn expand_cfg_select<'cx>( ExpandResult::Ready(match parse_cfg_select(&mut ecx.new_parser_from_tts(tts)) { Ok(branches) => { if let Some((underscore, _, _)) = branches.wildcard { - // Warn for every unreachable rule. We store the fully parsed branch for rustfmt. - for (rule, _, _) in &branches.unreachable { - let span = match rule { - CfgSelectRule::Wildcard(underscore) => underscore.span, - CfgSelectRule::Cfg(cfg) => cfg.span(), + // Warn for every unreachable predicate. We store the fully parsed branch for rustfmt. + for (predicate, _, _) in &branches.unreachable { + let span = match predicate { + CfgSelectPredicate::Wildcard(underscore) => underscore.span, + CfgSelectPredicate::Cfg(cfg) => cfg.span(), }; let err = CfgSelectUnreachable { span, wildcard_span: underscore.span }; ecx.dcx().emit_warn(err); @@ -50,7 +50,7 @@ pub(super) fn expand_cfg_select<'cx>( Ident::with_dummy_span(sym::cfg_select), ); } else { - // Emit a compiler error when none of the rules matched. + // Emit a compiler error when none of the predicates matched. let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp }); DummyResult::any(sp, guar) } diff --git a/compiler/rustc_parse/src/parser/cfg_select.rs b/compiler/rustc_parse/src/parser/cfg_select.rs index 24a05afff4ac..2c6fb224d70d 100644 --- a/compiler/rustc_parse/src/parser/cfg_select.rs +++ b/compiler/rustc_parse/src/parser/cfg_select.rs @@ -7,7 +7,7 @@ use rustc_span::Span; use crate::exp; use crate::parser::Parser; -pub enum CfgSelectRule { +pub enum CfgSelectPredicate { Cfg(MetaItemInner), Wildcard(Token), } @@ -20,7 +20,7 @@ pub struct CfgSelectBranches { pub wildcard: Option<(Token, TokenStream, Span)>, /// All branches after the first wildcard, including further wildcards. /// These branches are kept for formatting. - pub unreachable: Vec<(CfgSelectRule, TokenStream, Span)>, + pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>, } /// Parses a `TokenTree` that must be of the form `{ /* ... */ }`, and returns a `TokenStream` where @@ -52,7 +52,7 @@ pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches match branches.wildcard { None => branches.wildcard = Some((underscore, tts, span)), Some(_) => { - branches.unreachable.push((CfgSelectRule::Wildcard(underscore), tts, span)) + branches.unreachable.push((CfgSelectPredicate::Wildcard(underscore), tts, span)) } } } else { @@ -64,7 +64,9 @@ pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches match branches.wildcard { None => branches.reachable.push((meta_item, tts, span)), - Some(_) => branches.unreachable.push((CfgSelectRule::Cfg(meta_item), tts, span)), + Some(_) => { + branches.unreachable.push((CfgSelectPredicate::Cfg(meta_item), tts, span)) + } } } } diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 6b9cbb064358..1b6dbc2f428f 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -196,16 +196,14 @@ pub macro assert_matches { }, } -/// A macro for defining `#[cfg]` match-like statements. +/// Selects code at compile-time based on `cfg` predicates. /// -/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of -/// `#[cfg]` cases, emitting the implementation which matches first. +/// This macro evaluates, at compile-time, a series of `cfg` predicates, +/// selects the first that is true, and emits the code guarded by that +/// predicate. The code guarded by other predicates is not emitted. /// -/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code -/// without having to rewrite each clause multiple times. -/// -/// Trailing `_` wildcard match arms are **optional** and they indicate a fallback branch when -/// all previous declarations do not evaluate to true. +/// An optional trailing `_` wildcard can be used to specify a fallback. If +/// none of the predicates are true, a [`compile_error`] is emitted. /// /// # Example /// @@ -225,7 +223,7 @@ pub macro assert_matches { /// } /// ``` /// -/// If desired, it is possible to return expressions through the use of surrounding braces: +/// The `cfg_select!` macro can also be used in expression position: /// /// ``` /// #![feature(cfg_select)] diff --git a/tests/ui/macros/cfg_select.rs b/tests/ui/macros/cfg_select.rs index a4d94836a09a..461d2e0e8c1f 100644 --- a/tests/ui/macros/cfg_select.rs +++ b/tests/ui/macros/cfg_select.rs @@ -18,10 +18,13 @@ fn arm_rhs_must_be_in_braces() -> i32 { cfg_select! { _ => {} true => {} - //~^ WARN unreachable rule + //~^ WARN unreachable predicate } cfg_select! { - //~^ ERROR none of the rules in this `cfg_select` evaluated to true + //~^ ERROR none of the predicates in this `cfg_select` evaluated to true false => {} } + +cfg_select! {} +//~^ ERROR none of the predicates in this `cfg_select` evaluated to true diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr index fef5e95a6bce..6c18a7c189dc 100644 --- a/tests/ui/macros/cfg_select.stderr +++ b/tests/ui/macros/cfg_select.stderr @@ -4,15 +4,15 @@ error: expected `{`, found `1` LL | true => 1 | ^ expected `{` -warning: unreachable rule +warning: unreachable predicate --> $DIR/cfg_select.rs:20:5 | LL | _ => {} | - always matches LL | true => {} - | ^^^^ this rules is never reached + | ^^^^ this predicate is never reached -error: none of the rules in this `cfg_select` evaluated to true +error: none of the predicates in this `cfg_select` evaluated to true --> $DIR/cfg_select.rs:24:1 | LL | / cfg_select! { @@ -21,5 +21,11 @@ LL | | false => {} LL | | } | |_^ -error: aborting due to 2 previous errors; 1 warning emitted +error: none of the predicates in this `cfg_select` evaluated to true + --> $DIR/cfg_select.rs:29:1 + | +LL | cfg_select! {} + | ^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 1 warning emitted From f0d0afab8e3c37286d261467df053a9a1635b91a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 13 Jul 2025 11:56:13 +0200 Subject: [PATCH 161/363] Port `#[pointee]` to the new attribute parsing infrastructure Signed-off-by: Jonathan Brouwer --- compiler/rustc_attr_data_structures/src/attributes.rs | 3 +++ .../rustc_attr_data_structures/src/encode_cross_crate.rs | 1 + compiler/rustc_attr_parsing/src/attributes/traits.rs | 7 +++++++ compiler/rustc_attr_parsing/src/context.rs | 5 +++-- compiler/rustc_parse/src/validate_attr.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 16 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 9b14ed88978b..a5c04970e812 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -349,6 +349,9 @@ pub enum AttributeKind { /// Represents `#[path]` Path(Symbol, Span), + /// Represents `#[pointee]` + Pointee(Span), + /// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint). PubTransparent(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 494b570c86c7..3e2dc0a15b2f 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -57,6 +57,7 @@ impl AttributeKind { ParenSugar(..) => No, PassByValue(..) => Yes, Path(..) => No, + Pointee(..) => No, PubTransparent(..) => Yes, Repr { .. } => No, RustcLayoutScalarValidRangeEnd(..) => Yes, diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index ee8a33ae9c43..d5e088effd51 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -145,3 +145,10 @@ impl NoArgsAttributeParser for FundamentalParser { const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Fundamental; } + +pub(crate) struct PointeeParser; +impl NoArgsAttributeParser for PointeeParser { + const PATH: &[Symbol] = &[sym::pointee]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const CREATE: fn(Span) -> AttributeKind = AttributeKind::Pointee; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6c70f2ee4ee0..61638001a2bc 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -48,8 +48,8 @@ use crate::attributes::test_attrs::IgnoreParser; use crate::attributes::traits::{ AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser, DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, - ParenSugarParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser, - UnsafeSpecializationMarkerParser, + ParenSugarParser, PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, + TypeConstParser, UnsafeSpecializationMarkerParser, }; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; @@ -178,6 +178,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 5c748e956a06..b9d387e072c9 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -299,6 +299,7 @@ pub fn check_builtin_meta_item( | sym::align | sym::deprecated | sym::optimize + | sym::pointee | sym::cold | sym::target_feature | sym::rustc_allow_const_fn_unstable diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 820255afe274..2009ddc1e2d5 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -251,6 +251,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect | AttributeKind::MacroTransparency(_) + | AttributeKind::Pointee(..) | AttributeKind::Dummy | AttributeKind::OmitGdbPrettyPrinterSection, ) => { /* do nothing */ } @@ -381,7 +382,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::cfg_attr_trace // need to be fixed | sym::cfi_encoding // FIXME(cfi_encoding) - | sym::pointee // FIXME(derive_coerce_pointee) | sym::instruction_set // broken on stable!!! | sym::windows_subsystem // broken on stable!!! | sym::patchable_function_entry // FIXME(patchable_function_entry) From 02dc14b25c729b8167620d2c2381ebbab20a0a04 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 14 Jul 2025 16:28:32 -0700 Subject: [PATCH 162/363] Update mdbook to 0.4.52 Changelog: https://github.com/rust-lang/mdBook/blob/master/CHANGELOG.md#mdbook-0452 This primarily picks up a few fixes. --- src/tools/rustbook/Cargo.lock | 4 ++-- src/tools/rustbook/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 050ddf47baef..27798d6aeb0b 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -885,9 +885,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.51" +version = "0.4.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a87e65420ab45ca9c1b8cdf698f95b710cc826d373fa550f0f7fad82beac9328" +checksum = "93c284d2855916af7c5919cf9ad897cfc77d3c2db6f55429c7cfb769182030ec" dependencies = [ "ammonia", "anyhow", diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 69c0cfaf5c99..c7c6e39f1577 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -15,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3" mdbook-spec = { path = "../../doc/reference/mdbook-spec" } [dependencies.mdbook] -version = "0.4.51" +version = "0.4.52" default-features = false features = ["search"] From ed88af21637ff3677100fd26f8db354cd6134ad4 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Mon, 14 Jul 2025 04:28:20 +0800 Subject: [PATCH 163/363] Recover and suggest use `;` to construct array type Signed-off-by: xizheyin --- compiler/rustc_parse/src/parser/ty.rs | 59 +++++++++++++- src/tools/tidy/src/issues.txt | 1 - src/tools/tidy/src/ui_tests.rs | 2 +- tests/ui/issues/issue-50571.fixed | 10 --- tests/ui/issues/issue-50571.rs | 10 --- tests/ui/issues/issue-50571.stderr | 15 ---- tests/ui/parser/better-expected.rs | 2 +- tests/ui/parser/better-expected.stderr | 12 ++- .../issues/error-pattern-issue-50571.rs | 11 +++ .../issues/error-pattern-issue-50571.stderr | 28 +++++++ tests/ui/parser/recover/array-type-no-semi.rs | 11 ++- .../parser/recover/array-type-no-semi.stderr | 81 +++++++++++-------- .../removed-syntax-fixed-vec.rs | 7 +- .../removed-syntax-fixed-vec.stderr | 21 ++++- 14 files changed, 183 insertions(+), 87 deletions(-) delete mode 100644 tests/ui/issues/issue-50571.fixed delete mode 100644 tests/ui/issues/issue-50571.rs delete mode 100644 tests/ui/issues/issue-50571.stderr create mode 100644 tests/ui/parser/issues/error-pattern-issue-50571.rs create mode 100644 tests/ui/parser/issues/error-pattern-issue-50571.stderr diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a997be3405d6..740dd10ea8ba 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -575,14 +575,69 @@ impl<'a> Parser<'a> { self.expect(exp!(CloseBracket))?; } TyKind::Array(elt_ty, length) - } else { - self.expect(exp!(CloseBracket))?; + } else if self.eat(exp!(CloseBracket)) { TyKind::Slice(elt_ty) + } else { + self.maybe_recover_array_ty_without_semi(elt_ty)? }; Ok(ty) } + /// Recover from malformed array type syntax. + /// + /// This method attempts to recover from cases like: + /// - `[u8, 5]` → suggests using `;`, return a Array type + /// - `[u8 5]` → suggests using `;`, return a Array type + /// Consider to add more cases in the future. + fn maybe_recover_array_ty_without_semi(&mut self, elt_ty: P) -> PResult<'a, TyKind> { + let span = self.token.span; + let token_descr = super::token_descr(&self.token); + let mut err = + self.dcx().struct_span_err(span, format!("expected `;` or `]`, found {}", token_descr)); + err.span_label(span, "expected `;` or `]`"); + err.note("you might have meant to write a slice or array type"); + + // If we cannot recover, return the error immediately. + if !self.may_recover() { + return Err(err); + } + + let snapshot = self.create_snapshot_for_diagnostic(); + + let suggestion_span = if self.eat(exp!(Comma)) || self.eat(exp!(Star)) { + // Consume common erroneous separators. + self.prev_token.span + } else { + self.token.span.shrink_to_lo() + }; + + // we first try to parse pattern like `[u8 5]` + let length = match self.parse_expr_anon_const() { + Ok(length) => length, + Err(e) => { + e.cancel(); + self.restore_snapshot(snapshot); + return Err(err); + } + }; + + if let Err(e) = self.expect(exp!(CloseBracket)) { + e.cancel(); + self.restore_snapshot(snapshot); + return Err(err); + } + + err.span_suggestion_verbose( + suggestion_span, + "you might have meant to use `;` as the separator", + ";", + Applicability::MaybeIncorrect, + ); + err.emit(); + Ok(TyKind::Array(elt_ty, length)) + } + fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { let and_span = self.prev_token.span; let mut opt_lifetime = self.check_lifetime().then(|| self.expect_lifetime()); diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index cac4dba2b49d..8b57db23d01c 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2338,7 +2338,6 @@ ui/issues/issue-50415.rs ui/issues/issue-50442.rs ui/issues/issue-50471.rs ui/issues/issue-50518.rs -ui/issues/issue-50571.rs ui/issues/issue-50581.rs ui/issues/issue-50582.rs ui/issues/issue-50585.rs diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 53226fcb80e6..74f8104c7e98 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use ignore::Walk; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1619; +const ISSUES_ENTRY_LIMIT: u32 = 1616; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/issues/issue-50571.fixed b/tests/ui/issues/issue-50571.fixed deleted file mode 100644 index 6d73f17cca4c..000000000000 --- a/tests/ui/issues/issue-50571.fixed +++ /dev/null @@ -1,10 +0,0 @@ -//@ edition: 2015 -//@ run-rustfix - -#![allow(dead_code)] -trait Foo { - fn foo(_: [i32; 2]) {} - //~^ ERROR: patterns aren't allowed in methods without bodies -} - -fn main() {} diff --git a/tests/ui/issues/issue-50571.rs b/tests/ui/issues/issue-50571.rs deleted file mode 100644 index dd840ffe4d17..000000000000 --- a/tests/ui/issues/issue-50571.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ edition: 2015 -//@ run-rustfix - -#![allow(dead_code)] -trait Foo { - fn foo([a, b]: [i32; 2]) {} - //~^ ERROR: patterns aren't allowed in methods without bodies -} - -fn main() {} diff --git a/tests/ui/issues/issue-50571.stderr b/tests/ui/issues/issue-50571.stderr deleted file mode 100644 index 9b00fe0f5db6..000000000000 --- a/tests/ui/issues/issue-50571.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0642]: patterns aren't allowed in methods without bodies - --> $DIR/issue-50571.rs:6:12 - | -LL | fn foo([a, b]: [i32; 2]) {} - | ^^^^^^ - | -help: give this argument a name or use an underscore to ignore it - | -LL - fn foo([a, b]: [i32; 2]) {} -LL + fn foo(_: [i32; 2]) {} - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0642`. diff --git a/tests/ui/parser/better-expected.rs b/tests/ui/parser/better-expected.rs index 16b61caa4dff..91128c39691d 100644 --- a/tests/ui/parser/better-expected.rs +++ b/tests/ui/parser/better-expected.rs @@ -1,3 +1,3 @@ fn main() { - let x: [isize 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3` + let x: [isize 3]; //~ ERROR expected `;` or `]`, found `3` } diff --git a/tests/ui/parser/better-expected.stderr b/tests/ui/parser/better-expected.stderr index f4ec933be164..4646ce7eff0e 100644 --- a/tests/ui/parser/better-expected.stderr +++ b/tests/ui/parser/better-expected.stderr @@ -1,10 +1,14 @@ -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3` +error: expected `;` or `]`, found `3` --> $DIR/better-expected.rs:2:19 | LL | let x: [isize 3]; - | - ^ expected one of 7 possible tokens - | | - | while parsing the type for `x` + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL | let x: [isize ;3]; + | + error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/error-pattern-issue-50571.rs b/tests/ui/parser/issues/error-pattern-issue-50571.rs new file mode 100644 index 000000000000..0c2ce6052cb8 --- /dev/null +++ b/tests/ui/parser/issues/error-pattern-issue-50571.rs @@ -0,0 +1,11 @@ +// There is a regression introduced for issue #143828 +//@ edition: 2015 + +#![allow(dead_code)] +trait Foo { + fn foo([a, b]: [i32; 2]) {} + //~^ ERROR: expected `;` or `]`, found `,` + //~| ERROR: patterns aren't allowed in methods without bodies +} + +fn main() {} diff --git a/tests/ui/parser/issues/error-pattern-issue-50571.stderr b/tests/ui/parser/issues/error-pattern-issue-50571.stderr new file mode 100644 index 000000000000..47457cff461c --- /dev/null +++ b/tests/ui/parser/issues/error-pattern-issue-50571.stderr @@ -0,0 +1,28 @@ +error: expected `;` or `]`, found `,` + --> $DIR/error-pattern-issue-50571.rs:6:14 + | +LL | fn foo([a, b]: [i32; 2]) {} + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL - fn foo([a, b]: [i32; 2]) {} +LL + fn foo([a; b]: [i32; 2]) {} + | + +error[E0642]: patterns aren't allowed in methods without bodies + --> $DIR/error-pattern-issue-50571.rs:6:12 + | +LL | fn foo([a, b]: [i32; 2]) {} + | ^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - fn foo([a, b]: [i32; 2]) {} +LL + fn foo(_: [i32; 2]) {} + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0642`. diff --git a/tests/ui/parser/recover/array-type-no-semi.rs b/tests/ui/parser/recover/array-type-no-semi.rs index ae5efbaf36ca..2cc5d979604c 100644 --- a/tests/ui/parser/recover/array-type-no-semi.rs +++ b/tests/ui/parser/recover/array-type-no-semi.rs @@ -5,14 +5,13 @@ fn main() { let x = 5; let b: [i32, 5]; - //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` - //~| ERROR expected value, found builtin type `i32` [E0423] + //~^ ERROR expected `;` or `]`, found `,` let a: [i32, ]; - //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + //~^ ERROR expected `;` or `]`, found `,` //~| ERROR expected value, found builtin type `i32` [E0423] let c: [i32, x]; - //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` - //~| ERROR expected value, found builtin type `i32` [E0423] + //~^ ERROR expected `;` or `]`, found `,` + //~| ERROR attempt to use a non-constant value in a constant [E0435] let e: [i32 5]; - //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `5` + //~^ ERROR expected `;` or `]`, found `5` } diff --git a/tests/ui/parser/recover/array-type-no-semi.stderr b/tests/ui/parser/recover/array-type-no-semi.stderr index 84b7282b4fed..82330465144c 100644 --- a/tests/ui/parser/recover/array-type-no-semi.stderr +++ b/tests/ui/parser/recover/array-type-no-semi.stderr @@ -1,56 +1,71 @@ -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` +error: expected `;` or `]`, found `,` --> $DIR/array-type-no-semi.rs:7:16 | LL | let b: [i32, 5]; - | - ^ expected one of 7 possible tokens - | | - | while parsing the type for `b` - | help: use `=` if you meant to assign + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL - let b: [i32, 5]; +LL + let b: [i32; 5]; + | -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` - --> $DIR/array-type-no-semi.rs:10:16 +error: expected `;` or `]`, found `,` + --> $DIR/array-type-no-semi.rs:9:16 | LL | let a: [i32, ]; - | - ^ expected one of 7 possible tokens + | - ^ expected `;` or `]` | | | while parsing the type for `a` | help: use `=` if you meant to assign + | + = note: you might have meant to write a slice or array type -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` - --> $DIR/array-type-no-semi.rs:13:16 +error: expected `;` or `]`, found `,` + --> $DIR/array-type-no-semi.rs:12:16 | LL | let c: [i32, x]; - | - ^ expected one of 7 possible tokens - | | - | while parsing the type for `c` - | help: use `=` if you meant to assign + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL - let c: [i32, x]; +LL + let c: [i32; x]; + | -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `5` - --> $DIR/array-type-no-semi.rs:16:17 +error: expected `;` or `]`, found `5` + --> $DIR/array-type-no-semi.rs:15:17 | LL | let e: [i32 5]; - | - ^ expected one of 7 possible tokens - | | - | while parsing the type for `e` - -error[E0423]: expected value, found builtin type `i32` - --> $DIR/array-type-no-semi.rs:7:13 + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL | let e: [i32 ;5]; + | + + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/array-type-no-semi.rs:12:18 + | +LL | let c: [i32, x]; + | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL - let x = 5; +LL + const x: /* Type */ = 5; | -LL | let b: [i32, 5]; - | ^^^ not a value error[E0423]: expected value, found builtin type `i32` - --> $DIR/array-type-no-semi.rs:10:13 + --> $DIR/array-type-no-semi.rs:9:13 | LL | let a: [i32, ]; | ^^^ not a value -error[E0423]: expected value, found builtin type `i32` - --> $DIR/array-type-no-semi.rs:13:13 - | -LL | let c: [i32, x]; - | ^^^ not a value +error: aborting due to 6 previous errors -error: aborting due to 7 previous errors - -For more information about this error, try `rustc --explain E0423`. +Some errors have detailed explanations: E0423, E0435. +For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs index 560efecb91cf..fb9a1c643fcc 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs +++ b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs @@ -1 +1,6 @@ -type v = [isize * 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*` +type v = [isize * 3]; +//~^ ERROR expected `;` or `]`, found `*` +//~| WARN type `v` should have an upper camel case name [non_camel_case_types] + + +fn main() {} diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr index 5bc9c2ccf00a..8d7938a1a469 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr @@ -1,8 +1,23 @@ -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*` +error: expected `;` or `]`, found `*` --> $DIR/removed-syntax-fixed-vec.rs:1:17 | LL | type v = [isize * 3]; - | ^ expected one of 7 possible tokens + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL - type v = [isize * 3]; +LL + type v = [isize ; 3]; + | -error: aborting due to 1 previous error +warning: type `v` should have an upper camel case name + --> $DIR/removed-syntax-fixed-vec.rs:1:6 + | +LL | type v = [isize * 3]; + | ^ help: convert the identifier to upper camel case (notice the capitalization): `V` + | + = note: `#[warn(non_camel_case_types)]` on by default + +error: aborting due to 1 previous error; 1 warning emitted From 80224c3e888bf14ddca14700e79363b25eda93ce Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Fri, 13 Jun 2025 05:09:09 +0000 Subject: [PATCH 164/363] test: Add UI tests for testing type analysis autodiff Signed-off-by: Karan Janthe --- src/tools/enzyme | 2 +- .../type-trees/type-analysis/README.md | 13 +++++ .../type-analysis/array/array.check | 26 +++++++++ .../type-trees/type-analysis/array/array.rs | 20 +++++++ .../type-trees/type-analysis/array/rmake.rs | 28 ++++++++++ .../type-analysis/array3d/array3d.check | 54 +++++++++++++++++++ .../type-analysis/array3d/array3d.rs | 32 +++++++++++ .../type-trees/type-analysis/array3d/rmake.rs | 28 ++++++++++ .../type-trees/type-analysis/box/box.check | 12 +++++ .../type-trees/type-analysis/box/box.rs | 18 +++++++ .../type-trees/type-analysis/box/rmake.rs | 28 ++++++++++ .../const_pointer/const_pointer.check | 10 ++++ .../const_pointer/const_pointer.rs | 18 +++++++ .../type-analysis/const_pointer/rmake.rs | 31 +++++++++++ .../type-trees/type-analysis/f32/f32.check | 12 +++++ .../type-trees/type-analysis/f32/f32.rs | 19 +++++++ .../type-trees/type-analysis/f32/rmake.rs | 28 ++++++++++ .../type-trees/type-analysis/f64/f64.check | 10 ++++ .../type-trees/type-analysis/f64/f64.rs | 20 +++++++ .../type-trees/type-analysis/f64/rmake.rs | 28 ++++++++++ .../type-trees/type-analysis/i128/i128.check | 10 ++++ .../type-trees/type-analysis/i128/i128.rs | 14 +++++ .../type-trees/type-analysis/i128/rmake.rs | 28 ++++++++++ .../type-trees/type-analysis/i16/i16.check | 10 ++++ .../type-trees/type-analysis/i16/i16.rs | 14 +++++ .../type-trees/type-analysis/i16/rmake.rs | 28 ++++++++++ .../type-trees/type-analysis/i32/i32.check | 10 ++++ .../type-trees/type-analysis/i32/i32.rs | 14 +++++ .../type-trees/type-analysis/i32/rmake.rs | 28 ++++++++++ .../type-trees/type-analysis/i8/i8.check | 10 ++++ .../type-trees/type-analysis/i8/i8.rs | 14 +++++ .../type-trees/type-analysis/i8/rmake.rs | 28 ++++++++++ .../type-analysis/isize/isize.check | 10 ++++ .../type-trees/type-analysis/isize/isize.rs | 14 +++++ .../type-trees/type-analysis/isize/rmake.rs | 28 ++++++++++ .../mut_pointer/mut_pointer.check | 10 ++++ .../type-analysis/mut_pointer/mut_pointer.rs | 18 +++++++ .../type-analysis/mut_pointer/rmake.rs | 28 ++++++++++ .../type-analysis/mut_ref/mut_ref.check | 10 ++++ .../type-analysis/mut_ref/mut_ref.rs | 18 +++++++ .../type-trees/type-analysis/mut_ref/rmake.rs | 28 ++++++++++ .../type-trees/type-analysis/ref/ref.check | 10 ++++ .../type-trees/type-analysis/ref/ref.rs | 18 +++++++ .../type-trees/type-analysis/ref/rmake.rs | 28 ++++++++++ .../type-trees/type-analysis/struct/rmake.rs | 28 ++++++++++ .../type-analysis/struct/struct.check | 10 ++++ .../type-trees/type-analysis/struct/struct.rs | 23 ++++++++ .../type-trees/type-analysis/u128/rmake.rs | 28 ++++++++++ .../type-trees/type-analysis/u128/u128.check | 10 ++++ .../type-trees/type-analysis/u128/u128.rs | 14 +++++ .../type-trees/type-analysis/u16/rmake.rs | 28 ++++++++++ .../type-trees/type-analysis/u16/u16.check | 10 ++++ .../type-trees/type-analysis/u16/u16.rs | 14 +++++ .../type-trees/type-analysis/u32/rmake.rs | 28 ++++++++++ .../type-trees/type-analysis/u32/u32.check | 10 ++++ .../type-trees/type-analysis/u32/u32.rs | 14 +++++ .../type-trees/type-analysis/u8/rmake.rs | 28 ++++++++++ .../type-trees/type-analysis/u8/u8.check | 10 ++++ .../type-trees/type-analysis/u8/u8.rs | 14 +++++ .../type-trees/type-analysis/union/rmake.rs | 28 ++++++++++ .../type-analysis/union/union.check | 10 ++++ .../type-trees/type-analysis/union/union.rs | 20 +++++++ .../type-trees/type-analysis/usize/rmake.rs | 28 ++++++++++ .../type-analysis/usize/usize.check | 10 ++++ .../type-trees/type-analysis/usize/usize.rs | 14 +++++ .../type-trees/type-analysis/vec/rmake.rs | 28 ++++++++++ .../type-trees/type-analysis/vec/vec.check | 18 +++++++ .../type-trees/type-analysis/vec/vec.rs | 14 +++++ 68 files changed, 1303 insertions(+), 1 deletion(-) create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/README.md create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/array/array.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/array/array.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/array/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/array3d/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/box/box.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/box/box.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/box/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/const_pointer/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/f32/f32.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/f32/f32.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/f32/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/f64/f64.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/f64/f64.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/f64/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/i128/i128.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/i128/i128.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/i128/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/i16/i16.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/i16/i16.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/i16/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/i32/i32.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/i32/i32.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/i32/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/i8/i8.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/i8/i8.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/i8/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/isize/isize.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/isize/isize.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/isize/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/mut_ref/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/ref/ref.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/ref/ref.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/ref/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/struct/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/struct/struct.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/struct/struct.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/u128/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/u128/u128.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/u128/u128.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/u16/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/u16/u16.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/u16/u16.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/u32/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/u32/u32.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/u32/u32.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/u8/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/u8/u8.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/u8/u8.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/union/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/union/union.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/union/union.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/usize/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/usize/usize.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/usize/usize.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/vec/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check create mode 100644 tests/run-make/autodiff/type-trees/type-analysis/vec/vec.rs diff --git a/src/tools/enzyme b/src/tools/enzyme index 0f65f31837a6..b5098d515d5e 160000 --- a/src/tools/enzyme +++ b/src/tools/enzyme @@ -1 +1 @@ -Subproject commit 0f65f31837a608db469ebde94adbc921be70bd8a +Subproject commit b5098d515d5e1bd0f5470553bc0d18da9794ca8b diff --git a/tests/run-make/autodiff/type-trees/type-analysis/README.md b/tests/run-make/autodiff/type-trees/type-analysis/README.md new file mode 100644 index 000000000000..c712edfaf504 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/README.md @@ -0,0 +1,13 @@ +# Autodiff Type-Trees Type Analysis Tests + +This directory contains run-make tests for the autodiff type-trees type analysis functionality. These tests verify that the autodiff compiler correctly analyzes and tracks type information for different Rust types during automatic differentiation. + +## What These Tests Do + +Each test compiles a simple Rust function with the `#[autodiff_reverse]` attribute and verifies that the compiler: + +1. **Correctly identifies type information** in the generated LLVM IR +2. **Tracks type annotations** for variables and operations +3. **Preserves type context** through the autodiff transformation process + +The tests capture the stdout from the autodiff compiler (which contains type analysis information) and verify it matches expected patterns using FileCheck. diff --git a/tests/run-make/autodiff/type-trees/type-analysis/array/array.check b/tests/run-make/autodiff/type-trees/type-analysis/array/array.check new file mode 100644 index 000000000000..6e4197692a7b --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/array/array.check @@ -0,0 +1,26 @@ +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float, [-1,4]:Float@float, [-1,8]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 4, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float, [-1,4]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 8, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float, [-1,4]:Float@float, [-1,8]:Float@float}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float, [-1,4]:Float@float, [-1,8]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 4, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float, [-1,4]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 8, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/array/array.rs b/tests/run-make/autodiff/type-trees/type-analysis/array/array.rs new file mode 100644 index 000000000000..9a859418b106 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/array/array.rs @@ -0,0 +1,20 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &[f32; 3]) -> f32 { + x[0] * x[0] + x[1] * x[1] + x[2] * x[2] +} + +fn main() { + let x = [1.0f32, 2.0, 3.0]; + let mut df_dx = [0.0f32; 3]; + let out = callee(&x); + let out_ = d_square(&x, &mut df_dx, 1.0); + assert_eq!(out, out_); + assert_eq!(2.0, df_dx[0]); + assert_eq!(4.0, df_dx[1]); + assert_eq!(6.0, df_dx[2]); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/array/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/array/rmake.rs new file mode 100644 index 000000000000..d68ab46bb946 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/array/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("array.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("array.stdout", stdout); + rfs::write("array.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("array.check").stdin_buf(rfs::read("array.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.check b/tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.check new file mode 100644 index 000000000000..ed81ad4869ac --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.check @@ -0,0 +1,54 @@ +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: br label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi float [ 0.000000e+00, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ]: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = phi i1 [ true, %{{[0-9]+}} ], [ false, %{{[0-9]+}} ]: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = phi i64 [ 0, %{{[0-9]+}} ], [ 1, %{{[0-9]+}} ]: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw [2 x [2 x float]], ptr %{{[0-9]+}}, i64 %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: br label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ]: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = phi i1 [ true, %{{[0-9]+}} ], [ false, %{{[0-9]+}} ]: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = phi i64 [ 0, %{{[0-9]+}} ], [ 1, %{{[0-9]+}} ]: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw [2 x float], ptr %{{[0-9]+}}, i64 %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: br label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ]: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = phi i1 [ true, %{{[0-9]+}} ], [ false, %{{[0-9]+}} ]: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = phi i64 [ 0, %{{[0-9]+}} ], [ 1, %{{[0-9]+}} ]: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw float, ptr %{{[0-9]+}}, i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: br label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi float [ 0.000000e+00, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ]: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = phi i1 [ true, %{{[0-9]+}} ], [ false, %{{[0-9]+}} ]: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = phi i64 [ 0, %{{[0-9]+}} ], [ 1, %{{[0-9]+}} ]: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw [2 x [2 x float]], ptr %{{[0-9]+}}, i64 %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: br label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ]: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = phi i1 [ true, %{{[0-9]+}} ], [ false, %{{[0-9]+}} ]: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = phi i64 [ 0, %{{[0-9]+}} ], [ 1, %{{[0-9]+}} ]: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw [2 x float], ptr %{{[0-9]+}}, i64 %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: br label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ]: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = phi i1 [ true, %{{[0-9]+}} ], [ false, %{{[0-9]+}} ]: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = phi i64 [ 0, %{{[0-9]+}} ], [ 1, %{{[0-9]+}} ]: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw float, ptr %{{[0-9]+}}, i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.rs b/tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.rs new file mode 100644 index 000000000000..a95111a0daee --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.rs @@ -0,0 +1,32 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &[[[f32; 2]; 2]; 2]) -> f32 { + let mut sum = 0.0; + for i in 0..2 { + for j in 0..2 { + for k in 0..2 { + sum += x[i][j][k] * x[i][j][k]; + } + } + } + sum +} + +fn main() { + let x = [[[1.0f32, 2.0], [3.0, 4.0]], [[5.0, 6.0], [7.0, 8.0]]]; + let mut df_dx = [[[0.0f32; 2]; 2]; 2]; + let out = callee(&x); + let out_ = d_square(&x, &mut df_dx, 1.0); + assert_eq!(out, out_); + for i in 0..2 { + for j in 0..2 { + for k in 0..2 { + assert_eq!(df_dx[i][j][k], 2.0 * x[i][j][k]); + } + } + } +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/array3d/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/array3d/rmake.rs new file mode 100644 index 000000000000..8e75c21c9d65 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/array3d/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("array3d.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("array3d.stdout", stdout); + rfs::write("array3d.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("array3d.check").stdin_buf(rfs::read("array3d.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/box/box.check b/tests/run-make/autodiff/type-trees/type-analysis/box/box.check new file mode 100644 index 000000000000..1911e18a1375 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/box/box.check @@ -0,0 +1,12 @@ +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Pointer, [-1,0,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load ptr, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !nonnull !{{[0-9]+}}, !align !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Pointer, [-1,0,0]:Float@float}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Pointer, [-1,0,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load ptr, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !nonnull !{{[0-9]+}}, !align !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/box/box.rs b/tests/run-make/autodiff/type-trees/type-analysis/box/box.rs new file mode 100644 index 000000000000..658ccffc74eb --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/box/box.rs @@ -0,0 +1,18 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &Box) -> f32 { + **x * **x +} + +fn main() { + let x = Box::new(7.0f32); + let mut df_dx = Box::new(0.0f32); + let out = callee(&x); + let out_ = d_square(&x, &mut df_dx, 1.0); + assert_eq!(out, out_); + assert_eq!(14.0, *df_dx); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/box/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/box/rmake.rs new file mode 100644 index 000000000000..1e8c8f9ccbd1 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/box/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("box.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("box.stdout", stdout); + rfs::write("box.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("box.check").stdin_buf(rfs::read("box.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.check b/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.check new file mode 100644 index 000000000000..e7503453f8e6 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.rs b/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.rs new file mode 100644 index 000000000000..8c877bfec05d --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.rs @@ -0,0 +1,18 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: *const f32) -> f32 { + unsafe { *x * *x } +} + +fn main() { + let x: f32 = 7.0; + let out = callee(&x as *const f32); + let mut df_dx: f32 = 0.0; + let out_ = d_square(&x as *const f32, &mut df_dx, 1.0); + assert_eq!(out, out_); + assert_eq!(14.0, df_dx); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/rmake.rs new file mode 100644 index 000000000000..ce38c6bd2aed --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/rmake.rs @@ -0,0 +1,31 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("const_pointer.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("const_pointer.stdout", stdout); + rfs::write("const_pointer.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck() + .patterns("const_pointer.check") + .stdin_buf(rfs::read("const_pointer.stdout")) + .run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/f32/f32.check b/tests/run-make/autodiff/type-trees/type-analysis/f32/f32.check new file mode 100644 index 000000000000..0cc0ffda43d0 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/f32/f32.check @@ -0,0 +1,12 @@ +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} + +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} + +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/f32/f32.rs b/tests/run-make/autodiff/type-trees/type-analysis/f32/f32.rs new file mode 100644 index 000000000000..b945821934a9 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/f32/f32.rs @@ -0,0 +1,19 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &f32) -> f32 { + *x * *x +} + +fn main() { + let x: f32 = 7.0; + let mut df_dx: f32 = 0.0; + let out = callee(&x); + let out_ = d_square(&x, &mut df_dx, 1.0); + + assert_eq!(out, out_); + assert_eq!(14.0, df_dx); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/f32/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/f32/rmake.rs new file mode 100644 index 000000000000..d7e49219da68 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/f32/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("f32.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("f32.stdout", stdout); + rfs::write("f32.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("f32.check").stdin_buf(rfs::read("f32.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/f64/f64.check b/tests/run-make/autodiff/type-trees/type-analysis/f64/f64.check new file mode 100644 index 000000000000..efc49da5ffcc --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/f64/f64.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Float@double} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@double} +// CHECK-DAG: %{{[0-9]+}} = load double, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@double} +// CHECK-DAG: %{{[0-9]+}} = fmul double %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@double} +// CHECK-DAG: ret double %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Float@double} |{[-1]:Pointer, [-1,0]:Float@double}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@double} +// CHECK-DAG: %{{[0-9]+}} = load double, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@double} +// CHECK-DAG: %{{[0-9]+}} = fmul double %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@double} +// CHECK-DAG: ret double %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/f64/f64.rs b/tests/run-make/autodiff/type-trees/type-analysis/f64/f64.rs new file mode 100644 index 000000000000..9b47569652e3 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/f64/f64.rs @@ -0,0 +1,20 @@ +#![feature(autodiff)] +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_callee, Duplicated, Active)] +#[no_mangle] +fn callee(x: &f64) -> f64 { + x * x +} + +fn main() { + let x = std::hint::black_box(3.0); + + let output = callee(&x); + assert_eq!(9.0, output); + + let mut df_dx = 0.0; + let output_ = d_callee(&x, &mut df_dx, 1.0); + assert_eq!(output, output_); + assert_eq!(6.0, df_dx); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/f64/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/f64/rmake.rs new file mode 100644 index 000000000000..8bf92b8c1bd1 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/f64/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("f64.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("f64.stdout", stdout); + rfs::write("f64.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("f64.check").stdin_buf(rfs::read("f64.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i128/i128.check b/tests/run-make/autodiff/type-trees/type-analysis/i128/i128.check new file mode 100644 index 000000000000..31a07219e743 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/i128/i128.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer, [-1,12]:Integer, [-1,13]:Integer, [-1,14]:Integer, [-1,15]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i128, ptr %{{[0-9]+}}, align 16, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i128 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i128 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer, [-1,12]:Integer, [-1,13]:Integer, [-1,14]:Integer, [-1,15]:Integer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer, [-1,12]:Integer, [-1,13]:Integer, [-1,14]:Integer, [-1,15]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i128, ptr %{{[0-9]+}}, align 16, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i128 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i128 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i128/i128.rs b/tests/run-make/autodiff/type-trees/type-analysis/i128/i128.rs new file mode 100644 index 000000000000..19dfbbb22db0 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/i128/i128.rs @@ -0,0 +1,14 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &i128) -> i128 { + *x * *x +} + +fn main() { + let x: i128 = 7; + let _ = callee(&x); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i128/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/i128/rmake.rs new file mode 100644 index 000000000000..21e8698634f0 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/i128/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("i128.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("i128.stdout", stdout); + rfs::write("i128.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("i128.check").stdin_buf(rfs::read("i128.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i16/i16.check b/tests/run-make/autodiff/type-trees/type-analysis/i16/i16.check new file mode 100644 index 000000000000..8cc299532c50 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/i16/i16.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i16, ptr %{{[0-9]+}}, align 2, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i16 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i16 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i16, ptr %{{[0-9]+}}, align 2, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i16 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i16 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i16/i16.rs b/tests/run-make/autodiff/type-trees/type-analysis/i16/i16.rs new file mode 100644 index 000000000000..82099198a2ee --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/i16/i16.rs @@ -0,0 +1,14 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &i16) -> i16 { + *x * *x +} + +fn main() { + let x: i16 = 7; + let _ = callee(&x); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i16/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/i16/rmake.rs new file mode 100644 index 000000000000..a2875a8c573f --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/i16/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("i16.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("i16.stdout", stdout); + rfs::write("i16.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("i16.check").stdin_buf(rfs::read("i16.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i32/i32.check b/tests/run-make/autodiff/type-trees/type-analysis/i32/i32.check new file mode 100644 index 000000000000..4df982887d74 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/i32/i32.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i32, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i32 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i32 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i32, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i32 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i32 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i32/i32.rs b/tests/run-make/autodiff/type-trees/type-analysis/i32/i32.rs new file mode 100644 index 000000000000..e95068d5c49c --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/i32/i32.rs @@ -0,0 +1,14 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &i32) -> i32 { + *x * *x +} + +fn main() { + let x: i32 = 7; + let _ = callee(&x); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i32/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/i32/rmake.rs new file mode 100644 index 000000000000..857017feeab0 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/i32/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("i32.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("i32.stdout", stdout); + rfs::write("i32.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("i32.check").stdin_buf(rfs::read("i32.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i8/i8.check b/tests/run-make/autodiff/type-trees/type-analysis/i8/i8.check new file mode 100644 index 000000000000..651a2085bc6f --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/i8/i8.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i8, ptr %{{[0-9]+}}, align 1, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i8 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i8 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i8, ptr %{{[0-9]+}}, align 1, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i8 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i8 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i8/i8.rs b/tests/run-make/autodiff/type-trees/type-analysis/i8/i8.rs new file mode 100644 index 000000000000..afc0cad703c6 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/i8/i8.rs @@ -0,0 +1,14 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &i8) -> i8 { + *x * *x +} + +fn main() { + let x: i8 = 7; + let _ = callee(&x); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i8/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/i8/rmake.rs new file mode 100644 index 000000000000..6551e2d6c4ef --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/i8/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("i8.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("i8.stdout", stdout); + rfs::write("i8.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("i8.check").stdin_buf(rfs::read("i8.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/isize/isize.check b/tests/run-make/autodiff/type-trees/type-analysis/isize/isize.check new file mode 100644 index 000000000000..40ee6edc02c0 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/isize/isize.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i64, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i64, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/isize/isize.rs b/tests/run-make/autodiff/type-trees/type-analysis/isize/isize.rs new file mode 100644 index 000000000000..dd160984a4ed --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/isize/isize.rs @@ -0,0 +1,14 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &isize) -> isize { + *x * *x +} + +fn main() { + let x: isize = 7; + let _ = callee(&x); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/isize/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/isize/rmake.rs new file mode 100644 index 000000000000..09277f63ed4b --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/isize/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("isize.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("isize.stdout", stdout); + rfs::write("isize.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("isize.check").stdin_buf(rfs::read("isize.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.check b/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.check new file mode 100644 index 000000000000..e7503453f8e6 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.rs b/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.rs new file mode 100644 index 000000000000..2b672f6d3f8f --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.rs @@ -0,0 +1,18 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: *mut f32) -> f32 { + unsafe { *x * *x } +} + +fn main() { + let mut x: f32 = 7.0; + let out = callee(&mut x as *mut f32); + let mut df_dx: f32 = 0.0; + let out_ = d_square(&mut x as *mut f32, &mut df_dx, 1.0); + assert_eq!(out, out_); + assert_eq!(14.0, df_dx); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/rmake.rs new file mode 100644 index 000000000000..4d5a5042141e --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("mut_pointer.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("mut_pointer.stdout", stdout); + rfs::write("mut_pointer.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("mut_pointer.check").stdin_buf(rfs::read("mut_pointer.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.check b/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.check new file mode 100644 index 000000000000..e7503453f8e6 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.rs b/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.rs new file mode 100644 index 000000000000..7019e3f71edf --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.rs @@ -0,0 +1,18 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &mut f32) -> f32 { + *x * *x +} + +fn main() { + let mut x: f32 = 7.0; + let mut df_dx: f32 = 0.0; + let out = callee(&mut x); + let out_ = d_square(&mut x, &mut df_dx, 1.0); + assert_eq!(out, out_); + assert_eq!(14.0, df_dx); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/rmake.rs new file mode 100644 index 000000000000..13668c54e781 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("mut_ref.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("mut_ref.stdout", stdout); + rfs::write("mut_ref.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("mut_ref.check").stdin_buf(rfs::read("mut_ref.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/ref/ref.check b/tests/run-make/autodiff/type-trees/type-analysis/ref/ref.check new file mode 100644 index 000000000000..e7503453f8e6 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/ref/ref.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/ref/ref.rs b/tests/run-make/autodiff/type-trees/type-analysis/ref/ref.rs new file mode 100644 index 000000000000..3ced164b86f0 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/ref/ref.rs @@ -0,0 +1,18 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &f32) -> f32 { + *x * *x +} + +fn main() { + let x: f32 = 7.0; + let mut df_dx: f32 = 0.0; + let out = callee(&x); + let out_ = d_square(&x, &mut df_dx, 1.0); + assert_eq!(out, out_); + assert_eq!(14.0, df_dx); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/ref/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/ref/rmake.rs new file mode 100644 index 000000000000..b68e4e5b8ac1 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/ref/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("ref.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("ref.stdout", stdout); + rfs::write("ref.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("ref.check").stdin_buf(rfs::read("ref.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/struct/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/struct/rmake.rs new file mode 100644 index 000000000000..4073f7554cca --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/struct/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("struct.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("struct.stdout", stdout); + rfs::write("struct.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("struct.check").stdin_buf(rfs::read("struct.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/struct/struct.check b/tests/run-make/autodiff/type-trees/type-analysis/struct/struct.check new file mode 100644 index 000000000000..e7503453f8e6 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/struct/struct.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/struct/struct.rs b/tests/run-make/autodiff/type-trees/type-analysis/struct/struct.rs new file mode 100644 index 000000000000..52cb6a9a6b93 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/struct/struct.rs @@ -0,0 +1,23 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[derive(Copy, Clone)] +struct MyStruct { + f: f32, +} + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &MyStruct) -> f32 { + x.f * x.f +} + +fn main() { + let x = MyStruct { f: 7.0 }; + let mut df_dx = MyStruct { f: 0.0 }; + let out = callee(&x); + let out_ = d_square(&x, &mut df_dx, 1.0); + assert_eq!(out, out_); + assert_eq!(14.0, df_dx.f); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u128/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/u128/rmake.rs new file mode 100644 index 000000000000..3f605d47c683 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/u128/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("u128.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("u128.stdout", stdout); + rfs::write("u128.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("u128.check").stdin_buf(rfs::read("u128.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u128/u128.check b/tests/run-make/autodiff/type-trees/type-analysis/u128/u128.check new file mode 100644 index 000000000000..31a07219e743 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/u128/u128.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer, [-1,12]:Integer, [-1,13]:Integer, [-1,14]:Integer, [-1,15]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i128, ptr %{{[0-9]+}}, align 16, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i128 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i128 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer, [-1,12]:Integer, [-1,13]:Integer, [-1,14]:Integer, [-1,15]:Integer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer, [-1,12]:Integer, [-1,13]:Integer, [-1,14]:Integer, [-1,15]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i128, ptr %{{[0-9]+}}, align 16, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i128 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i128 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u128/u128.rs b/tests/run-make/autodiff/type-trees/type-analysis/u128/u128.rs new file mode 100644 index 000000000000..d19d2faa51bb --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/u128/u128.rs @@ -0,0 +1,14 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &u128) -> u128 { + *x * *x +} + +fn main() { + let x: u128 = 7; + let _ = callee(&x); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u16/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/u16/rmake.rs new file mode 100644 index 000000000000..0051f6f9795b --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/u16/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("u16.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("u16.stdout", stdout); + rfs::write("u16.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("u16.check").stdin_buf(rfs::read("u16.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u16/u16.check b/tests/run-make/autodiff/type-trees/type-analysis/u16/u16.check new file mode 100644 index 000000000000..8cc299532c50 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/u16/u16.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i16, ptr %{{[0-9]+}}, align 2, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i16 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i16 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i16, ptr %{{[0-9]+}}, align 2, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i16 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i16 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u16/u16.rs b/tests/run-make/autodiff/type-trees/type-analysis/u16/u16.rs new file mode 100644 index 000000000000..f5f5b50622b5 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/u16/u16.rs @@ -0,0 +1,14 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &u16) -> u16 { + *x * *x +} + +fn main() { + let x: u16 = 7; + let _ = callee(&x); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u32/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/u32/rmake.rs new file mode 100644 index 000000000000..0882230b1c6d --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/u32/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("u32.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("u32.stdout", stdout); + rfs::write("u32.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("u32.check").stdin_buf(rfs::read("u32.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u32/u32.check b/tests/run-make/autodiff/type-trees/type-analysis/u32/u32.check new file mode 100644 index 000000000000..4df982887d74 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/u32/u32.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i32, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i32 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i32 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i32, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i32 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i32 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u32/u32.rs b/tests/run-make/autodiff/type-trees/type-analysis/u32/u32.rs new file mode 100644 index 000000000000..66b4c222c51d --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/u32/u32.rs @@ -0,0 +1,14 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &u32) -> u32 { + *x * *x +} + +fn main() { + let x: u32 = 7; + let _ = callee(&x); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u8/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/u8/rmake.rs new file mode 100644 index 000000000000..100b4f498f27 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/u8/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("u8.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("u8.stdout", stdout); + rfs::write("u8.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("u8.check").stdin_buf(rfs::read("u8.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u8/u8.check b/tests/run-make/autodiff/type-trees/type-analysis/u8/u8.check new file mode 100644 index 000000000000..651a2085bc6f --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/u8/u8.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i8, ptr %{{[0-9]+}}, align 1, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i8 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i8 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i8, ptr %{{[0-9]+}}, align 1, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i8 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i8 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u8/u8.rs b/tests/run-make/autodiff/type-trees/type-analysis/u8/u8.rs new file mode 100644 index 000000000000..de9cdeb631e9 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/u8/u8.rs @@ -0,0 +1,14 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &u8) -> u8 { + *x * *x +} + +fn main() { + let x: u8 = 7; + let _ = callee(&x); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/union/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/union/rmake.rs new file mode 100644 index 000000000000..67f0fe184818 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/union/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("union.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("union.stdout", stdout); + rfs::write("union.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("union.check").stdin_buf(rfs::read("union.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/union/union.check b/tests/run-make/autodiff/type-trees/type-analysis/union/union.check new file mode 100644 index 000000000000..e7503453f8e6 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/union/union.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/union/union.rs b/tests/run-make/autodiff/type-trees/type-analysis/union/union.rs new file mode 100644 index 000000000000..8d997f8c839d --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/union/union.rs @@ -0,0 +1,20 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[allow(dead_code)] +union MyUnion { + f: f32, + i: i32, +} + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &MyUnion) -> f32 { + unsafe { x.f * x.f } +} + +fn main() { + let x = MyUnion { f: 7.0 }; + let _ = callee(&x); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/usize/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/usize/rmake.rs new file mode 100644 index 000000000000..d5cfd708c3a3 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/usize/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("usize.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("usize.stdout", stdout); + rfs::write("usize.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("usize.check").stdin_buf(rfs::read("usize.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/usize/usize.check b/tests/run-make/autodiff/type-trees/type-analysis/usize/usize.check new file mode 100644 index 000000000000..40ee6edc02c0 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/usize/usize.check @@ -0,0 +1,10 @@ +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i64, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer} +// CHECK-DAG: %{{[0-9]+}} = load i64, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: ret i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/usize/usize.rs b/tests/run-make/autodiff/type-trees/type-analysis/usize/usize.rs new file mode 100644 index 000000000000..8e758be57d42 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/usize/usize.rs @@ -0,0 +1,14 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(x: &usize) -> usize { + *x * *x +} + +fn main() { + let x: usize = 7; + let _ = callee(&x); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/vec/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/vec/rmake.rs new file mode 100644 index 000000000000..94491fab8d62 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/vec/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile the Rust file with the required flags, capturing both stdout and stderr + let output = rustc() + .input("vec.rs") + .arg("-Zautodiff=Enable,PrintTAFn=callee") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + + // Write the outputs to files + rfs::write("vec.stdout", stdout); + rfs::write("vec.stderr", stderr); + + // Run FileCheck on the stdout using the check file + llvm_filecheck().patterns("vec.check").stdin_buf(rfs::read("vec.stdout")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check b/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check new file mode 100644 index 000000000000..dcf9508b69d6 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check @@ -0,0 +1,18 @@ +// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer} +// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 8, !dbg !{{[0-9]+}}: {[-1]:Pointer} +// CHECK-DAG: %{{[0-9]+}} = load ptr, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !nonnull !102, !noundef !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 16, !dbg !{{[0-9]+}}: {[-1]:Pointer} +// CHECK-DAG: %{{[0-9]+}} = load i64, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = icmp eq i64 %{{[0-9]+}}, 0, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi i64 [ %{{[0-9]+}}, %{{[0-9]+}} ], [ 0, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], [ -0.000000e+00, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw float, ptr %{{[0-9]+}}, i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: %{{[0-9]+}} = add nuw i64 %{{[0-9]+}}, 1, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: %{{[0-9]+}} = icmp eq i64 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer} +// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = phi float [ -0.000000e+00, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float} +// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.rs b/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.rs new file mode 100644 index 000000000000..b60c2a88064c --- /dev/null +++ b/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.rs @@ -0,0 +1,14 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn callee(arg: &std::vec::Vec) -> f32 { + arg.iter().sum() +} + +fn main() { + let v = vec![1.0f32, 2.0, 3.0]; + let _ = callee(&v); +} From a9a5b33c2d7d5d1ada0efd23f97cc1f3b774dbda Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Tue, 15 Jul 2025 04:59:27 +0000 Subject: [PATCH 165/363] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index adf3f7389c68..67f27e7aa2c7 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -9c3064e131f4939cc95a29bb11413c49bbda1491 +7f2065a4bae1faed5bab928c670964eafbf43b55 From a74a28493a00900616d5e52cd85b8b6bae761935 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 15 Jul 2025 15:10:24 +0800 Subject: [PATCH 166/363] Add tests for UB check in `set_len`, `from_raw_parts_in`, `from_parts_in` Signed-off-by: xizheyin --- .../ui/precondition-checks/vec-from-parts.rs | 15 ++++++++++ .../precondition-checks/vec-from-raw-parts.rs | 29 +++++++++++++++++++ tests/ui/precondition-checks/vec-set-len.rs | 11 +++++++ 3 files changed, 55 insertions(+) create mode 100644 tests/ui/precondition-checks/vec-from-parts.rs create mode 100644 tests/ui/precondition-checks/vec-from-raw-parts.rs create mode 100644 tests/ui/precondition-checks/vec-set-len.rs diff --git a/tests/ui/precondition-checks/vec-from-parts.rs b/tests/ui/precondition-checks/vec-from-parts.rs new file mode 100644 index 000000000000..0bafb5aa715e --- /dev/null +++ b/tests/ui/precondition-checks/vec-from-parts.rs @@ -0,0 +1,15 @@ +//@ run-fail +//@ compile-flags: -Cdebug-assertions=yes +//@ error-pattern: unsafe precondition(s) violated: Vec::from_parts_in requires that length <= capacity +#![feature(allocator_api)] + +use std::ptr::NonNull; + +fn main() { + let ptr: NonNull = std::ptr::NonNull::dangling(); + // Test Vec::from_parts_in with length > capacity + unsafe { + let alloc = std::alloc::Global; + let _vec = Vec::from_parts_in(ptr, 10, 5, alloc); + } +} diff --git a/tests/ui/precondition-checks/vec-from-raw-parts.rs b/tests/ui/precondition-checks/vec-from-raw-parts.rs new file mode 100644 index 000000000000..884d34c0a564 --- /dev/null +++ b/tests/ui/precondition-checks/vec-from-raw-parts.rs @@ -0,0 +1,29 @@ +//@ run-fail +//@ compile-flags: -Cdebug-assertions=yes +//@ error-pattern: unsafe precondition(s) violated: Vec::from_raw_parts_in requires that length <= capacity +//@ revisions: vec_from_raw_parts vec_from_raw_parts_in string_from_raw_parts + +#![feature(allocator_api)] + +fn main() { + let ptr = std::ptr::null_mut::(); + // Test Vec::from_raw_parts with length > capacity + unsafe { + #[cfg(vec_from_raw_parts)] + let _vec = Vec::from_raw_parts(ptr, 10, 5); + } + + // Test Vec::from_raw_parts_in with length > capacity + unsafe { + let alloc = std::alloc::Global; + #[cfg(vec_from_raw_parts_in)] + let _vec = Vec::from_raw_parts_in(ptr, 10, 5, alloc); + } + + // Test String::from_raw_parts with length > capacity + // Because it calls Vec::from_raw_parts, it should also fail + unsafe { + #[cfg(string_from_raw_parts)] + let _vec = String::from_raw_parts(ptr, 10, 5); + } +} diff --git a/tests/ui/precondition-checks/vec-set-len.rs b/tests/ui/precondition-checks/vec-set-len.rs new file mode 100644 index 000000000000..0987e7fe0282 --- /dev/null +++ b/tests/ui/precondition-checks/vec-set-len.rs @@ -0,0 +1,11 @@ +//@ run-fail +//@ compile-flags: -Cdebug-assertions=yes +//@ error-pattern: unsafe precondition(s) violated: Vec::set_len requires that new_len <= capacity() + +fn main() { + let mut vec: Vec = Vec::with_capacity(5); + // Test set_len with length > capacity + unsafe { + vec.set_len(10); + } +} From b5230e53604f1227a087397e561e1cd2329f59b6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Jul 2025 08:06:42 +0000 Subject: [PATCH 167/363] constify `SliceIndex` trait --- library/core/src/range.rs | 16 ++++++++++----- library/core/src/slice/index.rs | 35 ++++++++++++++++++++++----------- library/core/src/str/traits.rs | 27 ++++++++++++++++--------- 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/library/core/src/range.rs b/library/core/src/range.rs index 2276112a27bb..5cd7956291ca 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -186,14 +186,17 @@ impl IntoBounds for Range { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::Range { #[inline] fn from(value: Range) -> Self { Self { start: value.start, end: value.end } } } + #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for Range { #[inline] fn from(value: legacy::Range) -> Self { Self { start: value.start, end: value.end } @@ -362,7 +365,8 @@ impl IntoBounds for RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::RangeInclusive { #[inline] fn from(value: RangeInclusive) -> Self { Self::new(value.start, value.end) @@ -506,14 +510,16 @@ impl IntoBounds for RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::RangeFrom { #[inline] fn from(value: RangeFrom) -> Self { Self { start: value.start } } } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for RangeFrom { #[inline] fn from(value: legacy::RangeFrom) -> Self { Self { start: value.start } diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index f725c3fdd94c..c9b8e9c71b49 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -158,6 +158,8 @@ mod private_slice_index { message = "the type `{T}` cannot be indexed by `{Self}`", label = "slice indices are of type `usize` or ranges of `usize`" )] +#[const_trait] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] pub unsafe trait SliceIndex: private_slice_index::Sealed { /// The output type returned by methods. #[stable(feature = "slice_get_slice", since = "1.28.0")] @@ -208,7 +210,8 @@ pub unsafe trait SliceIndex: private_slice_index::Sealed { /// The methods `index` and `index_mut` panic if the index is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for usize { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for usize { type Output = T; #[inline] @@ -278,7 +281,8 @@ unsafe impl SliceIndex<[T]> for usize { /// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here /// than there are for a general `Range` (which might be `100..3`). -unsafe impl SliceIndex<[T]> for ops::IndexRange { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::IndexRange { type Output = [T]; #[inline] @@ -354,7 +358,8 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { /// - the start of the range is greater than the end of the range or /// - the end of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::Range { type Output = [T]; #[inline] @@ -453,7 +458,8 @@ unsafe impl SliceIndex<[T]> for ops::Range { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::Range { type Output = [T]; #[inline] @@ -491,7 +497,8 @@ unsafe impl SliceIndex<[T]> for range::Range { /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeTo { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeTo { type Output = [T]; #[inline] @@ -529,7 +536,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeTo { /// The methods `index` and `index_mut` panic if the start of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeFrom { type Output = [T]; #[inline] @@ -574,7 +582,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::RangeFrom { type Output = [T]; #[inline] @@ -611,7 +620,8 @@ unsafe impl SliceIndex<[T]> for range::RangeFrom { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFull { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeFull { type Output = [T]; #[inline] @@ -650,7 +660,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeFull { /// - the start of the range is greater than the end of the range or /// - the end of the range is out of bounds. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; #[inline] @@ -693,7 +704,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::RangeInclusive { type Output = [T]; #[inline] @@ -731,7 +743,8 @@ unsafe impl SliceIndex<[T]> for range::RangeInclusive { /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; #[inline] diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index b9559c831713..2ed5e686399e 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -92,7 +92,8 @@ const fn str_index_overflow_fail() -> ! { /// /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeFull { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeFull { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -156,7 +157,8 @@ unsafe impl SliceIndex for ops::RangeFull { /// // &s[3 .. 100]; /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::Range { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -260,7 +262,8 @@ unsafe impl SliceIndex for ops::Range { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::Range { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -431,7 +434,8 @@ unsafe impl SliceIndex for (ops::Bound, ops::Bound) { /// Panics if `end` does not point to the starting byte offset of a /// character (as defined by `is_char_boundary`), or if `end > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeTo { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeTo { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -499,7 +503,8 @@ unsafe impl SliceIndex for ops::RangeTo { /// Panics if `begin` does not point to the starting byte offset of /// a character (as defined by `is_char_boundary`), or if `begin > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeFrom { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -554,7 +559,8 @@ unsafe impl SliceIndex for ops::RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::RangeFrom { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -625,7 +631,8 @@ unsafe impl SliceIndex for range::RangeFrom { /// to the ending byte offset of a character (`end + 1` is either a starting /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex for ops::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -662,7 +669,8 @@ unsafe impl SliceIndex for ops::RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::RangeInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -713,7 +721,8 @@ unsafe impl SliceIndex for range::RangeInclusive { /// (`end + 1` is either a starting byte offset as defined by /// `is_char_boundary`, or equal to `len`), or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex for ops::RangeToInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeToInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { From cb7d52f6430922b5ffd29073f6605b19b80e7f36 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Jul 2025 08:37:09 +0000 Subject: [PATCH 168/363] constify some methods using `SliceIndex` --- library/core/src/ptr/const_ptr.rs | 5 +++-- library/core/src/ptr/mut_ptr.rs | 5 +++-- library/core/src/ptr/non_null.rs | 5 +++-- library/core/src/slice/mod.rs | 20 +++++++++++-------- library/core/src/str/mod.rs | 6 ++++-- .../const-eval/ub-slice-get-unchecked.rs | 3 ++- .../const-eval/ub-slice-get-unchecked.stderr | 12 +++++------ 7 files changed, 33 insertions(+), 23 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 27b0c6830db6..2ad520b7ead7 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1524,10 +1524,11 @@ impl *const [T] { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub unsafe fn get_unchecked(self, index: I) -> *const I::Output + pub const unsafe fn get_unchecked(self, index: I) -> *const I::Output where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. unsafe { index.get_unchecked(self) } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 73efdf044541..579e2461103d 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1881,10 +1881,11 @@ impl *mut [T] { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline(always)] - pub unsafe fn get_unchecked_mut(self, index: I) -> *mut I::Output + pub const unsafe fn get_unchecked_mut(self, index: I) -> *mut I::Output where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. unsafe { index.get_unchecked_mut(self) } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index c4ca29a36797..62da6567cca7 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1597,10 +1597,11 @@ impl NonNull<[T]> { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub unsafe fn get_unchecked_mut(self, index: I) -> NonNull + pub const unsafe fn get_unchecked_mut(self, index: I) -> NonNull where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. // As a consequence, the resulting pointer cannot be null. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index abcba5a621e2..32419024db95 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -568,9 +568,10 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] - pub fn get(&self, index: I) -> Option<&I::Output> + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get(&self, index: I) -> Option<&I::Output> where - I: SliceIndex, + I: ~const SliceIndex, { index.get(self) } @@ -594,9 +595,10 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] - pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get_mut(&mut self, index: I) -> Option<&mut I::Output> where - I: SliceIndex, + I: ~const SliceIndex, { index.get_mut(self) } @@ -633,9 +635,10 @@ impl [T] { #[inline] #[must_use] #[track_caller] - pub unsafe fn get_unchecked(&self, index: I) -> &I::Output + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const unsafe fn get_unchecked(&self, index: I) -> &I::Output where - I: SliceIndex, + I: ~const SliceIndex, { // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`; // the slice is dereferenceable because `self` is a safe reference. @@ -677,9 +680,10 @@ impl [T] { #[inline] #[must_use] #[track_caller] - pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output where - I: SliceIndex, + I: ~const SliceIndex, { // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`; // the slice is dereferenceable because `self` is a safe reference. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index fba3436496e3..bb0106b9fd94 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -589,8 +589,9 @@ impl str { /// assert!(v.get(..42).is_none()); /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub fn get>(&self, i: I) -> Option<&I::Output> { + pub const fn get>(&self, i: I) -> Option<&I::Output> { i.get(self) } @@ -621,8 +622,9 @@ impl str { /// assert_eq!("HEllo", v); /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { + pub const fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { i.get_mut(self) } diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs index e805ac01c9d0..ad2b49e60498 100644 --- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs +++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs @@ -1,9 +1,10 @@ -//@ known-bug: #110395 +#![feature(const_index, const_trait_impl)] const A: [(); 5] = [(), (), (), (), ()]; // Since the indexing is on a ZST, the addresses are all fine, // but we should still catch the bad range. const B: &[()] = unsafe { A.get_unchecked(3..1) }; +//~^ ERROR: slice::get_unchecked requires that the range is within the slice fn main() {} diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr index 6e428079afe8..88ea310f19c6 100644 --- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr +++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr @@ -1,11 +1,11 @@ -error[E0015]: cannot call non-const method `core::slice::::get_unchecked::>` in constants - --> $DIR/ub-slice-get-unchecked.rs:7:29 +error[E0080]: evaluation panicked: unsafe precondition(s) violated: slice::get_unchecked requires that the range is within the slice + + This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety. + --> $DIR/ub-slice-get-unchecked.rs:7:27 | LL | const B: &[()] = unsafe { A.get_unchecked(3..1) }; - | ^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `B` failed here error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0080`. From 2b4ede7e3d37de731821b5b04a6f1fce269c1afb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Jul 2025 09:24:42 +0000 Subject: [PATCH 169/363] constify `Index` trait and its slice impls --- library/core/src/array/mod.rs | 10 +++-- library/core/src/ops/index.rs | 6 ++- library/core/src/slice/index.rs | 10 +++-- library/core/src/str/traits.rs | 10 +++-- tests/ui/consts/issue-94675.rs | 4 +- tests/ui/consts/issue-94675.stderr | 27 +++++++++---- .../issues/issue-35813-postfix-after-cast.rs | 3 +- .../issue-35813-postfix-after-cast.stderr | 38 +++++++------------ 8 files changed, 60 insertions(+), 48 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 16356f749c92..62203e132b70 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -374,9 +374,10 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] { } #[stable(feature = "index_trait_on_arrays", since = "1.50.0")] -impl Index for [T; N] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const Index for [T; N] where - [T]: Index, + [T]: ~const Index, { type Output = <[T] as Index>::Output; @@ -387,9 +388,10 @@ where } #[stable(feature = "index_trait_on_arrays", since = "1.50.0")] -impl IndexMut for [T; N] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const IndexMut for [T; N] where - [T]: IndexMut, + [T]: ~const IndexMut, { #[inline] fn index_mut(&mut self, index: I) -> &mut Self::Output { diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 8092fa9eb2fc..d8489e9a9491 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -55,6 +55,8 @@ #[doc(alias = "]")] #[doc(alias = "[")] #[doc(alias = "[]")] +#[const_trait] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] pub trait Index { /// The returned type after indexing. #[stable(feature = "rust1", since = "1.0.0")] @@ -165,7 +167,9 @@ see chapter in The Book : Index { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +#[const_trait] +pub trait IndexMut: ~const Index { /// Performs the mutable indexing (`container[index]`) operation. /// /// # Panics diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index c9b8e9c71b49..322b3580eded 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -6,9 +6,10 @@ use crate::ub_checks::assert_unsafe_precondition; use crate::{ops, range}; #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for [T] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::Index for [T] where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { type Output = I::Output; @@ -19,9 +20,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for [T] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::IndexMut for [T] where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { #[inline(always)] fn index_mut(&mut self, index: I) -> &mut I::Output { diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 2ed5e686399e..42ffc591b5bb 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -49,9 +49,10 @@ impl PartialOrd for str { } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for str +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::Index for str where - I: SliceIndex, + I: ~const SliceIndex, { type Output = I::Output; @@ -62,9 +63,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for str +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::IndexMut for str where - I: SliceIndex, + I: ~const SliceIndex, { #[inline] fn index_mut(&mut self, index: I) -> &mut I::Output { diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs index 87c8b04452ba..22791e7d15e5 100644 --- a/tests/ui/consts/issue-94675.rs +++ b/tests/ui/consts/issue-94675.rs @@ -7,7 +7,9 @@ struct Foo<'a> { impl<'a> Foo<'a> { const fn spam(&mut self, baz: &mut Vec) { self.bar[0] = baz.len(); - //~^ ERROR: cannot call + //~^ ERROR: `Vec: [const] Index<_>` is not satisfied + //~| ERROR: `Vec: [const] Index` is not satisfied + //~| ERROR: `Vec: [const] IndexMut` is not satisfied } } diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index 63a86b456332..608ce0cfef01 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -1,13 +1,24 @@ -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/issue-94675.rs:9:17 +error[E0277]: the trait bound `Vec: [const] Index<_>` is not satisfied + --> $DIR/issue-94675.rs:9:9 | LL | self.bar[0] = baz.len(); - | ^^^ + | ^^^^^^^^^^^ + +error[E0277]: the trait bound `Vec: [const] IndexMut` is not satisfied + --> $DIR/issue-94675.rs:9:9 | -note: impl defined here, but it is not `const` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +LL | self.bar[0] = baz.len(); + | ^^^^^^^^^^^ -error: aborting due to 1 previous error +error[E0277]: the trait bound `Vec: [const] Index` is not satisfied + --> $DIR/issue-94675.rs:9:9 + | +LL | self.bar[0] = baz.len(); + | ^^^^^^^^^^^ + | +note: required by a bound in `std::ops::IndexMut::index_mut` + --> $SRC_DIR/core/src/ops/index.rs:LL:COL -For more information about this error, try `rustc --explain E0015`. +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs b/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs index 316c612940c9..439793ea8f72 100644 --- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs +++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs @@ -1,6 +1,6 @@ //@ edition:2018 #![crate_type = "lib"] -#![feature(type_ascription)] +#![feature(type_ascription, const_index, const_trait_impl)] use std::future::Future; use std::pin::Pin; @@ -129,7 +129,6 @@ pub fn inside_block() { static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); //~^ ERROR: cast cannot be followed by indexing -//~| ERROR: cannot call non-const operator in statics static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); //~^ ERROR: expected one of diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr index 64cf8baf9a5d..ce7129da9371 100644 --- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr +++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr @@ -219,13 +219,13 @@ LL | static bar: &[i32] = &((&[1,2,3] as &[i32])[0..1]); | + + error: expected one of `)`, `,`, `.`, `?`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:134:36 + --> $DIR/issue-35813-postfix-after-cast.rs:133:36 | LL | static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); | ^ expected one of `)`, `,`, `.`, `?`, or an operator error: cast cannot be followed by `?` - --> $DIR/issue-35813-postfix-after-cast.rs:139:5 + --> $DIR/issue-35813-postfix-after-cast.rs:138:5 | LL | Err(0u64) as Result?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -236,25 +236,25 @@ LL | (Err(0u64) as Result)?; | + + error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:141:14 + --> $DIR/issue-35813-postfix-after-cast.rs:140:14 | LL | Err(0u64): Result?; | ^ expected one of `.`, `;`, `?`, `}`, or an operator error: expected identifier, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:153:13 + --> $DIR/issue-35813-postfix-after-cast.rs:152:13 | LL | drop_ptr: F(); | ^ expected identifier error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:160:13 + --> $DIR/issue-35813-postfix-after-cast.rs:159:13 | LL | drop_ptr: fn(u8); | ^ expected one of 8 possible tokens error: cast cannot be followed by a function call - --> $DIR/issue-35813-postfix-after-cast.rs:166:5 + --> $DIR/issue-35813-postfix-after-cast.rs:165:5 | LL | drop as fn(u8)(0); | ^^^^^^^^^^^^^^ @@ -265,13 +265,13 @@ LL | (drop as fn(u8))(0); | + + error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:168:13 + --> $DIR/issue-35813-postfix-after-cast.rs:167:13 | LL | drop_ptr: fn(u8)(0); | ^ expected one of 8 possible tokens error: cast cannot be followed by `.await` - --> $DIR/issue-35813-postfix-after-cast.rs:173:5 + --> $DIR/issue-35813-postfix-after-cast.rs:172:5 | LL | Box::pin(noop()) as Pin>>.await; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -282,13 +282,13 @@ LL | (Box::pin(noop()) as Pin>>).await; | + + error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:176:21 + --> $DIR/issue-35813-postfix-after-cast.rs:175:21 | LL | Box::pin(noop()): Pin>.await; | ^ expected one of `.`, `;`, `?`, `}`, or an operator error: cast cannot be followed by a field access - --> $DIR/issue-35813-postfix-after-cast.rs:188:5 + --> $DIR/issue-35813-postfix-after-cast.rs:187:5 | LL | Foo::default() as Foo.bar; | ^^^^^^^^^^^^^^^^^^^^^ @@ -299,7 +299,7 @@ LL | (Foo::default() as Foo).bar; | + + error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:190:19 + --> $DIR/issue-35813-postfix-after-cast.rs:189:19 | LL | Foo::default(): Foo.bar; | ^ expected one of `.`, `;`, `?`, `}`, or an operator @@ -322,21 +322,11 @@ LL | if true { 33 } else { 44 }: i32.max(0) | ^ expected one of `,`, `.`, `?`, or an operator error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/issue-35813-postfix-after-cast.rs:151:13 + --> $DIR/issue-35813-postfix-after-cast.rs:150:13 | LL | drop as F(); | ^^^ only `Fn` traits may use parentheses -error[E0015]: cannot call non-const operator in statics - --> $DIR/issue-35813-postfix-after-cast.rs:130:42 - | -LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); - | ^^^^^^ - | - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` +error: aborting due to 39 previous errors -error: aborting due to 40 previous errors - -Some errors have detailed explanations: E0015, E0214. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0214`. From 0d6dc2f52de5bd7900f36c3e12234ee5d8fa7f91 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Mon, 14 Jul 2025 09:08:29 +0000 Subject: [PATCH 170/363] tidy: more clippy fixes --- src/tools/tidy/src/features.rs | 35 ++++++++-------- src/tools/tidy/src/fluent_period.rs | 29 ++++++------- src/tools/tidy/src/lib.rs | 2 +- src/tools/tidy/src/mir_opt_tests.rs | 31 +++++++------- src/tools/tidy/src/rustdoc_templates.rs | 2 +- src/tools/tidy/src/style.rs | 46 ++++++++++----------- src/tools/tidy/src/target_specific_tests.rs | 22 +++++----- src/tools/tidy/src/ui_tests.rs | 41 +++++++++--------- src/tools/tidy/src/x_version.rs | 12 +++--- 9 files changed, 109 insertions(+), 111 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index e83b47e13806..fb00b3a943f8 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -331,11 +331,9 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba continue; } - if in_feature_group { - if let Some(doc_comment) = line.strip_prefix("///") { - doc_comments.push(doc_comment.trim().to_string()); - continue; - } + if in_feature_group && let Some(doc_comment) = line.strip_prefix("///") { + doc_comments.push(doc_comment.trim().to_string()); + continue; } let mut parts = line.split(','); @@ -465,19 +463,20 @@ fn get_and_check_lib_features( map_lib_features(base_src_path, &mut |res, file, line| match res { Ok((name, f)) => { let mut check_features = |f: &Feature, list: &Features, display: &str| { - if let Some(s) = list.get(name) { - if f.tracking_issue != s.tracking_issue && f.level != Status::Accepted { - tidy_error!( - bad, - "{}:{}: feature gate {} has inconsistent `issue`: \"{}\" mismatches the {} `issue` of \"{}\"", - file.display(), - line, - name, - f.tracking_issue_display(), - display, - s.tracking_issue_display(), - ); - } + if let Some(s) = list.get(name) + && f.tracking_issue != s.tracking_issue + && f.level != Status::Accepted + { + tidy_error!( + bad, + "{}:{}: feature gate {} has inconsistent `issue`: \"{}\" mismatches the {} `issue` of \"{}\"", + file.display(), + line, + name, + f.tracking_issue_display(), + display, + s.tracking_issue_display(), + ); } }; check_features(&f, lang_features, "corresponding lang feature"); diff --git a/src/tools/tidy/src/fluent_period.rs b/src/tools/tidy/src/fluent_period.rs index 85c1ef6166a4..836b5699289f 100644 --- a/src/tools/tidy/src/fluent_period.rs +++ b/src/tools/tidy/src/fluent_period.rs @@ -33,14 +33,14 @@ fn check_period(filename: &str, contents: &str, bad: &mut bool) { continue; } - if let Some(pat) = &m.value { - if let Some(PatternElement::TextElement { value }) = pat.elements.last() { - // We don't care about ellipses. - if value.ends_with(".") && !value.ends_with("...") { - let ll = find_line(contents, value); - let name = m.id.name; - tidy_error!(bad, "{filename}:{ll}: message `{name}` ends in a period"); - } + if let Some(pat) = &m.value + && let Some(PatternElement::TextElement { value }) = pat.elements.last() + { + // We don't care about ellipses. + if value.ends_with(".") && !value.ends_with("...") { + let ll = find_line(contents, value); + let name = m.id.name; + tidy_error!(bad, "{filename}:{ll}: message `{name}` ends in a period"); } } @@ -50,12 +50,13 @@ fn check_period(filename: &str, contents: &str, bad: &mut bool) { continue; } - if let Some(PatternElement::TextElement { value }) = attr.value.elements.last() { - if value.ends_with(".") && !value.ends_with("...") { - let ll = find_line(contents, value); - let name = attr.id.name; - tidy_error!(bad, "{filename}:{ll}: attr `{name}` ends in a period"); - } + if let Some(PatternElement::TextElement { value }) = attr.value.elements.last() + && value.ends_with(".") + && !value.ends_with("...") + { + let ll = find_line(contents, value); + let name = attr.id.name; + tidy_error!(bad, "{filename}:{ll}: attr `{name}` ends in a period"); } } } diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 77855392b4da..bd8660797a8f 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -134,7 +134,7 @@ pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool { eprintln!("No base commit, assuming all files are modified"); return true; }; - match crate::git_diff(&base_commit, "--name-status") { + match crate::git_diff(base_commit, "--name-status") { Some(output) => { let modified_files = output.lines().filter_map(|ln| { let (status, name) = ln diff --git a/src/tools/tidy/src/mir_opt_tests.rs b/src/tools/tidy/src/mir_opt_tests.rs index 1efe71b1687e..6119eb58383e 100644 --- a/src/tools/tidy/src/mir_opt_tests.rs +++ b/src/tools/tidy/src/mir_opt_tests.rs @@ -55,22 +55,21 @@ fn check_dash_files(path: &Path, bless: bool, bad: &mut bool) { .filter(|e| e.file_type().is_file()) { let path = file.path(); - if path.extension() == Some("rs".as_ref()) { - if let Some(name) = path.file_name().and_then(|s| s.to_str()) { - if name.contains('-') { - if !bless { - tidy_error!( - bad, - "mir-opt test files should not have dashes in them: {}", - path.display() - ); - } else { - let new_name = name.replace('-', "_"); - let mut new_path = path.to_owned(); - new_path.set_file_name(new_name); - let _ = std::fs::rename(path, new_path); - } - } + if path.extension() == Some("rs".as_ref()) + && let Some(name) = path.file_name().and_then(|s| s.to_str()) + && name.contains('-') + { + if !bless { + tidy_error!( + bad, + "mir-opt test files should not have dashes in them: {}", + path.display() + ); + } else { + let new_name = name.replace('-', "_"); + let mut new_path = path.to_owned(); + new_path.set_file_name(new_name); + let _ = std::fs::rename(path, new_path); } } } diff --git a/src/tools/tidy/src/rustdoc_templates.rs b/src/tools/tidy/src/rustdoc_templates.rs index dca3e8d9d25f..597290a6a9a8 100644 --- a/src/tools/tidy/src/rustdoc_templates.rs +++ b/src/tools/tidy/src/rustdoc_templates.rs @@ -26,7 +26,7 @@ pub fn check(librustdoc_path: &Path, bad: &mut bool) { None // Then we check if this a comment tag. } else if *tag != "{#" { - return Some(false); + Some(false) // And finally we check if the comment is empty (ie, only there to strip // extra whitespace characters). } else if let Some(start_pos) = line.rfind(tag) { diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 8dde4618ce52..35ed61eacc73 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -417,10 +417,10 @@ pub fn check(path: &Path, bad: &mut bool) { return; } // Shell completions are automatically generated - if let Some(p) = file.parent() { - if p.ends_with(Path::new("src/etc/completions")) { - return; - } + if let Some(p) = file.parent() + && p.ends_with(Path::new("src/etc/completions")) + { + return; } let [ mut skip_cr, @@ -604,25 +604,25 @@ pub fn check(path: &Path, bad: &mut bool) { backtick_count += comment_text.chars().filter(|ch| *ch == '`').count(); } comment_block = Some((start_line, backtick_count)); - } else if let Some((start_line, backtick_count)) = comment_block.take() { - if backtick_count % 2 == 1 { - let mut err = |msg: &str| { - tidy_error!(bad, "{}:{start_line}: {msg}", file.display()); - }; - let block_len = (i + 1) - start_line; - if block_len == 1 { - suppressible_tidy_err!( - err, - skip_odd_backticks, - "comment with odd number of backticks" - ); - } else { - suppressible_tidy_err!( - err, - skip_odd_backticks, - "{block_len}-line comment block with odd number of backticks" - ); - } + } else if let Some((start_line, backtick_count)) = comment_block.take() + && backtick_count % 2 == 1 + { + let mut err = |msg: &str| { + tidy_error!(bad, "{}:{start_line}: {msg}", file.display()); + }; + let block_len = (i + 1) - start_line; + if block_len == 1 { + suppressible_tidy_err!( + err, + skip_odd_backticks, + "comment with odd number of backticks" + ); + } else { + suppressible_tidy_err!( + err, + skip_odd_backticks, + "{block_len}-line comment block with odd number of backticks" + ); } } } diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs index 1a6fd3eaf2dd..f4a6783abb67 100644 --- a/src/tools/tidy/src/target_specific_tests.rs +++ b/src/tools/tidy/src/target_specific_tests.rs @@ -30,17 +30,17 @@ pub fn check(tests_path: &Path, bad: &mut bool) { comp_vec.push(component); } } - } else if let Some(compile_flags) = directive.strip_prefix(COMPILE_FLAGS_HEADER) { - if 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); - } else { - eprintln!("{file}: seems to have a malformed --target value"); - *bad = true; - } + } else if let Some(compile_flags) = directive.strip_prefix(COMPILE_FLAGS_HEADER) + && 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); + } else { + eprintln!("{file}: seems to have a malformed --target value"); + *bad = true; } } }); diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index b1ace74e5bd2..adc001828723 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -161,31 +161,30 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) { tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path); } - if let Ok(metadata) = fs::metadata(file_path) { - if metadata.len() == 0 { - tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path); - } + if let Ok(metadata) = fs::metadata(file_path) + && metadata.len() == 0 + { + tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path); } } - if ext == "rs" { - if let Some(test_name) = static_regex!(r"^issues?[-_]?(\d{3,})").captures(testname) - { - // these paths are always relative to the passed `path` and always UTF8 - let stripped_path = file_path - .strip_prefix(path) - .unwrap() - .to_str() - .unwrap() - .replace(std::path::MAIN_SEPARATOR_STR, "/"); + if ext == "rs" + && let Some(test_name) = static_regex!(r"^issues?[-_]?(\d{3,})").captures(testname) + { + // these paths are always relative to the passed `path` and always UTF8 + let stripped_path = file_path + .strip_prefix(path) + .unwrap() + .to_str() + .unwrap() + .replace(std::path::MAIN_SEPARATOR_STR, "/"); - if !remaining_issue_names.remove(stripped_path.as_str()) { - tidy_error!( - bad, - "file `tests/{stripped_path}` must begin with a descriptive name, consider `{{reason}}-issue-{issue_n}.rs`", - issue_n = &test_name[1], - ); - } + if !remaining_issue_names.remove(stripped_path.as_str()) { + tidy_error!( + bad, + "file `tests/{stripped_path}` must begin with a descriptive name, consider `{{reason}}-issue-{issue_n}.rs`", + issue_n = &test_name[1], + ); } } } diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs index 6a5e9eca8132..9f7f43c4000b 100644 --- a/src/tools/tidy/src/x_version.rs +++ b/src/tools/tidy/src/x_version.rs @@ -25,12 +25,12 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { if let Some(version) = iter.next() { // Check this is the rust-lang/rust x tool installation since it should be // installed at a path containing `src/tools/x`. - if let Some(path) = iter.next() { - if path.contains("src/tools/x") { - let version = version.strip_prefix("v").unwrap(); - installed = Some(Version::parse(version).unwrap()); - break; - } + if let Some(path) = iter.next() + && path.contains("src/tools/x") + { + let version = version.strip_prefix("v").unwrap(); + installed = Some(Version::parse(version).unwrap()); + break; }; } } else { From e1d35c551fde82668d7e8be8f759bd02e9b5345b Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Tue, 15 Jul 2025 10:32:19 +0200 Subject: [PATCH 171/363] Add std::hint::spin_loop() --- .../miri/tests/pass/0weak_memory_consistency.rs | 12 ++++++++++-- .../miri/tests/pass/0weak_memory_consistency_sc.rs | 12 ++++++++++-- src/tools/miri/tests/pass/weak_memory/weak.rs | 4 ++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/tests/pass/0weak_memory_consistency.rs b/src/tools/miri/tests/pass/0weak_memory_consistency.rs index b33aefaf1d59..5fba54934421 100644 --- a/src/tools/miri/tests/pass/0weak_memory_consistency.rs +++ b/src/tools/miri/tests/pass/0weak_memory_consistency.rs @@ -48,6 +48,14 @@ fn loads_value(loc: &AtomicI32, ord: Ordering, val: i32) -> i32 { val } +/// Spins until it acquires a pre-determined boolean. +fn loads_bool(loc: &AtomicBool, ord: Ordering, val: bool) -> bool { + while loc.load(ord) != val { + std::hint::spin_loop(); + } + val +} + fn test_corr() { let x = static_atomic(0); let y = static_atomic(0); @@ -216,12 +224,12 @@ fn test_sync_through_rmw_and_fences() { let go = static_atomic_bool(false); let t1 = spawn(move || { - while !go.load(Relaxed) {} + loads_bool(go, Relaxed, true); rdmw(y, x, z) }); let t2 = spawn(move || { - while !go.load(Relaxed) {} + loads_bool(go, Relaxed, true); rdmw(z, x, y) }); diff --git a/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs b/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs index 45cc5e6e7221..2c9d742a8b11 100644 --- a/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs +++ b/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs @@ -27,6 +27,14 @@ fn loads_value(loc: &AtomicI32, ord: Ordering, val: i32) -> i32 { val } +/// Spins until it acquires a pre-determined boolean. +fn loads_bool(loc: &AtomicBool, ord: Ordering, val: bool) -> bool { + while loc.load(ord) != val { + std::hint::spin_loop(); + } + val +} + // Test case SB taken from Repairing Sequential Consistency in C/C++11 // by Lahav et al. // https://plv.mpi-sws.org/scfix/paper.pdf @@ -60,11 +68,11 @@ fn test_iriw_sc_rlx() { let a = spawn(move || x.store(true, Relaxed)); let b = spawn(move || y.store(true, Relaxed)); let c = spawn(move || { - while !x.load(SeqCst) {} + loads_bool(x, SeqCst, true); y.load(SeqCst) }); let d = spawn(move || { - while !y.load(SeqCst) {} + loads_bool(y, SeqCst, true); x.load(SeqCst) }); diff --git a/src/tools/miri/tests/pass/weak_memory/weak.rs b/src/tools/miri/tests/pass/weak_memory/weak.rs index eeab4ebf129e..569a307ab064 100644 --- a/src/tools/miri/tests/pass/weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/weak_memory/weak.rs @@ -119,12 +119,12 @@ fn faa_replaced_by_load() -> bool { let go = static_atomic(0); let t1 = spawn(move || { - while go.load(Relaxed) == 0 {} + reads_value(go, 1); rdmw(y, x, z) }); let t2 = spawn(move || { - while go.load(Relaxed) == 0 {} + reads_value(go, 1); rdmw(z, x, y) }); From da6d7ca1be6586ba8e0d2b89f1d60ff256dfc7ea Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Tue, 15 Jul 2025 08:59:41 +0000 Subject: [PATCH 172/363] tidy static regex: OnceLock -> LazyLock --- src/tools/tidy/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index bd8660797a8f..a301781fac86 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -13,8 +13,9 @@ use termcolor::WriteColor; macro_rules! static_regex { ($re:literal) => {{ - static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new(); - RE.get_or_init(|| ::regex::Regex::new($re).unwrap()) + static RE: ::std::sync::LazyLock<::regex::Regex> = + ::std::sync::LazyLock::new(|| ::regex::Regex::new($re).unwrap()); + &*RE }}; } From 32391f71598f637887abcb7614ad287763f8275d Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Tue, 15 Jul 2025 09:07:07 +0000 Subject: [PATCH 173/363] tidy: improve comment --- src/tools/tidy/src/fluent_used.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/tidy/src/fluent_used.rs b/src/tools/tidy/src/fluent_used.rs index 12fafd9a7ffc..909bf482ddfc 100644 --- a/src/tools/tidy/src/fluent_used.rs +++ b/src/tools/tidy/src/fluent_used.rs @@ -12,7 +12,7 @@ fn filter_used_messages( ) { // we don't just check messages never appear in Rust files, // because messages can be used as parts of other fluent messages in Fluent files, - // so we do checking messages appear only once in all Rust and Fluent files. + // so we check messages appear only once in all Rust and Fluent files. let matches = static_regex!(r"\w+").find_iter(contents); for name in matches { if let Some((name, filename)) = msgs_not_appeared_yet.remove_entry(name.as_str()) { From cbaaf153a58ed0ebbc9c327c3d61462aef7aee15 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 15 Jul 2025 11:04:07 +0200 Subject: [PATCH 174/363] tidy: check for invalid file names --- src/tools/tidy/src/filenames.rs | 40 +++++++++++++++++++++++++++++++++ src/tools/tidy/src/lib.rs | 1 + src/tools/tidy/src/main.rs | 2 ++ 3 files changed, 43 insertions(+) create mode 100644 src/tools/tidy/src/filenames.rs diff --git a/src/tools/tidy/src/filenames.rs b/src/tools/tidy/src/filenames.rs new file mode 100644 index 000000000000..53115f4eaa41 --- /dev/null +++ b/src/tools/tidy/src/filenames.rs @@ -0,0 +1,40 @@ +//! Tidy check to ensure that there are no filenames containing forbidden characters +//! checked into the source tree by accident: +//! - Non-UTF8 filenames +//! - Control characters such as CR or TAB +//! - Filenames containing ":" as they are not supported on Windows +//! +//! Only files added to git are checked, as it may be acceptable to have temporary +//! invalid filenames in the local directory during development. + +use std::path::Path; +use std::process::Command; + +pub fn check(root_path: &Path, bad: &mut bool) { + let stat_output = Command::new("git") + .arg("-C") + .arg(root_path) + .args(["ls-files", "-z"]) + .output() + .unwrap() + .stdout; + for filename in stat_output.split(|&b| b == 0) { + match str::from_utf8(filename) { + Err(_) => tidy_error!( + bad, + r#"non-UTF8 file names are not supported: "{}""#, + String::from_utf8_lossy(filename), + ), + Ok(name) if name.chars().any(|c| c.is_control()) => tidy_error!( + bad, + r#"control characters are not supported in file names: "{}""#, + String::from_utf8_lossy(filename), + ), + Ok(name) if name.contains(':') => tidy_error!( + bad, + r#"":" is not supported in file names because of Windows compatibility: "{name}""#, + ), + _ => (), + } + } +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 77855392b4da..ade4055b5bd1 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -167,6 +167,7 @@ pub mod error_codes; pub mod ext_tool_checks; pub mod extdeps; pub mod features; +pub mod filenames; pub mod fluent_alphabetical; pub mod fluent_period; mod fluent_used; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index a67f7a511b59..0f1116a632e2 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -155,6 +155,8 @@ fn main() { check!(triagebot, &root_path); + check!(filenames, &root_path); + let collected = { drain_handles(&mut handles); From 6b51eee9df2622c790cb7ff26176c9be7672ef9c Mon Sep 17 00:00:00 2001 From: Stypox Date: Mon, 7 Jul 2025 11:10:51 +0200 Subject: [PATCH 175/363] Add enter_trace_span! that checks #[cfg("tracing")] Includes a custom syntax shortand to enter_trace_span! with NAME::SUBNAME. MaybeEnteredTraceSpan is `pub use`d in lib.rs to make it available also in bin/, just in case. --- src/tools/miri/src/helpers.rs | 41 +++++++++++++++++++++++++++++++++++ src/tools/miri/src/lib.rs | 4 +++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index b259243602ee..b76d046d1d22 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1431,3 +1431,44 @@ impl ToU64 for usize { self.try_into().unwrap() } } + +/// This struct is needed to enforce `#[must_use]` on values produced by [enter_trace_span] even +/// when the "tracing" feature is not enabled. +#[must_use] +pub struct MaybeEnteredTraceSpan { + #[cfg(feature = "tracing")] + pub _entered_span: tracing::span::EnteredSpan, +} + +/// Enters a [tracing::info_span] only if the "tracing" feature is enabled, otherwise does nothing. +/// This is like [rustc_const_eval::enter_trace_span] except that it does not depend on the +/// [Machine] trait to check if tracing is enabled, because from the Miri codebase we can directly +/// check whether the "tracing" feature is enabled, unlike from the rustc_const_eval codebase. +/// +/// In addition to the syntax accepted by [tracing::span!], this macro optionally allows passing +/// the span name (i.e. the first macro argument) in the form `NAME::SUBNAME` (without quotes) to +/// indicate that the span has name "NAME" (usually the name of the component) and has an additional +/// more specific name "SUBNAME" (usually the function name). The latter is passed to the [tracing] +/// infrastructure as a span field with the name "NAME". This allows not being distracted by +/// subnames when looking at the trace in , but when deeper introspection +/// is needed within a component, it's still possible to view the subnames directly in the UI by +/// selecting a span, clicking on the "NAME" argument on the right, and clicking on "Visualize +/// argument values". +/// ```rust +/// // for example, the first will expand to the second +/// enter_trace_span!(borrow_tracker::on_stack_pop, /* ... */) +/// enter_trace_span!("borrow_tracker", borrow_tracker = "on_stack_pop", /* ... */) +/// ``` +#[macro_export] +macro_rules! enter_trace_span { + ($name:ident :: $subname:ident $($tt:tt)*) => {{ + enter_trace_span!(stringify!($name), $name = %stringify!(subname) $($tt)*) + }}; + + ($($tt:tt)*) => { + $crate::MaybeEnteredTraceSpan { + #[cfg(feature = "tracing")] + _entered_span: tracing::info_span!($($tt)*).entered() + } + }; +} diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index ca99d69b32d0..f6d01831a972 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -139,7 +139,9 @@ pub use crate::eval::{ AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, MiriEntryFnType, RejectOpWith, ValidationMode, create_ecx, eval_entry, }; -pub use crate::helpers::{AccessKind, EvalContextExt as _, ToU64 as _, ToUsize as _}; +pub use crate::helpers::{ + AccessKind, EvalContextExt as _, MaybeEnteredTraceSpan, ToU64 as _, ToUsize as _, +}; pub use crate::intrinsics::EvalContextExt as _; pub use crate::machine::{ AllocExtra, DynMachineCallback, FrameExtra, MachineCallback, MemoryKind, MiriInterpCx, From 2ee58dc31fe5f3f60b9ad56dd85900d02f70db4a Mon Sep 17 00:00:00 2001 From: Stypox Date: Mon, 7 Jul 2025 11:11:15 +0200 Subject: [PATCH 176/363] Add tracing calls to borrow tracker under the same name ... but the function name is specified in the arguments, see https://github.com/rust-lang/miri/pull/4452#discussion_r2204958019 --- src/tools/miri/src/borrow_tracker/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index 36c61053a320..ec6c2c60ca9c 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -260,6 +260,7 @@ impl GlobalStateInner { kind: MemoryKind, machine: &MiriMachine<'_>, ) -> AllocState { + let _span = enter_trace_span!(borrow_tracker::new_allocation, ?id, ?alloc_size, ?kind); match self.borrow_tracker_method { BorrowTrackerMethod::StackedBorrows => AllocState::StackedBorrows(Box::new(RefCell::new(Stacks::new_allocation( @@ -280,6 +281,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { kind: RetagKind, val: &ImmTy<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx>> { + let _span = enter_trace_span!(borrow_tracker::retag_ptr_value, ?kind, ?val.layout); let this = self.eval_context_mut(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { @@ -293,6 +295,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { kind: RetagKind, place: &PlaceTy<'tcx>, ) -> InterpResult<'tcx> { + let _span = enter_trace_span!(borrow_tracker::retag_place_contents, ?kind, ?place); let this = self.eval_context_mut(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { @@ -302,6 +305,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } fn protect_place(&mut self, place: &MPlaceTy<'tcx>) -> InterpResult<'tcx, MPlaceTy<'tcx>> { + let _span = enter_trace_span!(borrow_tracker::protect_place, ?place); let this = self.eval_context_mut(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { @@ -311,6 +315,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } fn expose_tag(&self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> { + let _span = + enter_trace_span!(borrow_tracker::expose_tag, alloc_id = alloc_id.0, tag = tag.0); let this = self.eval_context_ref(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { @@ -354,6 +360,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &self, frame: &Frame<'tcx, Provenance, FrameExtra<'tcx>>, ) -> InterpResult<'tcx> { + let _span = enter_trace_span!(borrow_tracker::on_stack_pop); let this = self.eval_context_ref(); let borrow_tracker = this.machine.borrow_tracker.as_ref().unwrap(); // The body of this loop needs `borrow_tracker` immutably @@ -431,6 +438,7 @@ impl AllocState { range: AllocRange, machine: &MiriMachine<'tcx>, ) -> InterpResult<'tcx> { + let _span = enter_trace_span!(borrow_tracker::before_memory_read, alloc_id = alloc_id.0); match self { AllocState::StackedBorrows(sb) => sb.borrow_mut().before_memory_read(alloc_id, prov_extra, range, machine), @@ -452,6 +460,7 @@ impl AllocState { range: AllocRange, machine: &MiriMachine<'tcx>, ) -> InterpResult<'tcx> { + let _span = enter_trace_span!(borrow_tracker::before_memory_write, alloc_id = alloc_id.0); match self { AllocState::StackedBorrows(sb) => sb.get_mut().before_memory_write(alloc_id, prov_extra, range, machine), @@ -473,6 +482,8 @@ impl AllocState { size: Size, machine: &MiriMachine<'tcx>, ) -> InterpResult<'tcx> { + let _span = + enter_trace_span!(borrow_tracker::before_memory_deallocation, alloc_id = alloc_id.0); match self { AllocState::StackedBorrows(sb) => sb.get_mut().before_memory_deallocation(alloc_id, prov_extra, size, machine), @@ -482,6 +493,7 @@ impl AllocState { } pub fn remove_unreachable_tags(&self, tags: &FxHashSet) { + let _span = enter_trace_span!(borrow_tracker::remove_unreachable_tags); match self { AllocState::StackedBorrows(sb) => sb.borrow_mut().remove_unreachable_tags(tags), AllocState::TreeBorrows(tb) => tb.borrow_mut().remove_unreachable_tags(tags), @@ -496,6 +508,11 @@ impl AllocState { tag: BorTag, alloc_id: AllocId, // diagnostics ) -> InterpResult<'tcx> { + let _span = enter_trace_span!( + borrow_tracker::release_protector, + alloc_id = alloc_id.0, + tag = tag.0 + ); match self { AllocState::StackedBorrows(_sb) => interp_ok(()), AllocState::TreeBorrows(tb) => @@ -506,6 +523,7 @@ impl AllocState { impl VisitProvenance for AllocState { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + let _span = enter_trace_span!(borrow_tracker::visit_provenance); match self { AllocState::StackedBorrows(sb) => sb.visit_provenance(visit), AllocState::TreeBorrows(tb) => tb.visit_provenance(visit), From 132a47e72316b60e99c3e5fefb9c3a06641138e4 Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Tue, 15 Jul 2025 12:28:15 +0000 Subject: [PATCH 177/363] Correct which exploit mitigations are enabled by default --- src/doc/rustc/src/exploit-mitigations.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md index f8bafe032140..c80d7d8743cd 100644 --- a/src/doc/rustc/src/exploit-mitigations.md +++ b/src/doc/rustc/src/exploit-mitigations.md @@ -54,17 +54,17 @@ Summary of exploit mitigations supported by the Rust compiler when building programs for the Linux operating system on the AMD64 architecture and equivalent. -| Exploit mitigation | Supported and enabled by default | Since | -| - | - | - | -| Position-independent executable | Yes | 0.12.0 (2014-10-09) | -| Integer overflow checks | Yes (enabled when debug assertions are enabled, and disabled when debug assertions are disabled) | 1.1.0 (2015-06-25) | -| Non-executable memory regions | Yes | 1.8.0 (2016-04-14) | -| Stack clashing protection | Yes | 1.20.0 (2017-08-31) | -| Read-only relocations and immediate binding | Yes | 1.21.0 (2017-10-12) | -| Heap corruption protection | Yes | 1.32.0 (2019-01-17) (via operating system default or specified allocator) | -| Stack smashing protection | Yes | Nightly | -| Forward-edge control flow protection | Yes | Nightly | -| Backward-edge control flow protection (e.g., shadow and safe stack) | Yes | Nightly | +| Exploit mitigation | Supported | Enabled by default | Since | +| - | - | - | - | +| Position-independent executable | Yes | Yes | 0.12.0 (2014-10-09) | +| Integer overflow checks | Yes | (enabled when debug assertions are enabled, and disabled when debug assertions are disabled) | 1.1.0 (2015-06-25) | +| Non-executable memory regions | Yes | Yes | 1.8.0 (2016-04-14) | +| Stack clashing protection | Yes | Yes | 1.20.0 (2017-08-31) | +| Read-only relocations and immediate binding | Yes | Yes | 1.21.0 (2017-10-12) | +| Heap corruption protection | Yes | Yes | 1.32.0 (2019-01-17) (via operating system default or specified allocator) | +| Stack smashing protection | Yes | No, `-Z stack-protector` | Nightly | +| Forward-edge control flow protection | Yes | No, `-Z sanitizer=cfi` | Nightly | +| Backward-edge control flow protection (e.g., shadow and safe stack) | Yes | No, `-Z sanitizer=shadow-call-stack,safestack` | Nightly | [^all-targets]: See for a list of targets and their default options. From 14f47009cc5b02cd8c28ca2cc9c1fd58aeeef25b Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 15 Jul 2025 14:57:51 +0200 Subject: [PATCH 178/363] Add InterpCx::fn_abi_of_instance/_fn_ptr with tracing, shadowing FnAbiOf --- .../rustc_const_eval/src/interpret/call.rs | 2 +- .../src/interpret/eval_context.rs | 55 +++++++++++++------ .../rustc_const_eval/src/interpret/step.rs | 1 - src/tools/miri/src/helpers.rs | 2 +- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index ad3e02580f33..1503f3bcd990 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -6,7 +6,7 @@ use std::borrow::Cow; use either::{Left, Right}; use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx}; use rustc_hir::def_id::DefId; -use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, TyAndLayout}; +use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::sym; diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 41fc8d47cd36..11e7706fe605 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -7,8 +7,8 @@ use rustc_hir::def_id::DefId; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ - self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, - TyAndLayout, + self, FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, + LayoutOfHelpers, TyAndLayout, }; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance}; use rustc_middle::{mir, span_bug}; @@ -92,20 +92,6 @@ impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> { } } -impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { - /// This inherent method takes priority over the trait method with the same name in LayoutOf, - /// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span. - /// See [LayoutOf::layout_of] for the original documentation. - #[inline(always)] - pub fn layout_of( - &self, - ty: Ty<'tcx>, - ) -> as LayoutOfHelpers<'tcx>>::LayoutOfResult { - let _span = enter_trace_span!(M, "InterpCx::layout_of", "ty = {:?}", ty.kind()); - LayoutOf::layout_of(self, ty) - } -} - impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpErrorKind<'tcx>>; @@ -121,6 +107,43 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { } } +impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { + /// This inherent method takes priority over the trait method with the same name in LayoutOf, + /// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span. + /// See [LayoutOf::layout_of] for the original documentation. + #[inline(always)] + pub fn layout_of(&self, ty: Ty<'tcx>) -> >::LayoutOfResult { + let _span = enter_trace_span!(M, "InterpCx::layout_of", ty = ?ty.kind()); + LayoutOf::layout_of(self, ty) + } + + /// This inherent method takes priority over the trait method with the same name in FnAbiOf, + /// and allows wrapping the actual [FnAbiOf::fn_abi_of_fn_ptr] with a tracing span. + /// See [FnAbiOf::fn_abi_of_fn_ptr] for the original documentation. + #[inline(always)] + pub fn fn_abi_of_fn_ptr( + &self, + sig: ty::PolyFnSig<'tcx>, + extra_args: &'tcx ty::List>, + ) -> >::FnAbiOfResult { + let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_fn_ptr", ?sig, ?extra_args); + FnAbiOf::fn_abi_of_fn_ptr(self, sig, extra_args) + } + + /// This inherent method takes priority over the trait method with the same name in FnAbiOf, + /// and allows wrapping the actual [FnAbiOf::fn_abi_of_instance] with a tracing span. + /// See [FnAbiOf::fn_abi_of_instance] for the original documentation. + #[inline(always)] + pub fn fn_abi_of_instance( + &self, + instance: ty::Instance<'tcx>, + extra_args: &'tcx ty::List>, + ) -> >::FnAbiOfResult { + let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_instance", ?instance, ?extra_args); + FnAbiOf::fn_abi_of_instance(self, instance, extra_args) + } +} + /// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value. /// This test should be symmetric, as it is primarily about layout compatibility. pub(super) fn mir_assign_valid_types<'tcx>( diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 833fcc388179..629dcc3523ca 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -5,7 +5,6 @@ use either::Either; use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_index::IndexSlice; -use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::source_map::Spanned; diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index c150dc16b072..f2283f0902b0 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -13,7 +13,7 @@ use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::ExportedSymbol; -use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, MaybeResult, TyAndLayout}; +use rustc_middle::ty::layout::{LayoutOf, MaybeResult, TyAndLayout}; use rustc_middle::ty::{self, Binder, FloatTy, FnSig, IntTy, Ty, TyCtxt, UintTy}; use rustc_session::config::CrateType; use rustc_span::{Span, Symbol}; From 4a77a62e5611890dd275e17de0fb1694e4ff9a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Ml=C3=A1dek?= Date: Tue, 15 Jul 2025 15:26:18 +0200 Subject: [PATCH 179/363] rustc_resolve: rename `check_hidden_glob_reexports` to `lint_reexports` --- compiler/rustc_resolve/src/imports.rs | 5 +---- compiler/rustc_resolve/src/lib.rs | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 40c63a3edf3c..b2f6ee6563c5 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -634,10 +634,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - pub(crate) fn check_hidden_glob_reexports( - &mut self, - exported_ambiguities: FxHashSet>, - ) { + pub(crate) fn lint_reexports(&mut self, exported_ambiguities: FxHashSet>) { for module in self.arenas.local_modules().iter() { for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c2b3451d4a1d..87963295c2d8 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1775,9 +1775,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || { EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate) }); - self.tcx.sess.time("check_hidden_glob_reexports", || { - self.check_hidden_glob_reexports(exported_ambiguities) - }); + self.tcx.sess.time("lint_reexports", || self.lint_reexports(exported_ambiguities)); self.tcx .sess .time("finalize_macro_resolutions", || self.finalize_macro_resolutions(krate)); From 8b868fa534a8b660a5b8051a5c883d4c15c5b70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Ml=C3=A1dek?= Date: Sat, 12 Jul 2025 16:44:34 +0200 Subject: [PATCH 180/363] Implement resolver warnings about reexporting private dependencies --- compiler/rustc_lint/messages.ftl | 3 ++ compiler/rustc_lint/src/early/diagnostics.rs | 3 ++ compiler/rustc_lint/src/lints.rs | 8 ++++ compiler/rustc_lint_defs/src/lib.rs | 5 ++ compiler/rustc_resolve/src/imports.rs | 25 +++++++++- tests/ui/privacy/pub-priv-dep/pub-priv1.rs | 14 +++--- .../ui/privacy/pub-priv-dep/pub-priv1.stderr | 46 +++++++++++++++++-- 7 files changed, 90 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 8d9f2385b710..183db43ca765 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -744,6 +744,9 @@ lint_redundant_semicolons_suggestion = remove {$multiple_semicolons -> *[false] this semicolon } +lint_reexport_private_dependency = + {$kind} `{$name}` from private dependency '{$krate}' is re-exported + lint_remove_mut_from_pattern = remove `mut` from the parameter lint_removed_lint = lint `{$name}` has been removed: {$reason} diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 653559009ccc..f0fbf5bc81e9 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -351,6 +351,9 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } + BuiltinLintDiag::ReexportPrivateDependency { name, kind, krate } => { + lints::ReexportPrivateDependency { name, kind, krate }.decorate_lint(diag); + } BuiltinLintDiag::UnusedQualifications { removal_span } => { lints::UnusedQualifications { removal_span }.decorate_lint(diag); } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 21148833eaf7..fc3c10732598 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3080,6 +3080,14 @@ pub(crate) struct HiddenGlobReexports { pub namespace: String, } +#[derive(LintDiagnostic)] +#[diag(lint_reexport_private_dependency)] +pub(crate) struct ReexportPrivateDependency { + pub name: String, + pub kind: String, + pub krate: Symbol, +} + #[derive(LintDiagnostic)] #[diag(lint_unnecessary_qualification)] pub(crate) struct UnusedQualifications { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index cd402c9234fd..fe068d96b742 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -739,6 +739,11 @@ pub enum BuiltinLintDiag { /// The local binding that shadows the glob reexport. private_item_span: Span, }, + ReexportPrivateDependency { + name: String, + kind: String, + krate: Symbol, + }, UnusedQualifications { /// The span of the unnecessarily-qualified path to remove. removal_span: Span, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index b2f6ee6563c5..9e8eac75fa11 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -14,8 +14,8 @@ use rustc_middle::metadata::{ModChild, Reexport}; use rustc_middle::{span_bug, ty}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ - AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, - REDUNDANT_IMPORTS, UNUSED_IMPORTS, + AMBIGUOUS_GLOB_REEXPORTS, EXPORTED_PRIVATE_DEPENDENCIES, HIDDEN_GLOB_REEXPORTS, + PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, UNUSED_IMPORTS, }; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; @@ -696,6 +696,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } } + + if let NameBindingKind::Import { import, .. } = binding.kind + && let Some(binding_id) = import.id() + && let import_def_id = self.local_def_id(binding_id) + && self.effective_visibilities.is_exported(import_def_id) + && let Res::Def(reexported_kind, reexported_def_id) = binding.res() + && !matches!(reexported_kind, DefKind::Ctor(..)) + && !reexported_def_id.is_local() + && self.tcx.is_private_dep(reexported_def_id.krate) + { + self.lint_buffer.buffer_lint( + EXPORTED_PRIVATE_DEPENDENCIES, + binding_id, + binding.span, + BuiltinLintDiag::ReexportPrivateDependency { + kind: binding.res().descr().to_string(), + name: key.ident.name.to_string(), + krate: self.tcx.crate_name(reexported_def_id.krate), + }, + ); + } } } } diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs index 877029f3de37..192ca0db8bd4 100644 --- a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs +++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs @@ -9,10 +9,10 @@ #![deny(exported_private_dependencies)] // This crate is a private dependency -// FIXME: This should trigger. pub extern crate priv_dep; +//~^ ERROR crate `priv_dep` from private dependency 'priv_dep' is re-exported // This crate is a public dependency -extern crate pub_dep; +pub extern crate pub_dep; // This crate is a private dependency extern crate pm; @@ -91,16 +91,16 @@ pub struct AllowedPrivType { pub allowed: OtherType, } -// FIXME: This should trigger. pub use priv_dep::m; -// FIXME: This should trigger. +//~^ ERROR macro `m` from private dependency 'priv_dep' is re-exported pub use pm::fn_like; -// FIXME: This should trigger. +//~^ ERROR macro `fn_like` from private dependency 'pm' is re-exported pub use pm::PmDerive; -// FIXME: This should trigger. +//~^ ERROR macro `PmDerive` from private dependency 'pm' is re-exported pub use pm::pm_attr; +//~^ ERROR macro `pm_attr` from private dependency 'pm' is re-exported -// FIXME: This should trigger. pub use priv_dep::E::V1; +//~^ ERROR variant `V1` from private dependency 'priv_dep' is re-exported fn main() {} diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr index adfe13424cdf..9da47827be4b 100644 --- a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr +++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr @@ -1,8 +1,8 @@ -error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:29:5 +error: crate `priv_dep` from private dependency 'priv_dep' is re-exported + --> $DIR/pub-priv1.rs:12:1 | -LL | pub field: OtherType, - | ^^^^^^^^^^^^^^^^^^^^ +LL | pub extern crate priv_dep; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/pub-priv1.rs:9:9 @@ -10,6 +10,42 @@ note: the lint level is defined here LL | #![deny(exported_private_dependencies)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: macro `m` from private dependency 'priv_dep' is re-exported + --> $DIR/pub-priv1.rs:94:9 + | +LL | pub use priv_dep::m; + | ^^^^^^^^^^^ + +error: macro `fn_like` from private dependency 'pm' is re-exported + --> $DIR/pub-priv1.rs:96:9 + | +LL | pub use pm::fn_like; + | ^^^^^^^^^^^ + +error: derive macro `PmDerive` from private dependency 'pm' is re-exported + --> $DIR/pub-priv1.rs:98:9 + | +LL | pub use pm::PmDerive; + | ^^^^^^^^^^^^ + +error: attribute macro `pm_attr` from private dependency 'pm' is re-exported + --> $DIR/pub-priv1.rs:100:9 + | +LL | pub use pm::pm_attr; + | ^^^^^^^^^^^ + +error: variant `V1` from private dependency 'priv_dep' is re-exported + --> $DIR/pub-priv1.rs:103:9 + | +LL | pub use priv_dep::E::V1; + | ^^^^^^^^^^^^^^^ + +error: type `OtherType` from private dependency 'priv_dep' in public interface + --> $DIR/pub-priv1.rs:29:5 + | +LL | pub field: OtherType, + | ^^^^^^^^^^^^^^^^^^^^ + error: type `OtherType` from private dependency 'priv_dep' in public interface --> $DIR/pub-priv1.rs:36:5 | @@ -90,5 +126,5 @@ LL | impl PubTraitOnPrivate for OtherType {} | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 14 previous errors +error: aborting due to 20 previous errors From d627e252ae5f1d282f3c2ca6c0a0e24154552e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Ml=C3=A1dek?= Date: Sat, 12 Jul 2025 23:07:41 +0200 Subject: [PATCH 181/363] make `std_detect` public dependency of `std` --- library/std/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 62ece4b69619..ca2fb2f49a37 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -23,7 +23,7 @@ unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', ] } -std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = [ +std_detect = { path = "../stdarch/crates/std_detect", public = true, default-features = false, features = [ 'rustc-dep-of-std', ] } From fecd99881d545d6096d5489419f096cffe53b171 Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 14 Jul 2025 13:30:36 +0000 Subject: [PATCH 182/363] Setup unstable feature bound attribute --- .../src/attributes.rs | 3 ++ .../src/attributes/allow_unstable.rs | 20 +++++++++ compiler/rustc_passes/messages.ftl | 4 ++ compiler/rustc_passes/src/check_attr.rs | 44 +++++++++++++++++++ compiler/rustc_passes/src/errors.rs | 9 ++++ .../unstable_inherent_method.rs | 23 ++++++++++ .../unstable_inherent_method.stderr | 20 +++++++++ 7 files changed, 123 insertions(+) create mode 100644 tests/ui/unstable-feature-bound/unstable_inherent_method.rs create mode 100644 tests/ui/unstable-feature-bound/unstable_inherent_method.stderr diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 995ac514d8d6..5f38be346edd 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -417,6 +417,9 @@ pub enum AttributeKind { /// Represents `#[rustc_unsafe_specialization_marker]`. UnsafeSpecializationMarker(Span), + /// Represents `#[unstable_feature_bound]`. + UnstableFeatureBound(ThinVec<(Symbol, Span)>), + /// Represents `#[used]` Used { used_by: UsedBy, span: Span }, // tidy-alphabetical-end diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 1c51c3eee4ef..a6bd2306ec50 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -27,6 +27,26 @@ impl CombineAttributeParser for AllowInternalUnstableParser { } } +pub(crate) struct UnstableFeatureBoundParser; +impl CombineAttributeParser for UnstableFeatureBoundParser { + const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound]; + type Item = (Symbol, Span); + const CONVERT: ConvertFn = |items, _| AttributeKind::UnstableFeatureBound(items); + const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ..."); + + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator { + if !cx.features().staged_api() { + cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span }); + } + parse_unstable(cx, args, >::PATH[0]) + .into_iter() + .zip(iter::repeat(cx.attr_span)) + } +} + pub(crate) struct AllowConstFnUnstableParser; impl CombineAttributeParser for AllowConstFnUnstableParser { const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable]; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 3418d997b834..500b4279588a 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -667,6 +667,10 @@ passes_rustc_std_internal_symbol = attribute should be applied to functions or statics .label = not a function or static +passes_rustc_unstable_feature_bound = + attribute should be applied to `impl` or free function outside of any `impl` or trait + .label = not an `impl` or free function + passes_should_be_applied_to_fn = attribute should be applied to a function definition .label = {$on_crate -> diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 820255afe274..89000ab2619a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -247,6 +247,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::FfiPure(attr_span)) => { self.check_ffi_pure(attr_span, attrs, target) } + Attribute::Parsed(AttributeKind::UnstableFeatureBound(syms)) => { + self.check_unstable_feature_bound(syms.first().unwrap().1, span, target) + } Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -2267,6 +2270,47 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + fn check_unstable_feature_bound(&self, attr_span: Span, span: Span, target: Target) { + match target { + // FIXME(staged_api): There's no reason we can't support more targets here. We're just + // being conservative to begin with. + Target::Fn | Target::Impl => {} + Target::ExternCrate + | Target::Use + | Target::Static + | Target::Const + | Target::Closure + | Target::Mod + | Target::ForeignMod + | Target::GlobalAsm + | Target::TyAlias + | Target::Enum + | Target::Variant + | Target::Struct + | Target::Field + | Target::Union + | Target::Trait + | Target::TraitAlias + | Target::Expression + | Target::Statement + | Target::Arm + | Target::AssocConst + | Target::Method(_) + | Target::AssocTy + | Target::ForeignFn + | Target::ForeignStatic + | Target::ForeignTy + | Target::GenericParam(_) + | Target::MacroDef + | Target::Param + | Target::PatField + | Target::ExprField + | Target::WherePredicate => { + self.tcx.dcx().emit_err(errors::RustcUnstableFeatureBound { attr_span, span }); + } + } + } + fn check_rustc_std_internal_symbol(&self, attr_span: Span, span: Span, target: Target) { match target { Target::Fn | Target::Static | Target::ForeignFn | Target::ForeignStatic => {} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 093a2b38804f..37330c0ed6eb 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -686,6 +686,15 @@ pub(crate) struct RustcAllowConstFnUnstable { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes_rustc_unstable_feature_bound)] +pub(crate) struct RustcUnstableFeatureBound { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(passes_rustc_std_internal_symbol)] pub(crate) struct RustcStdInternalSymbol { diff --git a/tests/ui/unstable-feature-bound/unstable_inherent_method.rs b/tests/ui/unstable-feature-bound/unstable_inherent_method.rs new file mode 100644 index 000000000000..5f3095430a80 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_inherent_method.rs @@ -0,0 +1,23 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.1.1" )] + +/// FIXME(tiif): we haven't allowed marking trait and impl method as +/// unstable yet, but it should be possible. + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Trait { + #[unstable(feature = "feat", issue = "none" )] + #[unstable_feature_bound(foo)] + //~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait + fn foo(); +} + +#[stable(feature = "a", since = "1.1.1" )] +impl Trait for u8 { + #[unstable_feature_bound(foo)] + //~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr new file mode 100644 index 000000000000..fa1c39db259a --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr @@ -0,0 +1,20 @@ +error: attribute should be applied to `impl` or free function outside of any `impl` or trait + --> $DIR/unstable_inherent_method.rs:11:5 + | +LL | #[unstable_feature_bound(foo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn foo(); + | --------- not an `impl` or free function + +error: attribute should be applied to `impl` or free function outside of any `impl` or trait + --> $DIR/unstable_inherent_method.rs:18:5 + | +LL | #[unstable_feature_bound(foo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn foo() {} + | ----------- not an `impl` or free function + +error: aborting due to 2 previous errors + From 2586185831d318fda4de40b9fcc7c2737351292a Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 14 Jul 2025 13:31:30 +0000 Subject: [PATCH 183/363] Lower the UnstableFeatureBound predicate to UnstableFeature predicate --- .../src/collect/predicates_of.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index a93e58b101fe..60ccc484e002 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1,6 +1,7 @@ use std::assert_matches::assert_matches; use hir::Node; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -333,6 +334,19 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen predicates.extend(const_evaluatable_predicates_of(tcx, def_id, &predicates)); } + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + // FIXME(staged_api): We might want to look at the normal stability attributes too but + // first we would need a way to let std/core use APIs with unstable feature bounds from + // within stable APIs. + let allow_unstable_feature_attr = + find_attr!(attrs, AttributeKind::UnstableFeatureBound(i) => i) + .map(|i| i.as_slice()) + .unwrap_or_default(); + + for (feat_name, span) in allow_unstable_feature_attr { + predicates.insert((ty::ClauseKind::UnstableFeature(*feat_name).upcast(tcx), *span)); + } + let mut predicates: Vec<_> = predicates.into_iter().collect(); // Subtle: before we store the predicates into the tcx, we From 1e5c7b28772bb99b8af4ac350aaabbb28168dc99 Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 14 Jul 2025 13:35:06 +0000 Subject: [PATCH 184/363] Add the core logic in old and new solvers --- compiler/rustc_middle/src/ty/context.rs | 7 ++++ .../src/solve/eval_ctxt/mod.rs | 12 ++++++ .../rustc_next_trait_solver/src/solve/mod.rs | 14 +++++++ .../src/traits/fulfill.rs | 11 ++++- .../src/traits/select/mod.rs | 10 ++++- compiler/rustc_type_ir/src/infer_ctxt.rs | 42 +++++++++++++++++++ compiler/rustc_type_ir/src/inherent.rs | 2 + 7 files changed, 96 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 98b2ce01d89b..290213cab5e6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -833,6 +833,13 @@ impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_featu fn associated_const_equality(self) -> bool { self.associated_const_equality() } + + fn feature_bound_holds_in_crate(self, symbol: Symbol) -> bool { + // We don't consider feature bounds to hold in the crate when `staged_api` feature is + // enabled, even if it is enabled through `#[feature]`. + // This is to prevent accidentally leaking unstable APIs to stable. + !self.staged_api() && self.enabled(symbol) + } } impl<'tcx> rustc_type_ir::inherent::Span> for Span { diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index b42587618b57..ce9b794d40d3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -22,6 +22,7 @@ use crate::delegate::SolverDelegate; use crate::placeholder::BoundVarReplacer; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; +use crate::solve::ty::may_use_unstable_feature; use crate::solve::{ CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalEvaluationKind, GoalSource, GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput, @@ -550,6 +551,9 @@ where ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) }) } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + self.compute_unstable_feature_goal(param_env, symbol) + } ty::PredicateKind::Subtype(predicate) => { self.compute_subtype_goal(Goal { param_env, predicate }) } @@ -1177,6 +1181,14 @@ where ) -> T { BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, t).0 } + + pub(super) fn may_use_unstable_feature( + &self, + param_env: I::ParamEnv, + symbol: I::Symbol, + ) -> bool { + may_use_unstable_feature(&**self.delegate, param_env, symbol) + } } /// Eagerly replace aliases with inference variables, emitting `AliasRelate` diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index e68ea22c7a27..5ea3f0d10617 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -148,6 +148,20 @@ where } } + fn compute_unstable_feature_goal( + &mut self, + param_env: ::ParamEnv, + symbol: ::Symbol, + ) -> QueryResult { + if self.may_use_unstable_feature(param_env, symbol) { + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } else { + self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe( + MaybeCause::Ambiguity, + )) + } + } + #[instrument(level = "trace", skip(self))] fn compute_const_evaluatable_goal( &mut self, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 64a51e0550ba..3e13e5042667 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -11,7 +11,9 @@ use rustc_infer::traits::{ use rustc_middle::bug; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode}; +use rustc_middle::ty::{ + self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode, may_use_unstable_feature, +}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, debug_span, instrument}; @@ -767,6 +769,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + if may_use_unstable_feature(self.selcx.infcx, obligation.param_env, symbol) { + ProcessResult::Changed(Default::default()) + } else { + ProcessResult::Unchanged + } + } }, } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2e65750db25d..10bcf861d35b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -28,7 +28,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, SizedTraitKind, Ty, TyCtxt, - TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, + TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, may_use_unstable_feature, }; use rustc_span::{Symbol, sym}; use tracing::{debug, instrument, trace}; @@ -832,6 +832,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + if may_use_unstable_feature(self.infcx, obligation.param_env, symbol) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToAmbig) + } + } + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { match const_evaluatable::is_const_evaluatable( self.infcx, diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 6c77a90250a4..b558d0164483 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -285,3 +285,45 @@ pub trait InferCtxtLike: Sized { fn reset_opaque_types(&self); } + +pub fn may_use_unstable_feature<'a, I: Interner, Infcx>( + infcx: &'a Infcx, + param_env: I::ParamEnv, + symbol: I::Symbol, +) -> bool +where + Infcx: InferCtxtLike, +{ + // Iterate through all goals in param_env to find the one that has the same symbol. + for pred in param_env.caller_bounds().iter() { + if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() { + if sym == symbol { + return true; + } + } + } + + // During codegen we must assume that all feature bounds hold as we may be + // monomorphizing a body from an upstream crate which had an unstable feature + // enabled that we do not. + // + // Coherence should already report overlap errors involving unstable impls + // as the affected code would otherwise break when stabilizing this feature. + // It is also easily possible to accidentally cause unsoundness this way as + // we have to always enable unstable impls during codegen. + // + // Return ambiguity can also prevent people from writing code which depends on inference guidance + // that might no longer work after the impl is stabilised, + // tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs is one of the example. + // + // Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled + // if we are in std/core even if there is a corresponding `feature` attribute on the crate. + + if (infcx.typing_mode() == TypingMode::PostAnalysis) + || infcx.cx().features().feature_bound_holds_in_crate(symbol) + { + return true; + } else { + return false; + } +} diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 2754d40fd36c..0e307e15d5b4 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -630,6 +630,8 @@ pub trait Features: Copy { fn coroutine_clone(self) -> bool; fn associated_const_equality(self) -> bool; + + fn feature_bound_holds_in_crate(self, symbol: I::Symbol) -> bool; } pub trait DefId: Copy + Debug + Hash + Eq + TypeFoldable { From ab29256b96660ffd01ab0257588cb6cbd08355a8 Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 14 Jul 2025 13:36:19 +0000 Subject: [PATCH 185/363] Make stability attribute not to error when unstable feature bound is in effect --- compiler/rustc_passes/src/stability.rs | 32 +++++++++++++++-- .../unstable-feature-bound-no-effect.rs | 35 +++++++++++++++++++ .../unstable-feature-bound-no-effect.stderr | 11 ++++++ 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.rs create mode 100644 tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.stderr diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index adda94fda8f0..e5530d526866 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -802,12 +802,28 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability); + let unstable_feature_stab = + find_attr!(attrs, AttributeKind::UnstableFeatureBound(i) => i) + .map(|i| i.as_slice()) + .unwrap_or_default(); + // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because // it will have no effect. // See: https://github.com/rust-lang/rust/issues/55436 + // + // The exception is when there are both #[unstable_feature_bound(..)] and + // #![unstable(feature = "..", issue = "..")] that have the same symbol because + // that can effectively mark an impl as unstable. + // + // For example: + // ``` + // #[unstable_feature_bound(feat_foo)] + // #[unstable(feature = "feat_foo", issue = "none")] + // impl Foo for Bar {} + // ``` if let Some(( - Stability { level: attrs::StabilityLevel::Unstable { .. }, .. }, + Stability { level: attrs::StabilityLevel::Unstable { .. }, feature }, span, )) = stab { @@ -815,9 +831,21 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { c.visit_ty_unambig(self_ty); c.visit_trait_ref(t); + // Skip the lint if the impl is marked as unstable using + // #[unstable_feature_bound(..)] + let mut unstable_feature_bound_in_effect = false; + for (unstable_bound_feat_name, _) in unstable_feature_stab { + if *unstable_bound_feat_name == feature { + unstable_feature_bound_in_effect = true; + } + } + // do not lint when the trait isn't resolved, since resolution error should // be fixed first - if t.path.res != Res::Err && c.fully_stable { + if t.path.res != Res::Err + && c.fully_stable + && !unstable_feature_bound_in_effect + { self.tcx.emit_node_span_lint( INEFFECTIVE_UNSTABLE_TRAIT_IMPL, item.hir_id(), diff --git a/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.rs b/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.rs new file mode 100644 index 000000000000..99501893ae0a --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.rs @@ -0,0 +1,35 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![stable(feature = "a", since = "1.1.1" )] + +/// If #[unstable(..)] and #[unstable_feature_name(..)] have the same feature name, +/// the error should not be thrown as it can effectively mark an impl as unstable. +/// +/// If the feature name in #[feature] does not exist in #[unstable_feature_bound(..)] +/// an error should still be thrown because that feature will not be unstable. + +#[stable(feature = "a", since = "1.1.1")] +trait Moo {} +#[stable(feature = "a", since = "1.1.1")] +trait Foo {} +#[stable(feature = "a", since = "1.1.1")] +trait Boo {} +#[stable(feature = "a", since = "1.1.1")] +pub struct Bar; + + +#[unstable(feature = "feat_moo", issue = "none")] +#[unstable_feature_bound(feat_foo)] //~^ ERROR: an `#[unstable]` annotation here has no effect +impl Moo for Bar {} + +#[unstable(feature = "feat_foo", issue = "none")] +#[unstable_feature_bound(feat_foo)] +impl Foo for Bar {} + + +#[unstable(feature = "feat_foo", issue = "none")] +#[unstable_feature_bound(feat_foo, feat_bar)] +impl Boo for Bar {} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.stderr b/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.stderr new file mode 100644 index 000000000000..4c8af2bbe56f --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.stderr @@ -0,0 +1,11 @@ +error: an `#[unstable]` annotation here has no effect + --> $DIR/unstable-feature-bound-no-effect.rs:22:1 + | +LL | #[unstable(feature = "feat_moo", issue = "none")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #55436 for more information + = note: `#[deny(ineffective_unstable_trait_impl)]` on by default + +error: aborting due to 1 previous error + From dd067a689a05e50b80206536de22a2400277a7f8 Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 14 Jul 2025 13:37:51 +0000 Subject: [PATCH 186/363] Lint against having both #[unstable_feature_bound] and #[stable] on the same item --- compiler/rustc_attr_parsing/messages.ftl | 3 +++ .../rustc_attr_parsing/src/attributes/stability.rs | 10 ++++++++++ .../rustc_attr_parsing/src/session_diagnostics.rs | 8 ++++++++ ...nstable_feature_bound_incompatible_stability.rs | 14 ++++++++++++++ ...ble_feature_bound_incompatible_stability.stderr | 10 ++++++++++ 5 files changed, 45 insertions(+) create mode 100644 tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs create mode 100644 tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 8d0ead63a8d8..35ff48cb5f24 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -136,6 +136,9 @@ attr_parsing_unrecognized_repr_hint = attr_parsing_unstable_cfg_target_compact = compact `cfg(target(..))` is experimental and subject to change +attr_parsing_unstable_feature_bound_incompatible_stability = Item annotated with `#[unstable_feature_bound]` should not be stable + .help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` + attr_parsing_unsupported_literal_cfg_boolean = literal in `cfg` predicate value must be a boolean attr_parsing_unsupported_literal_cfg_string = diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 6bccd0042a80..8f405e5aad97 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -98,6 +98,16 @@ impl AttributeParser for StabilityParser { } } + if let Some((Stability { level: StabilityLevel::Stable { .. }, .. }, _)) = self.stability { + for other_attr in cx.all_attrs { + if other_attr.word_is(sym::unstable_feature_bound) { + cx.emit_err(session_diagnostics::UnstableFeatureBoundIncompatibleStability { + span: cx.target_span, + }); + } + } + } + let (stability, span) = self.stability?; Some(AttributeKind::Stability { stability, span }) diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 97bf3d1c5495..5b0bf0e6662f 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -503,6 +503,14 @@ pub(crate) struct UnrecognizedReprHint { pub span: Span, } +#[derive(Diagnostic)] +#[diag(attr_parsing_unstable_feature_bound_incompatible_stability)] +#[help] +pub(crate) struct UnstableFeatureBoundIncompatibleStability { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(attr_parsing_naked_functions_incompatible_attribute, code = E0736)] pub(crate) struct NakedFunctionIncompatibleAttribute { diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs new file mode 100644 index 000000000000..1a9652c10230 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs @@ -0,0 +1,14 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![stable(feature = "a", since = "1.1.1" )] + +// Lint against the usage of both #[unstable_feature_bound] and #[stable] on the +// same item. + +#[stable(feature = "a", since = "1.1.1")] +#[unstable_feature_bound(feat_bar)] +fn bar() {} +//~^ ERROR Item annotated with `#[unstable_feature_bound]` should not be stable + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr new file mode 100644 index 000000000000..9cb6a181beff --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr @@ -0,0 +1,10 @@ +error: Item annotated with `#[unstable_feature_bound]` should not be stable + --> $DIR/unstable_feature_bound_incompatible_stability.rs:11:1 + | +LL | fn bar() {} + | ^^^^^^^^^^^ + | + = help: If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` + +error: aborting due to 1 previous error + From 7356ff7517f4d95583f8fd6d631441893c87dd3f Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 14 Jul 2025 13:38:19 +0000 Subject: [PATCH 187/363] Implement other logics --- .../src/encode_cross_crate.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 5 ++- compiler/rustc_feature/src/builtin_attrs.rs | 4 ++ .../rustc_hir_analysis/src/check/wfcheck.rs | 14 ++++--- .../src/collect/predicates_of.rs | 2 + .../src/impl_wf_check/min_specialization.rs | 1 + .../src/outlives/explicit.rs | 1 + .../src/fn_ctxt/inspect_obligations.rs | 1 + compiler/rustc_hir_typeck/src/method/probe.rs | 1 + compiler/rustc_lint/src/builtin.rs | 3 +- compiler/rustc_middle/src/ty/context.rs | 1 + compiler/rustc_middle/src/ty/predicate.rs | 3 ++ compiler/rustc_middle/src/ty/print/pretty.rs | 1 + compiler/rustc_privacy/src/lib.rs | 1 + .../src/unstable/convert/stable/ty.rs | 3 ++ compiler/rustc_session/src/parse.rs | 40 +++++++++++++++++++ compiler/rustc_span/src/symbol.rs | 1 + .../src/error_reporting/traits/ambiguity.rs | 25 ++++++++++++ .../traits/fulfillment_errors.rs | 2 + .../src/traits/auto_trait.rs | 1 + .../src/traits/dyn_compatibility.rs | 2 + .../src/traits/fulfill.rs | 3 ++ .../query/type_op/implied_outlives_bounds.rs | 1 + .../rustc_trait_selection/src/traits/util.rs | 1 + .../rustc_trait_selection/src/traits/wf.rs | 2 + .../src/normalize_erasing_regions.rs | 1 + compiler/rustc_type_ir/src/elaborate.rs | 3 ++ compiler/rustc_type_ir/src/flags.rs | 3 +- compiler/rustc_type_ir/src/interner.rs | 1 + compiler/rustc_type_ir/src/predicate_kind.rs | 10 +++++ src/librustdoc/clean/mod.rs | 3 +- 31 files changed, 132 insertions(+), 9 deletions(-) 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 494b570c86c7..84c3bd1eb614 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -70,6 +70,7 @@ impl AttributeKind { TrackCaller(..) => Yes, TypeConst(..) => Yes, UnsafeSpecializationMarker(..) => No, + UnstableFeatureBound(..) => No, Used { .. } => No, // tidy-alphabetical-end } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 1f6675b4c5a8..390246239ed1 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -13,7 +13,9 @@ use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirI use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; -use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; +use crate::attributes::allow_unstable::{ + AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser, +}; use crate::attributes::codegen_attrs::{ ColdParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser, @@ -133,6 +135,7 @@ attribute_parsers!( Combine, Combine, Combine, + Combine, // tidy-alphabetical-end // tidy-alphabetical-start diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 7d9915d7f68b..e2827f227abf 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -683,6 +683,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk, EncodeCrossCrate::Yes ), + ungated!( + unstable_feature_bound, Normal, template!(Word, List: "feat1, feat2, ..."), + DuplicatesOk, EncodeCrossCrate::No, + ), ungated!( rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk, EncodeCrossCrate::Yes diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 607028f4d9ae..14ec82ede1c5 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2212,12 +2212,16 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { let implied_obligations = traits::elaborate(tcx, predicates_with_span); for (pred, obligation_span) in implied_obligations { - // We lower empty bounds like `Vec:` as - // `WellFormed(Vec)`, which will later get checked by - // regular WF checking - if let ty::ClauseKind::WellFormed(..) = pred.kind().skip_binder() { - continue; + match pred.kind().skip_binder() { + // We lower empty bounds like `Vec:` as + // `WellFormed(Vec)`, which will later get checked by + // regular WF checking + ty::ClauseKind::WellFormed(..) + // Unstable feature goals cannot be proven in an empty environment so skip them + | ty::ClauseKind::UnstableFeature(..) => continue, + _ => {} } + // Match the existing behavior. if pred.is_global() && !pred.has_type_flags(TypeFlags::HAS_BINDER_VARS) { let pred = self.normalize(span, None, pred); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 60ccc484e002..af78130899e4 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -778,6 +778,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::ConstEvaluatable(_) => { bug!( "unexpected non-`Self` predicate when computing \ @@ -805,6 +806,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => { bug!( "unexpected non-`Self` predicate when computing \ diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 574d19a5aa5a..0043f0c71176 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -499,6 +499,7 @@ fn trait_specialization_kind<'tcx>( | ty::ClauseKind::ConstArgHasType(..) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(..) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => None, } } diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 2c1d443f9512..d3a57a4d8e5d 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -54,6 +54,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => {} } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index e4c62bf027bd..367e2b6b372a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -54,6 +54,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::Ambiguous => false, } } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 94c93e736274..3261327a9fda 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -921,6 +921,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => None, } }); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 255ff56f62b1..8244f0bed4c9 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1519,8 +1519,9 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { ClauseKind::TypeOutlives(..) | ClauseKind::RegionOutlives(..) => "lifetime", + ClauseKind::UnstableFeature(_) // `ConstArgHasType` is never global as `ct` is always a param - ClauseKind::ConstArgHasType(..) + | ClauseKind::ConstArgHasType(..) // Ignore projections, as they can only be global // if the trait bound is global | ClauseKind::Projection(..) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 290213cab5e6..915b062417f2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -137,6 +137,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type FnInputTys = &'tcx [Ty<'tcx>]; type ParamTy = ParamTy; type BoundTy = ty::BoundTy; + type Symbol = Symbol; type PlaceholderTy = ty::PlaceholderType; type ErrorGuaranteed = ErrorGuaranteed; diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index bc2ac42b6b1f..ec2224877a8a 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -131,6 +131,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) | PredicateKind::Clause(ClauseKind::Projection(_)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) | PredicateKind::DynCompatible(_) | PredicateKind::Subtype(_) | PredicateKind::Coerce(_) @@ -649,6 +650,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(ClauseKind::Projection(..)) | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) | PredicateKind::NormalizesTo(..) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) @@ -670,6 +672,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(ClauseKind::Trait(..)) | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) | PredicateKind::NormalizesTo(..) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 7c48a4b0885e..b857788b8b7e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3237,6 +3237,7 @@ define_print! { ty::ClauseKind::ConstEvaluatable(ct) => { p!("the constant `", print(ct), "` can be evaluated") } + ty::ClauseKind::UnstableFeature(symbol) => p!("unstable feature: ", write("`{}`", symbol)), } } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index ab2433234aa9..80c13e44d7d8 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -156,6 +156,7 @@ where } ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self), ty::ClauseKind::WellFormed(term) => term.visit_with(self), + ty::ClauseKind::UnstableFeature(_) => V::Result::output(), } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 75c297887875..6b226b8a24d1 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -764,6 +764,9 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> { ClauseKind::HostEffect(..) => { todo!() } + ClauseKind::UnstableFeature(_) => { + todo!() + } } } } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 0118cdb1fc27..ea7a524efe6d 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -205,6 +205,46 @@ pub fn add_feature_diagnostics_for_issue( } } +/// This is only used by unstable_feature_bound as it does not have issue number information for now. +/// This is basically the same as `feature_err_issue` +/// but without the feature issue note. If we can do a lookup for issue number from feature name, +/// then we should directly use `feature_err_issue` for ambiguity error of +/// #[unstable_feature_bound]. +#[track_caller] +pub fn feature_err_unstable_feature_bound( + sess: &Session, + feature: Symbol, + span: impl Into, + explain: impl Into, +) -> Diag<'_> { + 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() + } + } + + let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); + + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable + if sess.psess.unstable_features.is_nightly_build() { + err.subdiagnostic(FeatureDiagnosticHelp { feature }); + + if feature == sym::rustc_attrs { + // We're unlikely to stabilize something out of `rustc_attrs` + // without at least renaming it, so pointing out how old + // the compiler is will do little good. + } else if sess.opts.unstable_opts.ui_testing { + err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); + } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { + err.subdiagnostic(suggestion); + } + } + err +} + /// Info about a parsing session. pub struct ParseSess { dcx: DiagCtxt, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b12edf426c1..bd34055f8513 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2284,6 +2284,7 @@ symbols! { unsized_locals, unsized_tuple_coercion, unstable, + unstable_feature_bound, unstable_location_reason_default: "this crate is being loaded from the sysroot, an \ unstable location; did you mean to load this crate \ from crates.io via `Cargo.toml` instead?", 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 712e88300fff..98f67257fd13 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -12,6 +12,7 @@ use rustc_infer::traits::{ Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation, }; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _}; +use rustc_session::parse::feature_err_unstable_feature_bound; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use tracing::{debug, instrument}; @@ -611,6 +612,30 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) .with_span_label(span, format!("cannot normalize `{alias}`")) } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(sym)) => { + if let Some(e) = self.tainted_by_errors() { + return e; + } + + let mut err; + + if self.tcx.features().staged_api() { + err = self.dcx().struct_span_err( + span, + format!("unstable feature `{sym}` is used without being enabled."), + ); + + err.help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`")); + } else { + err = feature_err_unstable_feature_bound( + &self.tcx.sess, + sym, + span, + format!("use of unstable library feature `{sym}`"), + ); + } + err + } _ => { if let Some(e) = self.tainted_by_errors() { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index cd3e6c4bc543..1ac309da101f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -647,6 +647,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ty::PredicateKind::ConstEquate { .. } // Ambiguous predicates should never error | ty::PredicateKind::Ambiguous + // We never return Err when proving UnstableFeature goal. + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature{ .. }) | ty::PredicateKind::NormalizesTo { .. } | ty::PredicateKind::AliasRelate { .. } | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => { diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 3ae908ec16b8..759db1d18c01 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -800,6 +800,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // FIXME(generic_const_exprs): you can absolutely add this as a where clauses | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {} ty::PredicateKind::Ambiguous => return false, }; diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 9a4f3887bbb5..ea1eed957233 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -238,6 +238,7 @@ fn predicate_references_self<'tcx>( // FIXME(generic_const_exprs): this can mention `Self` | ty::ClauseKind::ConstEvaluatable(..) | ty::ClauseKind::HostEffect(..) + | ty::ClauseKind::UnstableFeature(_) => None, } } @@ -278,6 +279,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => false, }) } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 3e13e5042667..2b5a41ef5a71 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -406,6 +406,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::AliasRelate(..) => { bug!("AliasRelate is only used by the new solver") } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) => { + unreachable!("unexpected higher ranked `UnstableFeature` goal") + } }, Some(pred) => match pred { ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index e294f7839aac..7540cbe3fd1a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -110,6 +110,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::NormalizesTo(..) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::AliasRelate(..) => {} // We need to search through *all* WellFormed predicates diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 141454bfe375..25cd7787a349 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -80,6 +80,7 @@ pub fn expand_trait_aliases<'tcx>( | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => {} } } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index fed9f254cdf8..adce9850b594 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -197,6 +197,7 @@ pub fn clause_obligations<'tcx>( ty::ClauseKind::ConstEvaluatable(ct) => { wf.add_wf_preds_for_term(ct.into()); } + ty::ClauseKind::UnstableFeature(_) => {} } wf.normalize(infcx) @@ -1095,6 +1096,7 @@ pub fn object_region_bounds<'tcx>( | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::ConstEvaluatable(_) => None, } }) diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 68ff66bbce7c..c1b848a2e79d 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -57,6 +57,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool { | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::NormalizesTo(..) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 7ffcf7b5d965..380082487579 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -234,6 +234,9 @@ impl> Elaborator { ty::ClauseKind::ConstArgHasType(..) => { // Nothing to elaborate } + ty::ClauseKind::UnstableFeature(_) => { + // Nothing to elaborate + } } } } diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 37cc2baa402a..a231908f874c 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -401,7 +401,6 @@ impl FlagComputation { self.add_const(expected); self.add_const(found); } - ty::PredicateKind::Ambiguous => {} ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => { self.add_alias_term(alias); self.add_term(term); @@ -410,6 +409,8 @@ impl FlagComputation { self.add_term(t1); self.add_term(t2); } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_sym)) => {} + ty::PredicateKind::Ambiguous => {} } } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index dd3cf1fc1811..0ec326d21169 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -106,6 +106,7 @@ pub trait Interner: type ParamTy: ParamLike; type BoundTy: BoundVarLike; type PlaceholderTy: PlaceholderLike; + type Symbol: Copy + Hash + PartialEq + Eq + Debug; // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index 4e41fd16ffd7..8bc15ec4ff55 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -46,6 +46,13 @@ pub enum ClauseKind { /// corresponding trait clause; this just enforces the *constness* of that /// implementation. HostEffect(ty::HostEffectPredicate), + + /// Support marking impl as unstable. + UnstableFeature( + #[type_foldable(identity)] + #[type_visitable(ignore)] + I::Symbol, + ), } #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] @@ -134,6 +141,9 @@ impl fmt::Debug for ClauseKind { ClauseKind::ConstEvaluatable(ct) => { write!(f, "ConstEvaluatable({ct:?})") } + ClauseKind::UnstableFeature(feature_name) => { + write!(f, "UnstableFeature({feature_name:?})") + } } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e7a1f4d8397b..3df04091f163 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -390,7 +390,8 @@ pub(crate) fn clean_predicate<'tcx>( ty::ClauseKind::ConstEvaluatable(..) | ty::ClauseKind::WellFormed(..) | ty::ClauseKind::ConstArgHasType(..) - // FIXME(const_trait_impl): We can probably use this `HostEffect` pred to render `[const]`. + | ty::ClauseKind::UnstableFeature(..) + // FIXME(const_trait_impl): We can probably use this `HostEffect` pred to render `~const`. | ty::ClauseKind::HostEffect(_) => None, } } From 7dd28181e2243c3715efc7e0ce49848bfd256c86 Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 14 Jul 2025 13:38:36 +0000 Subject: [PATCH 188/363] Add tests --- .../auxiliary/unstable_feature.rs | 25 +++++++++++ .../auxiliary/unstable_impl_codegen_aux1.rs | 19 +++++++++ .../auxiliary/unstable_impl_codegen_aux2.rs | 13 ++++++ .../auxiliary/unstable_impl_coherence_aux.rs | 11 +++++ .../unstable_impl_method_selection_aux.rs | 20 +++++++++ .../unstable-feature-bound-two-error.rs | 12 ++++++ .../unstable-feature-bound-two-error.stderr | 13 ++++++ ...ature-cross-crate-exact-symbol.fail.stderr | 13 ++++++ ...stable-feature-cross-crate-exact-symbol.rs | 18 ++++++++ ...ble-feature-cross-crate-multiple-symbol.rs | 11 +++++ ...ture-cross-crate-require-bound.fail.stderr | 13 ++++++ ...table-feature-cross-crate-require-bound.rs | 14 +++++++ .../unstable-feature-exact-symbol.fail.stderr | 17 ++++++++ .../unstable-feature-exact-symbol.rs | 42 +++++++++++++++++++ .../unstable-impl-assoc-type.fail.stderr | 22 ++++++++++ .../unstable-impl-assoc-type.rs | 28 +++++++++++++ ...stable-impl-cannot-use-feature.fail.stderr | 17 ++++++++ .../unstable-impl-cannot-use-feature.rs | 30 +++++++++++++ .../unstable-impl-multiple-symbol.rs | 27 ++++++++++++ ...unstable_feature_bound_free_fn.fail.stderr | 17 ++++++++ .../unstable_feature_bound_free_fn.rs | 40 ++++++++++++++++++ .../unstable_feature_bound_multi_attr.rs | 36 ++++++++++++++++ .../unstable_feature_bound_multi_attr.stderr | 18 ++++++++ .../unstable_feature_bound_staged_api.rs | 13 ++++++ .../unstable_feature_bound_staged_api.stderr | 9 ++++ .../unstable_impl_codegen.rs | 13 ++++++ .../unstable_impl_coherence.disabled.stderr | 13 ++++++ .../unstable_impl_coherence.enabled.stderr | 13 ++++++ .../unstable_impl_coherence.rs | 17 ++++++++ .../unstable_impl_method_selection.rs | 15 +++++++ .../unstable_impl_method_selection.stderr | 14 +++++++ 31 files changed, 583 insertions(+) create mode 100644 tests/ui/unstable-feature-bound/auxiliary/unstable_feature.rs create mode 100644 tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux1.rs create mode 100644 tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux2.rs create mode 100644 tests/ui/unstable-feature-bound/auxiliary/unstable_impl_coherence_aux.rs create mode 100644 tests/ui/unstable-feature-bound/auxiliary/unstable_impl_method_selection_aux.rs create mode 100644 tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.rs create mode 100644 tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.stderr create mode 100644 tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.fail.stderr create mode 100644 tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.rs create mode 100644 tests/ui/unstable-feature-bound/unstable-feature-cross-crate-multiple-symbol.rs create mode 100644 tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.fail.stderr create mode 100644 tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.rs create mode 100644 tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.fail.stderr create mode 100644 tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.rs create mode 100644 tests/ui/unstable-feature-bound/unstable-impl-assoc-type.fail.stderr create mode 100644 tests/ui/unstable-feature-bound/unstable-impl-assoc-type.rs create mode 100644 tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.fail.stderr create mode 100644 tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.rs create mode 100644 tests/ui/unstable-feature-bound/unstable-impl-multiple-symbol.rs create mode 100644 tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.fail.stderr create mode 100644 tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.rs create mode 100644 tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.rs create mode 100644 tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.stderr create mode 100644 tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.rs create mode 100644 tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.stderr create mode 100644 tests/ui/unstable-feature-bound/unstable_impl_codegen.rs create mode 100644 tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr create mode 100644 tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr create mode 100644 tests/ui/unstable-feature-bound/unstable_impl_coherence.rs create mode 100644 tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs create mode 100644 tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_feature.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_feature.rs new file mode 100644 index 000000000000..3749deb76273 --- /dev/null +++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_feature.rs @@ -0,0 +1,25 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.1.1" )] + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Foo { + #[stable(feature = "a", since = "1.1.1" )] + fn foo(); +} +#[stable(feature = "a", since = "1.1.1" )] +pub struct Bar; +#[stable(feature = "a", since = "1.1.1" )] +pub struct Moo; + +#[unstable_feature_bound(feat_bar)] +#[unstable(feature = "feat_bar", issue = "none" )] +impl Foo for Bar { + fn foo() {} +} + +#[unstable_feature_bound(feat_moo)] +#[unstable(feature = "feat_moo", issue = "none" )] +impl Foo for Moo { + fn foo() {} +} diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux1.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux1.rs new file mode 100644 index 000000000000..8c0d14a1bab6 --- /dev/null +++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux1.rs @@ -0,0 +1,19 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.1.1" )] + +/// Aux crate for unstable impl codegen test. + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Trait { + #[stable(feature = "a", since = "1.1.1" )] + fn method(&self); +} + +#[unstable_feature_bound(foo)] +#[unstable(feature = "foo", issue = "none" )] +impl Trait for T { + fn method(&self) { + println!("hi"); + } +} diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux2.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux2.rs new file mode 100644 index 000000000000..1b0e2b2eec31 --- /dev/null +++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux2.rs @@ -0,0 +1,13 @@ +//@ aux-build:unstable_impl_codegen_aux1.rs +#![feature(foo)] + +extern crate unstable_impl_codegen_aux1 as aux; +use aux::Trait; + +/// Upstream crate for unstable impl codegen test +/// that depends on aux crate in +/// unstable_impl_codegen_aux1.rs + +pub fn foo(a: T) { + a.method(); +} diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_coherence_aux.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_coherence_aux.rs new file mode 100644 index 000000000000..2e0551012163 --- /dev/null +++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_coherence_aux.rs @@ -0,0 +1,11 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![stable(feature = "a", since = "1.1.1" )] + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Trait {} + +#[unstable_feature_bound(foo)] +#[unstable(feature = "foo", issue = "none" )] +impl Trait for T {} diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_method_selection_aux.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_method_selection_aux.rs new file mode 100644 index 000000000000..3a433007b5d2 --- /dev/null +++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_method_selection_aux.rs @@ -0,0 +1,20 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.1.1" )] + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Trait { + #[stable(feature = "a", since = "1.1.1" )] + fn foo(&self) {} +} + +#[stable(feature = "a", since = "1.1.1" )] +impl Trait for Vec { + fn foo(&self) {} +} + +#[unstable_feature_bound(bar)] +#[unstable(feature = "bar", issue = "none" )] +impl Trait for Vec { + fn foo(&self) {} +} diff --git a/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.rs b/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.rs new file mode 100644 index 000000000000..798c2d8562c0 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.rs @@ -0,0 +1,12 @@ +//@ aux-build:unstable_feature.rs +extern crate unstable_feature; +use unstable_feature::{Foo, Bar, Moo}; + +// FIXME: both `feat_bar` and `feat_moo` are needed to pass this test, +// but the diagnostic only will point out `feat_bar`. + +fn main() { + Bar::foo(); + //~^ ERROR: use of unstable library feature `feat_bar` [E0658] + Moo::foo(); +} diff --git a/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.stderr b/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.stderr new file mode 100644 index 000000000000..673d10ce2ad9 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `feat_bar` + --> $DIR/unstable-feature-bound-two-error.rs:9:5 + | +LL | Bar::foo(); + | ^^^ + | + = help: add `#![feature(feat_bar)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required for `Bar` to implement `Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.fail.stderr b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.fail.stderr new file mode 100644 index 000000000000..ce8d7358cfcf --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.fail.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `feat_moo` + --> $DIR/unstable-feature-cross-crate-exact-symbol.rs:16:5 + | +LL | Moo::foo(); + | ^^^ + | + = help: add `#![feature(feat_moo)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required for `Moo` to implement `Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.rs b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.rs new file mode 100644 index 000000000000..a427bb8eb7ed --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.rs @@ -0,0 +1,18 @@ +//@ aux-build:unstable_feature.rs +//@ revisions: pass fail +//@[pass] check-pass + +#![cfg_attr(pass, feature(feat_bar, feat_moo))] +#![cfg_attr(fail, feature(feat_bar))] + +extern crate unstable_feature; +use unstable_feature::{Foo, Bar, Moo}; + +/// To use impls gated by both `feat_foo` and `feat_moo`, +/// both features must be enabled. + +fn main() { + Bar::foo(); + Moo::foo(); + //[fail]~^ ERROR:use of unstable library feature `feat_moo` [E0658] +} diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-multiple-symbol.rs b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-multiple-symbol.rs new file mode 100644 index 000000000000..5b09c898a08b --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-multiple-symbol.rs @@ -0,0 +1,11 @@ +//@ aux-build:unstable_feature.rs +//@ check-pass +#![feature(feat_bar, feat_moo)] +extern crate unstable_feature; +use unstable_feature::{Foo, Bar}; + +/// Bar::foo() should still be usable even if we enable multiple feature. + +fn main() { + Bar::foo(); +} diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.fail.stderr b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.fail.stderr new file mode 100644 index 000000000000..87a2ad41fc13 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.fail.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `feat_bar` + --> $DIR/unstable-feature-cross-crate-require-bound.rs:12:5 + | +LL | Bar::foo(); + | ^^^ + | + = help: add `#![feature(feat_bar)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required for `Bar` to implement `Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.rs b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.rs new file mode 100644 index 000000000000..8be214b5324c --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.rs @@ -0,0 +1,14 @@ +//@ aux-build:unstable_feature.rs +//@ revisions: pass fail +//@[pass] check-pass + +#![cfg_attr(pass, feature(feat_bar))] +extern crate unstable_feature; +use unstable_feature::{Foo, Bar}; + +/// #[feature(..)] is required to use unstable impl. + +fn main() { + Bar::foo(); + //[fail]~^ ERROR: use of unstable library feature `feat_bar` [E0658] +} diff --git a/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.fail.stderr b/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.fail.stderr new file mode 100644 index 000000000000..b8cb63ec65f3 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.fail.stderr @@ -0,0 +1,17 @@ +error: unstable feature `feat_moo` is used without being enabled. + --> $DIR/unstable-feature-exact-symbol.rs:37:5 + | +LL | Bar::moo(); + | ^^^ + | + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_moo)]` +note: required for `Bar` to implement `Moo` + --> $DIR/unstable-feature-exact-symbol.rs:29:6 + | +LL | #[unstable_feature_bound(feat_moo)] + | ----------------------------------- unsatisfied trait bound introduced here +LL | impl Moo for Bar { + | ^^^ ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.rs b/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.rs new file mode 100644 index 000000000000..2de9e6a857ea --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.rs @@ -0,0 +1,42 @@ +//@ revisions: pass fail +//@[pass] check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![unstable(feature = "feat_foo", issue = "none" )] + +/// In staged-api crate, impl that is marked as unstable with +/// feature name `feat_moo` should not be accessible +/// if only `feat_foo` is enabled. + +pub trait Foo { + fn foo(); +} + +pub trait Moo { + fn moo(); +} + +pub struct Bar; + +#[unstable_feature_bound(feat_foo)] +impl Foo for Bar { + fn foo() {} +} + +#[unstable_feature_bound(feat_moo)] +impl Moo for Bar { + fn moo() {} +} + +#[cfg_attr(fail, unstable_feature_bound(feat_foo))] +#[cfg_attr(pass, unstable_feature_bound(feat_foo, feat_moo))] +fn bar() { + Bar::foo(); + Bar::moo(); + //[fail]~^ ERROR unstable feature `feat_moo` is used without being enabled. + +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.fail.stderr b/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.fail.stderr new file mode 100644 index 000000000000..db9759b4cc3a --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.fail.stderr @@ -0,0 +1,22 @@ +error: unstable feature `feat_foo` is used without being enabled. + --> $DIR/unstable-impl-assoc-type.rs:23:16 + | +LL | type Assoc = Self; + | ^^^^ + | + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_foo)]` +note: required for `Foo` to implement `Bar` + --> $DIR/unstable-impl-assoc-type.rs:19:6 + | +LL | #[unstable_feature_bound(feat_foo)] + | ----------------------------------- unsatisfied trait bound introduced here +LL | impl Bar for Foo {} + | ^^^ ^^^ +note: required by a bound in `Trait::Assoc` + --> $DIR/unstable-impl-assoc-type.rs:13:17 + | +LL | type Assoc: Bar; + | ^^^ required by this bound in `Trait::Assoc` + +error: aborting due to 1 previous error + diff --git a/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.rs b/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.rs new file mode 100644 index 000000000000..e31dc688dfab --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.rs @@ -0,0 +1,28 @@ +//@ revisions: pass fail +//@[pass] check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![unstable(feature = "feat_foo", issue = "none" )] + +/// Test that you can't leak unstable impls through item bounds on associated types. + +trait Bar {} + +trait Trait { + type Assoc: Bar; +} + +struct Foo; + +#[unstable_feature_bound(feat_foo)] +impl Bar for Foo {} + +#[cfg_attr(pass, unstable_feature_bound(feat_foo))] +impl Trait for Foo { + type Assoc = Self; + //[fail]~^ ERROR: unstable feature `feat_foo` is used without being enabled. + +} + +fn main(){} diff --git a/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.fail.stderr b/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.fail.stderr new file mode 100644 index 000000000000..d56072362fe2 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.fail.stderr @@ -0,0 +1,17 @@ +error: unstable feature `feat_foo` is used without being enabled. + --> $DIR/unstable-impl-cannot-use-feature.rs:26:5 + | +LL | Bar::foo(); + | ^^^ + | + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_foo)]` +note: required for `Bar` to implement `Foo` + --> $DIR/unstable-impl-cannot-use-feature.rs:20:6 + | +LL | #[unstable_feature_bound(feat_foo)] + | ----------------------------------- unsatisfied trait bound introduced here +LL | impl Foo for Bar { + | ^^^ ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.rs b/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.rs new file mode 100644 index 000000000000..0da618445fd2 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.rs @@ -0,0 +1,30 @@ +//@ revisions: pass fail +//@[pass] check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![unstable(feature = "feat_foo", issue = "none" )] + +#![cfg_attr(fail, feature(feat_foo))] + +/// In staged-api crate, using an unstable impl requires +/// #[unstable_feature_bound(..)], not #[feature(..)]. + +pub trait Foo { + fn foo(); +} +pub struct Bar; + +#[unstable_feature_bound(feat_foo)] +impl Foo for Bar { + fn foo() {} +} + +#[cfg_attr(pass, unstable_feature_bound(feat_foo))] +fn bar() { + Bar::foo(); + //[fail]~^ ERROR: unstable feature `feat_foo` is used without being enabled. +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable-impl-multiple-symbol.rs b/tests/ui/unstable-feature-bound/unstable-impl-multiple-symbol.rs new file mode 100644 index 000000000000..c9a9029b0a06 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-impl-multiple-symbol.rs @@ -0,0 +1,27 @@ +//@ check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![unstable(feature = "feat_foo", issue = "none" )] + +/// In staged-api crate, if feat_foo is only needed to use an impl, +/// having both `feat_foo` and `feat_bar` will still make it pass. + +pub trait Foo { + fn foo(); +} +pub struct Bar; + +// Annotate the impl as unstable. +#[unstable_feature_bound(feat_foo)] +impl Foo for Bar { + fn foo() {} +} + +#[unstable_feature_bound(feat_foo, feat_bar)] +fn bar() { + Bar::foo(); +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.fail.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.fail.stderr new file mode 100644 index 000000000000..f83542568289 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.fail.stderr @@ -0,0 +1,17 @@ +error: unstable feature `feat_bar` is used without being enabled. + --> $DIR/unstable_feature_bound_free_fn.rs:36:5 + | +LL | bar(); + | ^^^^^ + | + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_bar)]` +note: required by a bound in `bar` + --> $DIR/unstable_feature_bound_free_fn.rs:29:1 + | +LL | #[unstable_feature_bound(feat_bar)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `bar` +LL | fn bar() { + | --- required by a bound in this function + +error: aborting due to 1 previous error + diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.rs new file mode 100644 index 000000000000..30e2ab3d65ef --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.rs @@ -0,0 +1,40 @@ +//@ revisions: pass fail +//@[pass] check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![stable(feature = "a", since = "1.1.1" )] + +/// When a free function with #[unstable_feature_bound(feat_bar)] is called by another +/// free function, that function should be annotated with +/// #[unstable_feature_bound(feat_bar)] too. + +#[stable(feature = "a", since = "1.1.1")] +trait Foo { + #[stable(feature = "a", since = "1.1.1")] + fn foo() { + } +} +#[stable(feature = "a", since = "1.1.1")] +pub struct Bar; + +#[unstable_feature_bound(feat_bar)] +#[unstable(feature = "feat_bar", issue = "none" )] +impl Foo for Bar { + fn foo() {} +} + + +#[unstable_feature_bound(feat_bar)] +fn bar() { + Bar::foo(); +} + +#[cfg_attr(pass, unstable_feature_bound(feat_bar))] +fn bar2() { + bar(); + //[fail]~^ERROR unstable feature `feat_bar` is used without being enabled. +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.rs new file mode 100644 index 000000000000..3d6b52ba5177 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.rs @@ -0,0 +1,36 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![unstable(feature = "feat_bar", issue = "none" )] + +/// Test the behaviour of multiple unstable_feature_bound attribute. + +trait Foo { + fn foo(); +} +struct Bar; + +#[unstable_feature_bound(feat_bar, feat_koo)] +#[unstable_feature_bound(feat_foo, feat_moo)] +impl Foo for Bar { + fn foo(){} +} + +#[unstable_feature_bound(feat_bar, feat_koo)] +#[unstable_feature_bound(feat_foo, feat_moo)] +fn moo() { + Bar::foo(); +} + +#[unstable_feature_bound(feat_bar, feat_koo, feat_foo, feat_moo)] +fn koo() { + Bar::foo(); +} + +#[unstable_feature_bound(feat_koo, feat_foo, feat_moo)] +fn boo() { + Bar::foo(); + //~^ ERROR: unstable feature `feat_bar` is used without being enabled. +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.stderr new file mode 100644 index 000000000000..936c70c19796 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.stderr @@ -0,0 +1,18 @@ +error: unstable feature `feat_bar` is used without being enabled. + --> $DIR/unstable_feature_bound_multi_attr.rs:32:5 + | +LL | Bar::foo(); + | ^^^ + | + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_bar)]` +note: required for `Bar` to implement `Foo` + --> $DIR/unstable_feature_bound_multi_attr.rs:15:6 + | +LL | #[unstable_feature_bound(feat_bar, feat_koo)] + | --------------------------------------------- unsatisfied trait bound introduced here +LL | #[unstable_feature_bound(feat_foo, feat_moo)] +LL | impl Foo for Bar { + | ^^^ ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.rs new file mode 100644 index 000000000000..51e388f7dd32 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.rs @@ -0,0 +1,13 @@ +/// Unstable feature bound can only be used only when +/// #[feature(staged_api)] is enabled. + +pub trait Foo { +} +pub struct Bar; + +#[unstable_feature_bound(feat_bar)] +//~^ ERROR: stability attributes may not be used outside of the standard library +impl Foo for Bar { +} + +fn main(){} diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.stderr new file mode 100644 index 000000000000..35ab89e6ad99 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.stderr @@ -0,0 +1,9 @@ +error[E0734]: stability attributes may not be used outside of the standard library + --> $DIR/unstable_feature_bound_staged_api.rs:8:1 + | +LL | #[unstable_feature_bound(feat_bar)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0734`. diff --git a/tests/ui/unstable-feature-bound/unstable_impl_codegen.rs b/tests/ui/unstable-feature-bound/unstable_impl_codegen.rs new file mode 100644 index 000000000000..285a64d2250a --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_impl_codegen.rs @@ -0,0 +1,13 @@ +//@ aux-build:unstable_impl_codegen_aux2.rs +//@ run-pass + +/// Downstream crate for unstable impl codegen test +/// that depends on upstream crate in +/// unstable_impl_codegen_aux2.rs + +extern crate unstable_impl_codegen_aux2 as aux; +use aux::foo; + +fn main() { + foo(1_u8); +} diff --git a/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr b/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr new file mode 100644 index 000000000000..c3147558b03f --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `LocalTy` + --> $DIR/unstable_impl_coherence.rs:14:1 + | +LL | impl aux::Trait for LocalTy {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `unstable_impl_coherence_aux`: + - impl Trait for T + where unstable feature: `foo`; + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr b/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr new file mode 100644 index 000000000000..c3147558b03f --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `LocalTy` + --> $DIR/unstable_impl_coherence.rs:14:1 + | +LL | impl aux::Trait for LocalTy {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `unstable_impl_coherence_aux`: + - impl Trait for T + where unstable feature: `foo`; + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/unstable-feature-bound/unstable_impl_coherence.rs b/tests/ui/unstable-feature-bound/unstable_impl_coherence.rs new file mode 100644 index 000000000000..22100f85f715 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_impl_coherence.rs @@ -0,0 +1,17 @@ +//@ aux-build:unstable_impl_coherence_aux.rs +//@ revisions: enabled disabled + +#![cfg_attr(enabled, feature(foo))] +extern crate unstable_impl_coherence_aux as aux; +use aux::Trait; + +/// Coherence test for unstable impl. +/// No matter feature `foo` is enabled or not, the impl +/// for aux::Trait will be rejected by coherence checking. + +struct LocalTy; + +impl aux::Trait for LocalTy {} +//~^ ERROR: conflicting implementations of trait `Trait` for type `LocalTy` + +fn main(){} diff --git a/tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs new file mode 100644 index 000000000000..acf521d3130c --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs @@ -0,0 +1,15 @@ +//@ aux-build:unstable_impl_method_selection_aux.rs + +extern crate unstable_impl_method_selection_aux as aux; +use aux::Trait; + +// The test below should not infer the type based on the fact +// that `impl Trait for Vec` is unstable. This would cause breakage +// in downstream crate once `impl Trait for Vec` is stabilised. + +fn bar() { + vec![].foo(); + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr new file mode 100644 index 000000000000..c2bb10f043b2 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr @@ -0,0 +1,14 @@ +error[E0283]: type annotations needed + --> $DIR/unstable_impl_method_selection.rs:11:12 + | +LL | vec![].foo(); + | ^^^ cannot infer type for struct `Vec<_>` + | + = note: multiple `impl`s satisfying `Vec<_>: Trait` found in the `unstable_impl_method_selection_aux` crate: + - impl Trait for Vec; + - impl Trait for Vec + where unstable feature: `bar`; + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. From e331de149f4fe5ddafe7f4bad13acb1499a6108e Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 14 Jul 2025 14:33:54 +0000 Subject: [PATCH 189/363] Fix CI --- compiler/rustc_session/src/parse.rs | 2 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index ea7a524efe6d..9097b27b86c4 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -209,7 +209,7 @@ pub fn add_feature_diagnostics_for_issue( /// This is basically the same as `feature_err_issue` /// but without the feature issue note. If we can do a lookup for issue number from feature name, /// then we should directly use `feature_err_issue` for ambiguity error of -/// #[unstable_feature_bound]. +/// `#[unstable_feature_bound]`. #[track_caller] pub fn feature_err_unstable_feature_bound( sess: &Session, diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index b558d0164483..e86a2305e233 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -319,11 +319,6 @@ where // Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled // if we are in std/core even if there is a corresponding `feature` attribute on the crate. - if (infcx.typing_mode() == TypingMode::PostAnalysis) + (infcx.typing_mode() == TypingMode::PostAnalysis) || infcx.cx().features().feature_bound_holds_in_crate(symbol) - { - return true; - } else { - return false; - } } From 9a76dde4d23371d2deef39c56ff9f22051c884f7 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Tue, 15 Jul 2025 15:50:02 +0200 Subject: [PATCH 190/363] Make spin function naming more consistent --- .../miri/tests/pass/0weak_memory_consistency.rs | 16 ++++++++-------- .../tests/pass/0weak_memory_consistency_sc.rs | 10 +++++----- src/tools/miri/tests/pass/weak_memory/weak.rs | 8 ++++---- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/tools/miri/tests/pass/0weak_memory_consistency.rs b/src/tools/miri/tests/pass/0weak_memory_consistency.rs index 5fba54934421..e4ed9675de82 100644 --- a/src/tools/miri/tests/pass/0weak_memory_consistency.rs +++ b/src/tools/miri/tests/pass/0weak_memory_consistency.rs @@ -41,7 +41,7 @@ fn static_atomic_bool(val: bool) -> &'static AtomicBool { } /// Spins until it acquires a pre-determined value. -fn loads_value(loc: &AtomicI32, ord: Ordering, val: i32) -> i32 { +fn spin_until_i32(loc: &AtomicI32, ord: Ordering, val: i32) -> i32 { while loc.load(ord) != val { std::hint::spin_loop(); } @@ -49,7 +49,7 @@ fn loads_value(loc: &AtomicI32, ord: Ordering, val: i32) -> i32 { } /// Spins until it acquires a pre-determined boolean. -fn loads_bool(loc: &AtomicBool, ord: Ordering, val: bool) -> bool { +fn spin_until_bool(loc: &AtomicBool, ord: Ordering, val: bool) -> bool { while loc.load(ord) != val { std::hint::spin_loop(); } @@ -73,7 +73,7 @@ fn test_corr() { }); // | | #[rustfmt::skip] // |synchronizes-with |happens-before let j3 = spawn(move || { // | | - loads_value(&y, Acquire, 1); // <------------+ | + spin_until_i32(&y, Acquire, 1); // <---------+ | x.load(Relaxed) // <----------------------------------------------+ // The two reads on x are ordered by hb, so they cannot observe values // differently from the modification order. If the first read observed @@ -98,12 +98,12 @@ fn test_wrc() { }); // | | #[rustfmt::skip] // |synchronizes-with | let j2 = spawn(move || { // | | - loads_value(&x, Acquire, 1); // <------------+ | + spin_until_i32(&x, Acquire, 1); // <---------+ | y.store(1, Release); // ---------------------+ |happens-before }); // | | #[rustfmt::skip] // |synchronizes-with | let j3 = spawn(move || { // | | - loads_value(&y, Acquire, 1); // <------------+ | + spin_until_i32(&y, Acquire, 1); // <---------+ | x.load(Relaxed) // <-----------------------------------------------+ }); @@ -129,7 +129,7 @@ fn test_message_passing() { #[rustfmt::skip] // |synchronizes-with | happens-before let j2 = spawn(move || { // | | let x = x; // avoid field capturing | | - loads_value(&y, Acquire, 1); // <------------+ | + spin_until_i32(&y, Acquire, 1); // <---------+ | unsafe { *x.0 } // <---------------------------------------------+ }); @@ -224,12 +224,12 @@ fn test_sync_through_rmw_and_fences() { let go = static_atomic_bool(false); let t1 = spawn(move || { - loads_bool(go, Relaxed, true); + spin_until_bool(go, Relaxed, true); rdmw(y, x, z) }); let t2 = spawn(move || { - loads_bool(go, Relaxed, true); + spin_until_bool(go, Relaxed, true); rdmw(z, x, y) }); diff --git a/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs b/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs index 2c9d742a8b11..937c2a8cf282 100644 --- a/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs +++ b/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs @@ -20,7 +20,7 @@ fn static_atomic_bool(val: bool) -> &'static AtomicBool { } /// Spins until it acquires a pre-determined value. -fn loads_value(loc: &AtomicI32, ord: Ordering, val: i32) -> i32 { +fn spin_until_i32(loc: &AtomicI32, ord: Ordering, val: i32) -> i32 { while loc.load(ord) != val { std::hint::spin_loop(); } @@ -28,7 +28,7 @@ fn loads_value(loc: &AtomicI32, ord: Ordering, val: i32) -> i32 { } /// Spins until it acquires a pre-determined boolean. -fn loads_bool(loc: &AtomicBool, ord: Ordering, val: bool) -> bool { +fn spin_until_bool(loc: &AtomicBool, ord: Ordering, val: bool) -> bool { while loc.load(ord) != val { std::hint::spin_loop(); } @@ -68,11 +68,11 @@ fn test_iriw_sc_rlx() { let a = spawn(move || x.store(true, Relaxed)); let b = spawn(move || y.store(true, Relaxed)); let c = spawn(move || { - loads_bool(x, SeqCst, true); + spin_until_bool(x, SeqCst, true); y.load(SeqCst) }); let d = spawn(move || { - loads_bool(y, SeqCst, true); + spin_until_bool(y, SeqCst, true); x.load(SeqCst) }); @@ -144,7 +144,7 @@ fn test_cpp20_rwc_syncs() { }); let j2 = spawn(move || { - loads_value(&x, Relaxed, 1); + spin_until_i32(&x, Relaxed, 1); fence(SeqCst); y.load(Relaxed) }); diff --git a/src/tools/miri/tests/pass/weak_memory/weak.rs b/src/tools/miri/tests/pass/weak_memory/weak.rs index 569a307ab064..199f83f05286 100644 --- a/src/tools/miri/tests/pass/weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/weak_memory/weak.rs @@ -24,7 +24,7 @@ fn static_atomic(val: usize) -> &'static AtomicUsize { } // Spins until it reads the given value -fn reads_value(loc: &AtomicUsize, val: usize) -> usize { +fn spin_until(loc: &AtomicUsize, val: usize) -> usize { while loc.load(Relaxed) != val { std::hint::spin_loop(); } @@ -85,7 +85,7 @@ fn initialization_write(add_fence: bool) -> bool { }); let j2 = spawn(move || { - reads_value(wait, 1); + spin_until(wait, 1); if add_fence { fence(AcqRel); } @@ -119,12 +119,12 @@ fn faa_replaced_by_load() -> bool { let go = static_atomic(0); let t1 = spawn(move || { - reads_value(go, 1); + spin_until(go, 1); rdmw(y, x, z) }); let t2 = spawn(move || { - reads_value(go, 1); + spin_until(go, 1); rdmw(z, x, y) }); From 4b421d44e20351426cf4ded11248bd1d0af40b5f Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 15 Jul 2025 13:33:32 +0000 Subject: [PATCH 191/363] Fix handling of SCRIPT_ARG in docker images Instead of making this a build parameter, pass the SCRIPT as an environment variable. To this purpose, normalize on always referring to a script in `/scripts`. For i686-gnu-nopt-2 I had to create a separate script, because Docker seems to be really terrible at command line argument parsing, so it's not possible to pass an environment variable that contains whitespace. --- .../host-aarch64/aarch64-gnu-llvm-19/Dockerfile | 8 +++----- .../host-x86_64/dist-x86_64-linux/Dockerfile | 4 +--- src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile | 4 ++-- src/ci/docker/host-x86_64/i686-gnu/Dockerfile | 3 +-- .../host-x86_64/x86_64-gnu-llvm-19/Dockerfile | 14 ++++++-------- .../host-x86_64/x86_64-gnu-llvm-20/Dockerfile | 14 ++++++-------- src/ci/docker/run.sh | 12 ++++-------- src/ci/docker/scripts/i686-gnu-nopt-2.sh | 6 ++++++ src/ci/docker/scripts/x86_64-gnu-llvm2.sh | 2 +- src/ci/github-actions/jobs.yml | 6 ++---- 10 files changed, 32 insertions(+), 41 deletions(-) create mode 100755 src/ci/docker/scripts/i686-gnu-nopt-2.sh diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile index 2f9d0010573a..e73fbe506f78 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile @@ -50,9 +50,7 @@ ENV RUST_CONFIGURE_ARGS \ COPY scripts/shared.sh /scripts/ -ARG SCRIPT_ARG +COPY scripts/stage_2_test_set1.sh /scripts/ +COPY scripts/stage_2_test_set2.sh /scripts/ -COPY scripts/stage_2_test_set1.sh /tmp/ -COPY scripts/stage_2_test_set2.sh /tmp/ - -ENV SCRIPT "/tmp/${SCRIPT_ARG}" +ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 44f6a8d2a155..01f19eac1d2f 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -96,12 +96,10 @@ ENV RUST_CONFIGURE_ARGS \ --set rust.lto=thin \ --set rust.codegen-units=1 -ARG SCRIPT_ARG - COPY host-x86_64/dist-x86_64-linux/dist.sh /scripts/ COPY host-x86_64/dist-x86_64-linux/dist-alt.sh /scripts/ -ENV SCRIPT /scripts/${SCRIPT_ARG} +ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile index 58e66fd637a2..be3df9d4036d 100644 --- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile @@ -23,7 +23,7 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests -ARG SCRIPT_ARG COPY scripts/stage_2_test_set1.sh /scripts/ COPY scripts/stage_2_test_set2.sh /scripts/ -ENV SCRIPT ${SCRIPT_ARG} +COPY scripts/i686-gnu-nopt-2.sh /scripts/ +ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile index a715f7182d2a..00cd24b89db8 100644 --- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile @@ -24,7 +24,6 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu -ARG SCRIPT_ARG COPY scripts/stage_2_test_set1.sh /scripts/ COPY scripts/stage_2_test_set2.sh /scripts/ -ENV SCRIPT /scripts/${SCRIPT_ARG} +ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile index c09be047c6a8..5cba7c564f16 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile @@ -57,12 +57,10 @@ ENV RUST_CONFIGURE_ARGS \ COPY scripts/shared.sh /scripts/ -ARG SCRIPT_ARG +COPY scripts/x86_64-gnu-llvm.sh /scripts/ +COPY scripts/x86_64-gnu-llvm2.sh /scripts/ +COPY scripts/x86_64-gnu-llvm3.sh /scripts/ +COPY scripts/stage_2_test_set1.sh /scripts/ +COPY scripts/stage_2_test_set2.sh /scripts/ -COPY scripts/x86_64-gnu-llvm.sh /tmp/ -COPY scripts/x86_64-gnu-llvm2.sh /tmp/ -COPY scripts/x86_64-gnu-llvm3.sh /tmp/ -COPY scripts/stage_2_test_set1.sh /tmp/ -COPY scripts/stage_2_test_set2.sh /tmp/ - -ENV SCRIPT "/tmp/${SCRIPT_ARG}" +ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile index 83a3bfb37a54..92c2631000f9 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile @@ -57,12 +57,10 @@ ENV RUST_CONFIGURE_ARGS \ COPY scripts/shared.sh /scripts/ -ARG SCRIPT_ARG +COPY scripts/x86_64-gnu-llvm.sh /scripts/ +COPY scripts/x86_64-gnu-llvm2.sh /scripts/ +COPY scripts/x86_64-gnu-llvm3.sh /scripts/ +COPY scripts/stage_2_test_set1.sh /scripts/ +COPY scripts/stage_2_test_set2.sh /scripts/ -COPY scripts/x86_64-gnu-llvm.sh /tmp/ -COPY scripts/x86_64-gnu-llvm2.sh /tmp/ -COPY scripts/x86_64-gnu-llvm3.sh /tmp/ -COPY scripts/stage_2_test_set1.sh /tmp/ -COPY scripts/stage_2_test_set2.sh /tmp/ - -ENV SCRIPT "/tmp/${SCRIPT_ARG}" +ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index da7d084d48d8..044f5a8fff32 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -114,14 +114,6 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then "$context" ) - # If the environment variable DOCKER_SCRIPT is defined, - # set the build argument SCRIPT_ARG to DOCKER_SCRIPT. - # In this way, we run the script defined in CI, - # instead of the one defined in the Dockerfile. - if [ -n "${DOCKER_SCRIPT+x}" ]; then - build_args+=("--build-arg" "SCRIPT_ARG=${DOCKER_SCRIPT}") - fi - GHCR_BUILDKIT_IMAGE="ghcr.io/rust-lang/buildkit:buildx-stable-1" # On non-CI jobs, we try to download a pre-built image from the rust-lang-ci # ghcr.io registry. If it is not possible, we fall back to building the image @@ -341,6 +333,10 @@ if [ "$ENABLE_GCC_CODEGEN" = "1" ]; then echo "Setting extra environment values for docker: $extra_env" fi +if [ -n "${DOCKER_SCRIPT}" ]; then + extra_env="$extra_env --env SCRIPT=\"/scripts/${DOCKER_SCRIPT}\"" +fi + docker \ run \ --workdir /checkout/obj \ diff --git a/src/ci/docker/scripts/i686-gnu-nopt-2.sh b/src/ci/docker/scripts/i686-gnu-nopt-2.sh new file mode 100755 index 000000000000..4c171739dafc --- /dev/null +++ b/src/ci/docker/scripts/i686-gnu-nopt-2.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +set -ex + +python3 ../x.py test --stage 1 --set rust.optimize=false library/std && +/scripts/stage_2_test_set2.sh diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm2.sh b/src/ci/docker/scripts/x86_64-gnu-llvm2.sh index fe5382aaa48c..0060b9bfd23b 100755 --- a/src/ci/docker/scripts/x86_64-gnu-llvm2.sh +++ b/src/ci/docker/scripts/x86_64-gnu-llvm2.sh @@ -4,7 +4,7 @@ set -ex ##### Test stage 2 ##### -/tmp/stage_2_test_set1.sh +/scripts/stage_2_test_set1.sh # Run the `mir-opt` tests again but this time for a 32-bit target. # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 445fc0dd018c..6c5e37b51ef2 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -315,16 +315,14 @@ auto: - name: i686-gnu-nopt-1 env: IMAGE: i686-gnu-nopt - DOCKER_SCRIPT: /scripts/stage_2_test_set1.sh + DOCKER_SCRIPT: stage_2_test_set1.sh <<: *job-linux-4c # Skip tests that run in i686-gnu-nopt-1 - name: i686-gnu-nopt-2 env: IMAGE: i686-gnu-nopt - DOCKER_SCRIPT: >- - python3 ../x.py test --stage 1 --set rust.optimize=false library/std && - /scripts/stage_2_test_set2.sh + DOCKER_SCRIPT: i686-gnu-nopt-2.sh <<: *job-linux-4c - name: pr-check-1 From 8770e5734ed5e7c1b8bc8b59b73b7f79134e4190 Mon Sep 17 00:00:00 2001 From: Havard Eidnes Date: Mon, 14 Jul 2025 17:03:42 +0000 Subject: [PATCH 192/363] Add `0323pin` as target maintainer, and fix link to pkgsrc-wip and explain. --- src/doc/rustc/src/platform-support/netbsd.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md index e80ff85edad1..b173bf82b440 100644 --- a/src/doc/rustc/src/platform-support/netbsd.md +++ b/src/doc/rustc/src/platform-support/netbsd.md @@ -32,10 +32,11 @@ are built for NetBSD 8.x but also work on newer OS versions). ## Target Maintainers [@he32](https://github.com/he32) +[@0323pin](https://github.com/0323pin) Further contacts: -- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust185/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust +- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust188/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust. Note that we have the convention of having multiple rust versions active in pkgsrc-wip at any one time, so the version number is part of the directory name, and from time to time old versions are culled so this is not a fully "stable" link. - [NetBSD's pkgsrc lang/rust](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust) for the "proper" package in pkgsrc. - [NetBSD's pkgsrc lang/rust-bin](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust-bin) which re-uses the bootstrap kit as a binary distribution and therefore avoids the rather protracted native build time of rust itself From 7976ca2442db9b69a7949b5fd6afcf8894441afa Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 19 May 2025 10:14:48 +0000 Subject: [PATCH 193/363] Add outlives to CoroutineWitnessTypes --- compiler/rustc_middle/src/ty/context.rs | 5 +++++ compiler/rustc_middle/src/ty/structural_impls.rs | 1 + compiler/rustc_traits/src/coroutine_witnesses.rs | 3 +-- compiler/rustc_type_ir/src/interner.rs | 7 +++++++ compiler/rustc_type_ir/src/ty_kind.rs | 1 + 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 98b2ce01d89b..45e311e95e4a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -162,6 +162,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type BoundRegion = ty::BoundRegion; type PlaceholderRegion = ty::PlaceholderRegion; + type RegionAssumptions = &'tcx ty::List>>; + type ParamEnv = ty::ParamEnv<'tcx>; type Predicate = Predicate<'tcx>; @@ -874,6 +876,7 @@ pub struct CtxtInterners<'tcx> { offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>, valtree: InternedSet<'tcx, ty::ValTreeKind<'tcx>>, patterns: InternedSet<'tcx, List>>, + outlives: InternedSet<'tcx, List>>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -911,6 +914,7 @@ impl<'tcx> CtxtInterners<'tcx> { offset_of: InternedSet::with_capacity(N), valtree: InternedSet::with_capacity(N), patterns: InternedSet::with_capacity(N), + outlives: InternedSet::with_capacity(N), } } @@ -2692,6 +2696,7 @@ slice_interners!( captures: intern_captures(&'tcx ty::CapturedPlace<'tcx>), offset_of: pub mk_offset_of((VariantIdx, FieldIdx)), patterns: pub mk_patterns(Pattern<'tcx>), + outlives: pub mk_outlives(ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>), ); impl<'tcx> TyCtxt<'tcx> { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index af9c98bd87d0..55aec0efd0f9 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -802,4 +802,5 @@ list_fold! { &'tcx ty::List> : mk_poly_existential_predicates, &'tcx ty::List> : mk_place_elems, &'tcx ty::List> : mk_patterns, + &'tcx ty::List>> : mk_outlives, } diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index 447e13126ccd..c1573ba76412 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -29,9 +29,8 @@ pub(crate) fn coroutine_hidden_types<'tcx>( ty }), ); - ty::EarlyBinder::bind(ty::Binder::bind_with_vars( - ty::CoroutineWitnessTypes { types: bound_tys }, + ty::CoroutineWitnessTypes { types: bound_tys, assumptions: ty::List::empty() }, tcx.mk_bound_variable_kinds(&vars), )) } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index dd3cf1fc1811..dfd683ac2439 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -145,6 +145,13 @@ pub trait Interner: type BoundRegion: BoundVarLike; type PlaceholderRegion: PlaceholderLike; + type RegionAssumptions: Copy + + Debug + + Hash + + Eq + + SliceLike> + + TypeFoldable; + // Predicates type ParamEnv: ParamEnv; type Predicate: Predicate; diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index db6fbefcf05c..7c6654247505 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -1150,4 +1150,5 @@ pub struct FnHeader { #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct CoroutineWitnessTypes { pub types: I::Tys, + pub assumptions: I::RegionAssumptions, } From 3e7dfaa51027d33f3613ed0203df495784b21f19 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 9 Jul 2025 23:57:41 +0000 Subject: [PATCH 194/363] Deduce outlives obligations from WF of coroutine interior types --- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 11 ++++ .../rustc_traits/src/coroutine_witnesses.rs | 57 ++++++++++++++++++- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 935cc8895740..f605da24bc49 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -988,7 +988,7 @@ rustc_queries! { } query coroutine_hidden_types( - def_id: DefId + def_id: DefId, ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes>>> { desc { "looking up the hidden types stored across await points in a coroutine" } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 45e311e95e4a..5a1d8d215d23 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3112,6 +3112,17 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_bound_variable_kinds(xs)) } + pub fn mk_outlives_from_iter(self, iter: I) -> T::Output + where + I: Iterator, + T: CollectAndApply< + ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, + &'tcx ty::List>>, + >, + { + T::collect_and_apply(iter, |xs| self.mk_outlives(xs)) + } + /// Emit a lint at `span` from a lint struct (some type that implements `LintDiagnostic`, /// typically generated by `#[derive(LintDiagnostic)]`). #[track_caller] diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index c1573ba76412..d79777437e6c 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -1,5 +1,10 @@ use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, TyCtxt, fold_regions}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::canonical::query_response::make_query_region_constraints; +use rustc_infer::infer::resolve::OpportunisticRegionResolver; +use rustc_infer::traits::{Obligation, ObligationCause}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions}; +use rustc_trait_selection::traits::{ObligationCtxt, with_replaced_escaping_bound_vars}; /// Return the set of types that should be taken into account when checking /// trait bounds on a coroutine's internal state. This properly replaces @@ -29,8 +34,56 @@ pub(crate) fn coroutine_hidden_types<'tcx>( ty }), ); + + let assumptions = compute_assumptions(tcx, def_id, bound_tys); + ty::EarlyBinder::bind(ty::Binder::bind_with_vars( - ty::CoroutineWitnessTypes { types: bound_tys, assumptions: ty::List::empty() }, + ty::CoroutineWitnessTypes { types: bound_tys, assumptions }, tcx.mk_bound_variable_kinds(&vars), )) } + +fn compute_assumptions<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + bound_tys: &'tcx ty::List>, +) -> &'tcx ty::List>> { + let infcx = tcx.infer_ctxt().build(ty::TypingMode::Analysis { + defining_opaque_types_and_generators: ty::List::empty(), + }); + with_replaced_escaping_bound_vars(&infcx, &mut vec![None], bound_tys, |bound_tys| { + let param_env = tcx.param_env(def_id); + let ocx = ObligationCtxt::new(&infcx); + + ocx.register_obligations(bound_tys.iter().map(|ty| { + Obligation::new( + tcx, + ObligationCause::dummy(), + param_env, + ty::ClauseKind::WellFormed(ty.into()), + ) + })); + let _errors = ocx.select_all_or_error(); + + let region_obligations = infcx.take_registered_region_obligations(); + let region_constraints = infcx.take_and_reset_region_constraints(); + + let outlives = make_query_region_constraints( + tcx, + region_obligations, + ®ion_constraints, + ) + .outlives + .fold_with(&mut OpportunisticRegionResolver::new(&infcx)); + + tcx.mk_outlives_from_iter( + outlives + .into_iter() + .map(|(o, _)| o) + // FIXME(higher_ranked_auto): We probably should deeply resolve these before + // filtering out infers which only correspond to unconstrained infer regions + // which we can sometimes get. + .filter(|o| !o.has_infer()), + ) + }) +} From e3f643c70670a3e1567b0816502ab247565305f8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Jul 2025 20:43:29 +0000 Subject: [PATCH 195/363] Consider outlives assumptions when proving auto traits for coroutine interiors --- .../src/type_check/constraint_conversion.rs | 27 +++++-- compiler/rustc_borrowck/src/type_check/mod.rs | 5 ++ .../src/infer/canonical/query_response.rs | 28 ++++++- compiler/rustc_infer/src/infer/mod.rs | 15 +++- .../rustc_infer/src/infer/outlives/env.rs | 13 +++- .../rustc_infer/src/infer/outlives/mod.rs | 19 ++++- .../src/infer/outlives/obligations.rs | 22 ++++++ .../src/infer/snapshot/undo_log.rs | 4 + compiler/rustc_middle/src/infer/canonical.rs | 11 ++- compiler/rustc_trait_selection/src/regions.rs | 8 +- .../src/solve/delegate.rs | 8 +- .../src/traits/coherence.rs | 1 + .../src/traits/outlives_bounds.rs | 5 +- .../src/traits/query/type_op/custom.rs | 7 ++ .../src/traits/query/type_op/mod.rs | 3 +- .../src/traits/select/confirmation.rs | 25 +++++-- .../src/traits/select/mod.rs | 73 ++++++++++++++----- .../rustc_traits/src/coroutine_witnesses.rs | 2 + compiler/rustc_type_ir/src/elaborate.rs | 51 +++++++++++++ src/tools/tidy/src/issues.txt | 2 - ...drop-tracking-unresolved-typeck-results.rs | 3 +- ...-tracking-unresolved-typeck-results.stderr | 29 -------- .../issue-110963-early.rs | 2 +- .../issue-110963-early.stderr | 31 -------- .../bugs/issue-100013.stderr | 48 ------------ ...gher-ranked-coroutine-param-outlives-2.rs} | 15 +--- .../higher-ranked-coroutine-param-outlives.rs | 21 ++++++ .../generic-associated-types/issue-92096.rs | 28 ------- .../issue-92096.stderr | 8 -- 29 files changed, 310 insertions(+), 204 deletions(-) delete mode 100644 tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr delete mode 100644 tests/ui/async-await/return-type-notation/issue-110963-early.stderr delete mode 100644 tests/ui/generic-associated-types/bugs/issue-100013.stderr rename tests/ui/generic-associated-types/{bugs/issue-100013.rs => higher-ranked-coroutine-param-outlives-2.rs} (54%) create mode 100644 tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs delete mode 100644 tests/ui/generic-associated-types/issue-92096.rs delete mode 100644 tests/ui/generic-associated-types/issue-92096.stderr diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index ca636a8c9992..fec3e415f75b 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; @@ -7,7 +8,7 @@ use rustc_infer::infer::{InferCtxt, SubregionOrigin}; use rustc_infer::traits::query::type_op::DeeplyNormalize; use rustc_middle::bug; use rustc_middle::ty::{ - self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions, + self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, elaborate, fold_regions, }; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -70,10 +71,12 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) { - let QueryRegionConstraints { outlives } = query_constraints; + let QueryRegionConstraints { outlives, assumptions } = query_constraints; + let assumptions = + elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied()); for &(predicate, constraint_category) in outlives { - self.convert(predicate, constraint_category); + self.convert(predicate, constraint_category, &assumptions); } } @@ -112,7 +115,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { self.category = outlives_requirement.category; self.span = outlives_requirement.blame_span; - self.convert(ty::OutlivesPredicate(subject, outlived_region), self.category); + self.convert( + ty::OutlivesPredicate(subject, outlived_region), + self.category, + &Default::default(), + ); } (self.category, self.span, self.from_closure) = backup; } @@ -121,6 +128,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { &mut self, predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, constraint_category: ConstraintCategory<'tcx>, + higher_ranked_assumptions: &FxHashSet>>, ) { let tcx = self.infcx.tcx; debug!("generate: constraints at: {:#?}", self.locations); @@ -150,7 +158,13 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } let mut next_outlives_predicates = vec![]; - for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates { + for (pred, constraint_category) in outlives_predicates { + // Constraint is implied by a coroutine's well-formedness. + if higher_ranked_assumptions.contains(&pred) { + continue; + } + + let ty::OutlivesPredicate(k1, r2) = pred; match k1.kind() { GenericArgKind::Lifetime(r1) => { let r1_vid = self.to_region_vid(r1); @@ -273,7 +287,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { match self.param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, self.span) { Ok(TypeOpOutput { output: ty, constraints, .. }) => { - if let Some(QueryRegionConstraints { outlives }) = constraints { + // FIXME(higher_ranked_auto): What should we do with the assumptions here? + if let Some(QueryRegionConstraints { outlives, assumptions: _ }) = constraints { next_outlives_predicates.extend(outlives.iter().copied()); } ty diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index f877e5eaadb9..d500088c259a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -131,6 +131,11 @@ pub(crate) fn type_check<'tcx>( pre_obligations.is_empty(), "there should be no incoming region obligations = {pre_obligations:#?}", ); + let pre_assumptions = infcx.take_registered_region_assumptions(); + assert!( + pre_assumptions.is_empty(), + "there should be no incoming region assumptions = {pre_assumptions:#?}", + ); debug!(?normalized_inputs_and_output); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index d5d49e3188aa..fed569761280 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -116,9 +116,15 @@ impl<'tcx> InferCtxt<'tcx> { } let region_obligations = self.take_registered_region_obligations(); + let region_assumptions = self.take_registered_region_assumptions(); debug!(?region_obligations); let region_constraints = self.with_region_constraints(|region_constraints| { - make_query_region_constraints(tcx, region_obligations, region_constraints) + make_query_region_constraints( + tcx, + region_obligations, + region_constraints, + region_assumptions, + ) }); debug!(?region_constraints); @@ -169,6 +175,11 @@ impl<'tcx> InferCtxt<'tcx> { self.register_outlives_constraint(predicate, cause); } + for assumption in &query_response.value.region_constraints.assumptions { + let assumption = instantiate_value(self.tcx, &result_args, *assumption); + self.register_region_assumption(assumption); + } + let user_result: R = query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone()); @@ -292,6 +303,18 @@ impl<'tcx> InferCtxt<'tcx> { }), ); + // FIXME(higher_ranked_auto): Optimize this to instantiate all assumptions + // at once, rather than calling `instantiate_value` repeatedly which may + // create more universes. + output_query_region_constraints.assumptions.extend( + query_response + .value + .region_constraints + .assumptions + .iter() + .map(|&r_c| instantiate_value(self.tcx, &result_args, r_c)), + ); + let user_result: R = query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone()); @@ -567,6 +590,7 @@ pub fn make_query_region_constraints<'tcx>( tcx: TyCtxt<'tcx>, outlives_obligations: Vec>, region_constraints: &RegionConstraintData<'tcx>, + assumptions: Vec>>, ) -> QueryRegionConstraints<'tcx> { let RegionConstraintData { constraints, verifys } = region_constraints; @@ -602,5 +626,5 @@ pub fn make_query_region_constraints<'tcx>( })) .collect(); - QueryRegionConstraints { outlives } + QueryRegionConstraints { outlives, assumptions } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index cc3ad921489f..458b21da6ce9 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -149,6 +149,13 @@ pub struct InferCtxtInner<'tcx> { /// that all type inference variables have been bound and so forth. region_obligations: Vec>, + /// The outlives bounds that we assume must hold about placeholders that + /// come from instantiating the binder of coroutine-witnesses. These bounds + /// are deduced from the well-formedness of the witness's types, and are + /// necessary because of the way we anonymize the regions in a coroutine, + /// which may cause types to no longer be considered well-formed. + region_assumptions: Vec>>, + /// Caches for opaque type inference. opaque_type_storage: OpaqueTypeStorage<'tcx>, } @@ -164,7 +171,8 @@ impl<'tcx> InferCtxtInner<'tcx> { int_unification_storage: Default::default(), float_unification_storage: Default::default(), region_constraint_storage: Some(Default::default()), - region_obligations: vec![], + region_obligations: Default::default(), + region_assumptions: Default::default(), opaque_type_storage: Default::default(), } } @@ -174,6 +182,11 @@ impl<'tcx> InferCtxtInner<'tcx> { &self.region_obligations } + #[inline] + pub fn region_assumptions(&self) -> &[ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>] { + &self.region_assumptions + } + #[inline] pub fn projection_cache(&mut self) -> traits::ProjectionCache<'_, 'tcx> { self.projection_cache.with_log(&mut self.undo_log) diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index cb5a33c5c972..2175ff1b4ae4 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::transitive_relation::TransitiveRelationBuilder; use rustc_middle::{bug, ty}; use tracing::debug; @@ -39,6 +39,9 @@ pub struct OutlivesEnvironment<'tcx> { /// optimized in the future, though. region_bound_pairs: RegionBoundPairs<'tcx>, known_type_outlives: Vec>, + /// Assumptions that come from the well-formedness of coroutines that we prove + /// auto trait bounds for during the type checking of this body. + higher_ranked_assumptions: FxHashSet>>, } /// "Region-bound pairs" tracks outlives relations that are known to @@ -52,6 +55,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { param_env: ty::ParamEnv<'tcx>, known_type_outlives: Vec>, extra_bounds: impl IntoIterator>, + higher_ranked_assumptions: FxHashSet>>, ) -> Self { let mut region_relation = TransitiveRelationBuilder::default(); let mut region_bound_pairs = RegionBoundPairs::default(); @@ -88,6 +92,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { known_type_outlives, free_region_map: FreeRegionMap { relation: region_relation.freeze() }, region_bound_pairs, + higher_ranked_assumptions, } } @@ -102,4 +107,10 @@ impl<'tcx> OutlivesEnvironment<'tcx> { pub fn known_type_outlives(&self) -> &[ty::PolyTypeOutlivesPredicate<'tcx>] { &self.known_type_outlives } + + pub fn higher_ranked_assumptions( + &self, + ) -> &FxHashSet>> { + &self.higher_ranked_assumptions + } } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 2a4544c1140d..db668032f1f2 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -10,6 +10,7 @@ use super::region_constraints::{RegionConstraintData, UndoLog}; use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; use crate::infer::free_regions::RegionRelations; use crate::infer::lexical_region_resolve; +use crate::infer::region_constraints::Constraint; pub mod env; pub mod for_liveness; @@ -54,18 +55,27 @@ impl<'tcx> InferCtxt<'tcx> { } }; - let storage = { + let mut storage = { let mut inner = self.inner.borrow_mut(); let inner = &mut *inner; assert!( self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(), "region_obligations not empty: {:#?}", - inner.region_obligations + inner.region_obligations, ); assert!(!UndoLogs::>::in_snapshot(&inner.undo_log)); inner.region_constraint_storage.take().expect("regions already resolved") }; + // Filter out any region-region outlives assumptions that are implied by + // coroutine well-formedness. + storage.data.constraints.retain(|(constraint, _)| match *constraint { + Constraint::RegSubReg(r1, r2) => !outlives_env + .higher_ranked_assumptions() + .contains(&ty::OutlivesPredicate(r2.into(), r1)), + _ => true, + }); + let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map()); let (lexical_region_resolutions, errors) = @@ -93,6 +103,11 @@ impl<'tcx> InferCtxt<'tcx> { "region_obligations not empty: {:#?}", self.inner.borrow().region_obligations ); + assert!( + self.inner.borrow().region_assumptions.is_empty(), + "region_assumptions not empty: {:#?}", + self.inner.borrow().region_assumptions + ); self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data() } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 43504bd77c18..2066cdd717e0 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -170,6 +170,21 @@ impl<'tcx> InferCtxt<'tcx> { std::mem::take(&mut self.inner.borrow_mut().region_obligations) } + pub fn register_region_assumption( + &self, + assumption: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, + ) { + let mut inner = self.inner.borrow_mut(); + inner.undo_log.push(UndoLog::PushRegionAssumption); + inner.region_assumptions.push(assumption); + } + + pub fn take_registered_region_assumptions( + &self, + ) -> Vec>> { + std::mem::take(&mut self.inner.borrow_mut().region_assumptions) + } + /// Process the region obligations that must be proven (during /// `regionck`) for the given `body_id`, given information about /// the region bounds in scope and so forth. @@ -220,6 +235,13 @@ impl<'tcx> InferCtxt<'tcx> { let (sup_type, sub_region) = (sup_type, sub_region).fold_with(&mut OpportunisticRegionResolver::new(self)); + if outlives_env + .higher_ranked_assumptions() + .contains(&ty::OutlivesPredicate(sup_type.into(), sub_region)) + { + continue; + } + debug!(?sup_type, ?sub_region, ?origin); let outlives = &mut TypeOutlives::new( diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index 34e649afedc6..40e4c329446d 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -28,6 +28,7 @@ pub(crate) enum UndoLog<'tcx> { RegionUnificationTable(sv::UndoLog>>), ProjectionCache(traits::UndoLog<'tcx>), PushTypeOutlivesConstraint, + PushRegionAssumption, } macro_rules! impl_from { @@ -77,6 +78,9 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { let popped = self.region_obligations.pop(); assert_matches!(popped, Some(_), "pushed region constraint but could not pop it"); } + UndoLog::PushRegionAssumption => { + self.region_assumptions.pop(); + } } } } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 2bbc48b633c8..8ce2789cb8e1 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -81,13 +81,18 @@ pub struct QueryResponse<'tcx, R> { #[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct QueryRegionConstraints<'tcx> { pub outlives: Vec>, + pub assumptions: Vec>>, } impl QueryRegionConstraints<'_> { - /// Represents an empty (trivially true) set of region - /// constraints. + /// Represents an empty (trivially true) set of region constraints. + /// + /// FIXME(higher_ranked_auto): This could still just be true if there are only assumptions? + /// Because I don't expect for us to get cases where an assumption from one query would + /// discharge a requirement from another query, which is a potential problem if we did throw + /// away these assumptions because there were no constraints. pub fn is_empty(&self) -> bool { - self.outlives.is_empty() + self.outlives.is_empty() && self.assumptions.is_empty() } } diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index 068e90b00b8d..2b33b8ac9f86 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -4,7 +4,7 @@ use rustc_infer::infer::{InferCtxt, RegionResolutionError}; use rustc_macros::extension; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, elaborate}; use crate::traits::ScrubbedTraitError; use crate::traits::outlives_bounds::InferCtxtExt; @@ -46,6 +46,11 @@ impl<'tcx> OutlivesEnvironment<'tcx> { } } + // FIXME(-Znext-trait-solver): Normalize these. + let higher_ranked_assumptions = infcx.take_registered_region_assumptions(); + let higher_ranked_assumptions = + elaborate::elaborate_outlives_assumptions(infcx.tcx, higher_ranked_assumptions); + // FIXME: This needs to be modified so that we normalize the known type // outlives obligations then elaborate them into their region/type components. // Otherwise, ` as Mirror>::Assoc: 'b` will not imply `'a: 'b` even @@ -59,6 +64,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { assumed_wf_tys, disable_implied_bounds_hack, ), + higher_ranked_assumptions, ) } } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 1a24254d57fb..670589faf9c9 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -212,8 +212,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< // Cannot use `take_registered_region_obligations` as we may compute the response // inside of a `probe` whenever we have multiple choices inside of the solver. let region_obligations = self.0.inner.borrow().region_obligations().to_owned(); + let region_assumptions = self.0.inner.borrow().region_assumptions().to_owned(); let region_constraints = self.0.with_region_constraints(|region_constraints| { - make_query_region_constraints(self.tcx, region_obligations, region_constraints) + make_query_region_constraints( + self.tcx, + region_obligations, + region_constraints, + region_assumptions, + ) }); let mut seen = FxHashSet::default(); diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index ce5a4edeaaa0..f50f01a285b5 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -461,6 +461,7 @@ fn impl_intersection_has_negative_obligation( // requirements, when proving the negated where clauses below. drop(equate_obligations); drop(infcx.take_registered_region_obligations()); + drop(infcx.take_registered_region_assumptions()); drop(infcx.take_and_reset_region_constraints()); plug_infer_with_placeholders( diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 59d3ac21387f..53518038f8d5 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -78,7 +78,10 @@ fn implied_outlives_bounds<'a, 'tcx>( bounds.retain(|bound| !bound.has_placeholders()); if !constraints.is_empty() { - let QueryRegionConstraints { outlives } = constraints; + // FIXME(higher_ranked_auto): Should we register assumptions here? + // We otherwise would get spurious errors if normalizing an implied + // outlives bound required proving some higher-ranked coroutine obl. + let QueryRegionConstraints { outlives, assumptions: _ } = constraints; let cause = ObligationCause::misc(span, body_id); for &(predicate, _) in &outlives { infcx.register_outlives_constraint(predicate, &cause); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 3b549244431d..f027ba1c5cbf 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -80,6 +80,11 @@ where pre_obligations.is_empty(), "scrape_region_constraints: incoming region obligations = {pre_obligations:#?}", ); + let pre_assumptions = infcx.take_registered_region_assumptions(); + assert!( + pre_assumptions.is_empty(), + "scrape_region_constraints: incoming region assumptions = {pre_assumptions:#?}", + ); let value = infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new(infcx); @@ -100,11 +105,13 @@ where let value = infcx.resolve_vars_if_possible(value); let region_obligations = infcx.take_registered_region_obligations(); + let region_assumptions = infcx.take_registered_region_assumptions(); let region_constraint_data = infcx.take_and_reset_region_constraints(); let region_constraints = query_response::make_query_region_constraints( infcx.tcx, region_obligations, ®ion_constraint_data, + region_assumptions, ); if region_constraints.is_empty() { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 4bdf04311a04..018e9748cf06 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -180,8 +180,9 @@ where span, )?; output.error_info = error_info; - if let Some(QueryRegionConstraints { outlives }) = output.constraints { + if let Some(QueryRegionConstraints { outlives, assumptions }) = output.constraints { region_constraints.outlives.extend(outlives.iter().cloned()); + region_constraints.assumptions.extend(assumptions.iter().cloned()); } output.constraints = if region_constraints.is_empty() { None diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index ee8cef202799..488094b15ac6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -411,18 +411,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty)); let self_ty = self.infcx.enter_forall_and_leak_universe(self_ty); - let types = self.constituent_types_for_ty(self_ty)?; - let types = self.infcx.enter_forall_and_leak_universe(types); + let constituents = self.constituent_types_for_auto_trait(self_ty)?; + let constituents = self.infcx.enter_forall_and_leak_universe(constituents); let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); - let obligations = self.collect_predicates_for_types( + let mut obligations = self.collect_predicates_for_types( obligation.param_env, - cause, + cause.clone(), obligation.recursion_depth + 1, obligation.predicate.def_id(), - types, + constituents.types, ); + // FIXME(coroutine_clone): We could uplift this into `collect_predicates_for_types` + // and do this for `Copy`/`Clone` too, but that's feature-gated so it doesn't really + // matter yet. + for assumption in constituents.assumptions { + let assumption = normalize_with_depth_to( + self, + obligation.param_env, + cause.clone(), + obligation.recursion_depth + 1, + assumption, + &mut obligations, + ); + self.infcx.register_region_assumption(assumption); + } + Ok(obligations) }) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2e65750db25d..b46fa9a44d36 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -20,6 +20,7 @@ use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::relate::TypeRelation; use rustc_infer::traits::{PredicateObligations, TraitObligation}; +use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::bug; use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds}; pub use rustc_middle::traits::select::*; @@ -2247,10 +2248,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> { /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] /// ``` #[instrument(level = "debug", skip(self), ret)] - fn constituent_types_for_ty( + fn constituent_types_for_auto_trait( &self, t: Ty<'tcx>, - ) -> Result>>, SelectionError<'tcx>> { + ) -> Result>, SelectionError<'tcx>> { Ok(match *t.kind() { ty::Uint(_) | ty::Int(_) @@ -2261,17 +2262,26 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Error(_) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Never - | ty::Char => ty::Binder::dummy(Vec::new()), + | ty::Char => { + ty::Binder::dummy(AutoImplConstituents { types: vec![], assumptions: vec![] }) + } // This branch is only for `experimental_default_bounds`. // Other foreign types were rejected earlier in // `assemble_candidates_from_auto_impls`. - ty::Foreign(..) => ty::Binder::dummy(Vec::new()), + ty::Foreign(..) => { + ty::Binder::dummy(AutoImplConstituents { types: vec![], assumptions: vec![] }) + } - ty::UnsafeBinder(ty) => ty.map_bound(|ty| vec![ty]), + ty::UnsafeBinder(ty) => { + ty.map_bound(|ty| AutoImplConstituents { types: vec![ty], assumptions: vec![] }) + } // Treat this like `struct str([u8]);` - ty::Str => ty::Binder::dummy(vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)]), + ty::Str => ty::Binder::dummy(AutoImplConstituents { + types: vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)], + assumptions: vec![], + }), ty::Placeholder(..) | ty::Dynamic(..) @@ -2283,30 +2293,41 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => { - ty::Binder::dummy(vec![element_ty]) + ty::Binder::dummy(AutoImplConstituents { + types: vec![element_ty], + assumptions: vec![], + }) } - ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => ty::Binder::dummy(vec![ty]), + ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => { + ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] }) + } ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - ty::Binder::dummy(tys.iter().collect()) + ty::Binder::dummy(AutoImplConstituents { + types: tys.iter().collect(), + assumptions: vec![], + }) } ty::Closure(_, args) => { let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty()); - ty::Binder::dummy(vec![ty]) + ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] }) } ty::CoroutineClosure(_, args) => { let ty = self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty()); - ty::Binder::dummy(vec![ty]) + ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] }) } ty::Coroutine(_, args) => { let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); let witness = args.as_coroutine().witness(); - ty::Binder::dummy([ty].into_iter().chain(iter::once(witness)).collect()) + ty::Binder::dummy(AutoImplConstituents { + types: [ty].into_iter().chain(iter::once(witness)).collect(), + assumptions: vec![], + }) } ty::CoroutineWitness(def_id, args) => self @@ -2314,16 +2335,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> { .tcx .coroutine_hidden_types(def_id) .instantiate(self.infcx.tcx, args) - .map_bound(|witness| witness.types.to_vec()), + .map_bound(|witness| AutoImplConstituents { + types: witness.types.to_vec(), + assumptions: witness.assumptions.to_vec(), + }), // For `PhantomData`, we pass `T`. ty::Adt(def, args) if def.is_phantom_data() => { - ty::Binder::dummy(args.types().collect()) + ty::Binder::dummy(AutoImplConstituents { + types: args.types().collect(), + assumptions: vec![], + }) } - ty::Adt(def, args) => { - ty::Binder::dummy(def.all_fields().map(|f| f.ty(self.tcx(), args)).collect()) - } + ty::Adt(def, args) => ty::Binder::dummy(AutoImplConstituents { + types: def.all_fields().map(|f| f.ty(self.tcx(), args)).collect(), + assumptions: vec![], + }), ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { if self.infcx.can_define_opaque_ty(def_id) { @@ -2333,7 +2361,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // which enforces a DAG between the functions requiring // the auto trait bounds in question. match self.tcx().type_of_opaque(def_id) { - Ok(ty) => ty::Binder::dummy(vec![ty.instantiate(self.tcx(), args)]), + Ok(ty) => ty::Binder::dummy(AutoImplConstituents { + types: vec![ty.instantiate(self.tcx(), args)], + assumptions: vec![], + }), Err(_) => { return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); } @@ -3113,3 +3144,9 @@ pub(crate) enum ProjectionMatchesProjection { Ambiguous, No, } + +#[derive(Clone, Debug, TypeFoldable, TypeVisitable)] +pub(crate) struct AutoImplConstituents<'tcx> { + pub types: Vec>, + pub assumptions: Vec>>, +} diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index d79777437e6c..9e487e380a9d 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -66,12 +66,14 @@ fn compute_assumptions<'tcx>( let _errors = ocx.select_all_or_error(); let region_obligations = infcx.take_registered_region_obligations(); + let region_assumptions = infcx.take_registered_region_assumptions(); let region_constraints = infcx.take_and_reset_region_constraints(); let outlives = make_query_region_constraints( tcx, region_obligations, ®ion_constraints, + region_assumptions, ) .outlives .fold_with(&mut OpportunisticRegionResolver::new(&infcx)); diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 7ffcf7b5d965..d3c951476499 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -368,3 +368,54 @@ impl> Iterator for FilterToTraits( + cx: I, + assumptions: impl IntoIterator>, +) -> HashSet> { + let mut collected = HashSet::default(); + + for ty::OutlivesPredicate(arg1, r2) in assumptions { + collected.insert(ty::OutlivesPredicate(arg1, r2)); + match arg1.kind() { + // Elaborate the components of an type, since we may have substituted a + // generic coroutine with a more specific type. + ty::GenericArgKind::Type(ty1) => { + let mut components = smallvec![]; + push_outlives_components(cx, ty1, &mut components); + for c in components { + match c { + Component::Region(r1) => { + if !r1.is_bound() { + collected.insert(ty::OutlivesPredicate(r1.into(), r2)); + } + } + + Component::Param(p) => { + let ty = Ty::new_param(cx, p); + collected.insert(ty::OutlivesPredicate(ty.into(), r2)); + } + + Component::Placeholder(p) => { + let ty = Ty::new_placeholder(cx, p); + collected.insert(ty::OutlivesPredicate(ty.into(), r2)); + } + + Component::Alias(alias_ty) => { + collected.insert(ty::OutlivesPredicate(alias_ty.to_ty(cx).into(), r2)); + } + + Component::UnresolvedInferenceVariable(_) | Component::EscapingAlias(_) => { + } + } + } + } + // Nothing to elaborate for a region. + ty::GenericArgKind::Lifetime(_) => {} + // Consts don't really participate in outlives. + ty::GenericArgKind::Const(_) => {} + } + } + + collected +} diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 8b57db23d01c..77414bec82d3 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1021,7 +1021,6 @@ ui/foreign/issue-91370-foreign-fn-block-impl.rs ui/foreign/issue-99276-same-type-lifetimes.rs ui/function-pointer/issue-102289.rs ui/functions-closures/closure-expected-type/issue-38714.rs -ui/generic-associated-types/bugs/issue-100013.rs ui/generic-associated-types/bugs/issue-80626.rs ui/generic-associated-types/bugs/issue-87735.rs ui/generic-associated-types/bugs/issue-87755.rs @@ -1099,7 +1098,6 @@ ui/generic-associated-types/issue-90729.rs ui/generic-associated-types/issue-91139.rs ui/generic-associated-types/issue-91883.rs ui/generic-associated-types/issue-92033.rs -ui/generic-associated-types/issue-92096.rs ui/generic-associated-types/issue-92280.rs ui/generic-associated-types/issue-92954.rs ui/generic-associated-types/issue-93141.rs diff --git a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs index e6c295405e2b..51945e023529 100644 --- a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs +++ b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs @@ -1,5 +1,6 @@ //@ incremental //@ edition: 2021 +//@ check-pass use std::future::*; use std::marker::PhantomData; @@ -96,8 +97,6 @@ impl Future for Next<'_, St> { fn main() { send(async { - //~^ ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `FnOnce` is not general enough Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await }); } diff --git a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr deleted file mode 100644 index 0d3ee8a93776..000000000000 --- a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error: implementation of `FnOnce` is not general enough - --> $DIR/drop-tracking-unresolved-typeck-results.rs:98:5 - | -LL | / send(async { -LL | | -LL | | -LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await -LL | | }); - | |______^ implementation of `FnOnce` is not general enough - | - = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... - = note: ...but it actually implements `FnOnce<(&(),)>` - -error: implementation of `FnOnce` is not general enough - --> $DIR/drop-tracking-unresolved-typeck-results.rs:98:5 - | -LL | / send(async { -LL | | -LL | | -LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await -LL | | }); - | |______^ implementation of `FnOnce` is not general enough - | - = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... - = note: ...but it actually implements `FnOnce<(&(),)>` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors - diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.rs b/tests/ui/async-await/return-type-notation/issue-110963-early.rs index 46b8fbf6f86e..7985f2e2de1a 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.rs @@ -1,5 +1,5 @@ //@ edition: 2021 -//@ known-bug: #110963 +//@ check-pass #![feature(return_type_notation)] diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr deleted file mode 100644 index d6c3bd12aee3..000000000000 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error: implementation of `Send` is not general enough - --> $DIR/issue-110963-early.rs:14:5 - | -LL | / spawn(async move { -LL | | let mut hc = hc; -LL | | if !hc.check().await { -LL | | log_health_check_failure().await; -LL | | } -LL | | }); - | |______^ implementation of `Send` is not general enough - | - = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... - = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` - -error: implementation of `Send` is not general enough - --> $DIR/issue-110963-early.rs:14:5 - | -LL | / spawn(async move { -LL | | let mut hc = hc; -LL | | if !hc.check().await { -LL | | log_health_check_failure().await; -LL | | } -LL | | }); - | |______^ implementation of `Send` is not general enough - | - = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... - = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors - diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.stderr b/tests/ui/generic-associated-types/bugs/issue-100013.stderr deleted file mode 100644 index ff82aebfef91..000000000000 --- a/tests/ui/generic-associated-types/bugs/issue-100013.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error: lifetime bound not satisfied - --> $DIR/issue-100013.rs:15:5 - | -LL | / async { // a coroutine checked for autotrait impl `Send` -LL | | let x = None::>; // a type referencing GAT -LL | | async {}.await; // a yield point -LL | | } - | |_____^ - | - = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) - -error: lifetime bound not satisfied - --> $DIR/issue-100013.rs:22:5 - | -LL | / async { // a coroutine checked for autotrait impl `Send` -LL | | let x = None::>; // a type referencing GAT -LL | | async {}.await; // a yield point -LL | | } - | |_____^ - | - = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) - -error: lifetime may not live long enough - --> $DIR/issue-100013.rs:23:17 - | -LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | async { // a coroutine checked for autotrait impl `Send` -LL | let x = None::>; // a type referencing GAT - | ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b` - | - = help: consider adding the following bound: `'a: 'b` - -error: lifetime bound not satisfied - --> $DIR/issue-100013.rs:29:5 - | -LL | / async { // a coroutine checked for autotrait impl `Send` -LL | | let x = None::>; // a type referencing GAT -LL | | async {}.await; // a yield point -LL | | } - | |_____^ - | - = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) - -error: aborting due to 4 previous errors - diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.rs b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs similarity index 54% rename from tests/ui/generic-associated-types/bugs/issue-100013.rs rename to tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs index ac72c29c03b9..f77626001654 100644 --- a/tests/ui/generic-associated-types/bugs/issue-100013.rs +++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs @@ -1,10 +1,6 @@ -//@ check-fail -//@ known-bug: #100013 +//@ check-pass //@ edition: 2021 -// We really should accept this, but we need implied bounds between the regions -// in a coroutine interior. - pub trait FutureIterator { type Future<'s, 'cx>: Send where @@ -18,14 +14,7 @@ fn call() -> impl Send { } } -fn call2<'a, 'b, I: FutureIterator>() -> impl Send { - async { // a coroutine checked for autotrait impl `Send` - let x = None::>; // a type referencing GAT - async {}.await; // a yield point - } -} - -fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send { +fn call2<'a: 'b, 'b, I: FutureIterator>() -> impl Send { async { // a coroutine checked for autotrait impl `Send` let x = None::>; // a type referencing GAT async {}.await; // a yield point diff --git a/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs new file mode 100644 index 000000000000..33a085ad26bc --- /dev/null +++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs @@ -0,0 +1,21 @@ +//@ edition:2018 +//@ check-pass + +use std::future::Future; + +trait Client { + type Connecting<'a>: Future + Send + where + Self: 'a; + + fn connect(&'_ self) -> Self::Connecting<'_>; +} + +fn call_connect(c: &'_ C) -> impl '_ + Future + Send +where + C: Client + Send + Sync, +{ + async move { c.connect().await } +} + +fn main() {} diff --git a/tests/ui/generic-associated-types/issue-92096.rs b/tests/ui/generic-associated-types/issue-92096.rs deleted file mode 100644 index a34c41795849..000000000000 --- a/tests/ui/generic-associated-types/issue-92096.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ edition:2018 - -use std::future::Future; - -trait Client { - type Connecting<'a>: Future + Send - where - Self: 'a; - - fn connect(&'_ self) -> Self::Connecting<'_>; -} - -fn call_connect(c: &'_ C) -> impl '_ + Future + Send -where - C: Client + Send + Sync, -{ - async move { c.connect().await } - //~^ ERROR `C` does not live long enough - // - // FIXME(#71723). This is because we infer at some point a value of - // - // impl Future::Connection<'_>> - // - // and then we somehow fail the WF check because `where C: 'a` is not known, - // but I'm not entirely sure how that comes about. -} - -fn main() {} diff --git a/tests/ui/generic-associated-types/issue-92096.stderr b/tests/ui/generic-associated-types/issue-92096.stderr deleted file mode 100644 index b9a16cf184e4..000000000000 --- a/tests/ui/generic-associated-types/issue-92096.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: `C` does not live long enough - --> $DIR/issue-92096.rs:17:5 - | -LL | async move { c.connect().await } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - From 512cf3ae88b26f50a92ebfcb69c24ca39acd72e6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Jul 2025 21:01:25 +0000 Subject: [PATCH 196/363] Gate things properly --- .../src/type_check/constraint_conversion.rs | 4 ++- .../rustc_infer/src/infer/outlives/mod.rs | 14 +++++---- .../src/infer/outlives/obligations.rs | 7 +++-- compiler/rustc_session/src/options.rs | 2 ++ ...olved-typeck-results.no_assumptions.stderr | 25 +++++++++++++++ ...drop-tracking-unresolved-typeck-results.rs | 5 ++- .../issue-110963-early.no_assumptions.stderr | 31 +++++++++++++++++++ .../issue-110963-early.rs | 5 ++- ...ine-param-outlives-2.no_assumptions.stderr | 24 ++++++++++++++ ...igher-ranked-coroutine-param-outlives-2.rs | 5 ++- ...utine-param-outlives.no_assumptions.stderr | 8 +++++ .../higher-ranked-coroutine-param-outlives.rs | 5 ++- 12 files changed, 121 insertions(+), 14 deletions(-) create mode 100644 tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr create mode 100644 tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr create mode 100644 tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.no_assumptions.stderr create mode 100644 tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.no_assumptions.stderr diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index fec3e415f75b..989d2cc70dd9 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -160,7 +160,9 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { let mut next_outlives_predicates = vec![]; for (pred, constraint_category) in outlives_predicates { // Constraint is implied by a coroutine's well-formedness. - if higher_ranked_assumptions.contains(&pred) { + if self.infcx.tcx.sess.opts.unstable_opts.higher_ranked_assumptions + && higher_ranked_assumptions.contains(&pred) + { continue; } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index db668032f1f2..19911bfbd48b 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -69,12 +69,14 @@ impl<'tcx> InferCtxt<'tcx> { // Filter out any region-region outlives assumptions that are implied by // coroutine well-formedness. - storage.data.constraints.retain(|(constraint, _)| match *constraint { - Constraint::RegSubReg(r1, r2) => !outlives_env - .higher_ranked_assumptions() - .contains(&ty::OutlivesPredicate(r2.into(), r1)), - _ => true, - }); + if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions { + storage.data.constraints.retain(|(constraint, _)| match *constraint { + Constraint::RegSubReg(r1, r2) => !outlives_env + .higher_ranked_assumptions() + .contains(&ty::OutlivesPredicate(r2.into(), r1)), + _ => true, + }); + } let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map()); diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 2066cdd717e0..1ca59c8d1301 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -235,9 +235,10 @@ impl<'tcx> InferCtxt<'tcx> { let (sup_type, sub_region) = (sup_type, sub_region).fold_with(&mut OpportunisticRegionResolver::new(self)); - if outlives_env - .higher_ranked_assumptions() - .contains(&ty::OutlivesPredicate(sup_type.into(), sub_region)) + if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions + && outlives_env + .higher_ranked_assumptions() + .contains(&ty::OutlivesPredicate(sup_type.into(), sub_region)) { continue; } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 626262c84425..2bdde2f887a3 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2256,6 +2256,8 @@ options! { environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"), has_thread_local: Option = (None, parse_opt_bool, [TRACKED], "explicitly enable the `cfg(target_thread_local)` directive"), + higher_ranked_assumptions: bool = (false, parse_bool, [TRACKED], + "allow deducing higher-ranked outlives assumptions from coroutines when proving auto traits"), hint_mostly_unused: bool = (false, parse_bool, [TRACKED], "hint that most of this crate will go unused, to minimize work for uncalled functions"), human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], diff --git a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr new file mode 100644 index 000000000000..d5560bf89203 --- /dev/null +++ b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr @@ -0,0 +1,25 @@ +error: implementation of `FnOnce` is not general enough + --> $DIR/drop-tracking-unresolved-typeck-results.rs:102:5 + | +LL | / send(async { +LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await +LL | | }); + | |______^ implementation of `FnOnce` is not general enough + | + = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... + = note: ...but it actually implements `FnOnce<(&(),)>` + +error: implementation of `FnOnce` is not general enough + --> $DIR/drop-tracking-unresolved-typeck-results.rs:102:5 + | +LL | / send(async { +LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await +LL | | }); + | |______^ implementation of `FnOnce` is not general enough + | + = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... + = note: ...but it actually implements `FnOnce<(&(),)>` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs index 51945e023529..16f929331cb4 100644 --- a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs +++ b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs @@ -1,6 +1,9 @@ //@ incremental //@ edition: 2021 -//@ check-pass +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 use std::future::*; use std::marker::PhantomData; diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr new file mode 100644 index 000000000000..bb4363649240 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr @@ -0,0 +1,31 @@ +error: implementation of `Send` is not general enough + --> $DIR/issue-110963-early.rs:17:5 + | +LL | / spawn(async move { +LL | | let mut hc = hc; +LL | | if !hc.check().await { +LL | | log_health_check_failure().await; +LL | | } +LL | | }); + | |______^ implementation of `Send` is not general enough + | + = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... + = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` + +error: implementation of `Send` is not general enough + --> $DIR/issue-110963-early.rs:17:5 + | +LL | / spawn(async move { +LL | | let mut hc = hc; +LL | | if !hc.check().await { +LL | | log_health_check_failure().await; +LL | | } +LL | | }); + | |______^ implementation of `Send` is not general enough + | + = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... + = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.rs b/tests/ui/async-await/return-type-notation/issue-110963-early.rs index 7985f2e2de1a..8c3180c01191 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.rs @@ -1,5 +1,8 @@ //@ edition: 2021 -//@ check-pass +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 #![feature(return_type_notation)] diff --git a/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.no_assumptions.stderr b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.no_assumptions.stderr new file mode 100644 index 000000000000..8b62fb6a2547 --- /dev/null +++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.no_assumptions.stderr @@ -0,0 +1,24 @@ +error: lifetime bound not satisfied + --> $DIR/higher-ranked-coroutine-param-outlives-2.rs:14:5 + | +LL | / async { // a coroutine checked for autotrait impl `Send` +LL | | let x = None::>; // a type referencing GAT +LL | | async {}.await; // a yield point +LL | | } + | |_____^ + | + = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) + +error: lifetime bound not satisfied + --> $DIR/higher-ranked-coroutine-param-outlives-2.rs:21:5 + | +LL | / async { // a coroutine checked for autotrait impl `Send` +LL | | let x = None::>; // a type referencing GAT +LL | | async {}.await; // a yield point +LL | | } + | |_____^ + | + = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) + +error: aborting due to 2 previous errors + diff --git a/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs index f77626001654..a5ed162d62c9 100644 --- a/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs +++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs @@ -1,5 +1,8 @@ -//@ check-pass //@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 pub trait FutureIterator { type Future<'s, 'cx>: Send diff --git a/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.no_assumptions.stderr b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.no_assumptions.stderr new file mode 100644 index 000000000000..f747ba9a7334 --- /dev/null +++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.no_assumptions.stderr @@ -0,0 +1,8 @@ +error: `C` does not live long enough + --> $DIR/higher-ranked-coroutine-param-outlives.rs:21:5 + | +LL | async move { c.connect().await } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs index 33a085ad26bc..5f683bd82fa4 100644 --- a/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs +++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs @@ -1,5 +1,8 @@ //@ edition:2018 -//@ check-pass +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 use std::future::Future; From 78fa79e7a642c8817b67d1c10d782c4c7b661a00 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Jul 2025 23:17:21 +0000 Subject: [PATCH 197/363] Add tests, some of them fail... --- ...-ranked-auto-trait-1.no_assumptions.stderr | 38 ++++++++++ .../async-await/higher-ranked-auto-trait-1.rs | 48 +++++++++++++ ...er-ranked-auto-trait-10.assumptions.stderr | 21 ++++++ ...ranked-auto-trait-10.no_assumptions.stderr | 21 ++++++ .../higher-ranked-auto-trait-10.rs | 35 +++++++++ ...er-ranked-auto-trait-11.assumptions.stderr | 20 ++++++ ...ranked-auto-trait-11.no_assumptions.stderr | 20 ++++++ .../higher-ranked-auto-trait-11.rs | 31 ++++++++ ...ranked-auto-trait-12.no_assumptions.stderr | 18 +++++ .../higher-ranked-auto-trait-12.rs | 40 +++++++++++ ...er-ranked-auto-trait-13.assumptions.stderr | 41 +++++++++++ ...ranked-auto-trait-13.no_assumptions.stderr | 60 ++++++++++++++++ .../higher-ranked-auto-trait-13.rs | 68 ++++++++++++++++++ ...ranked-auto-trait-14.no_assumptions.stderr | 33 +++++++++ .../higher-ranked-auto-trait-14.rs | 29 ++++++++ ...ranked-auto-trait-15.no_assumptions.stderr | 21 ++++++ .../higher-ranked-auto-trait-15.rs | 21 ++++++ ...er-ranked-auto-trait-16.assumptions.stderr | 25 +++++++ ...ranked-auto-trait-16.no_assumptions.stderr | 25 +++++++ .../higher-ranked-auto-trait-16.rs | 23 ++++++ ...ranked-auto-trait-17.no_assumptions.stderr | 29 ++++++++ .../higher-ranked-auto-trait-17.rs | 30 ++++++++ ...-ranked-auto-trait-2.no_assumptions.stderr | 49 +++++++++++++ .../async-await/higher-ranked-auto-trait-2.rs | 23 ++++++ ...-ranked-auto-trait-3.no_assumptions.stderr | 12 ++++ .../async-await/higher-ranked-auto-trait-3.rs | 72 +++++++++++++++++++ ...-ranked-auto-trait-4.no_assumptions.stderr | 10 +++ .../async-await/higher-ranked-auto-trait-4.rs | 34 +++++++++ ...-ranked-auto-trait-5.no_assumptions.stderr | 13 ++++ .../async-await/higher-ranked-auto-trait-5.rs | 54 ++++++++++++++ ...-ranked-auto-trait-6.no_assumptions.stderr | 50 +++++++++++++ .../async-await/higher-ranked-auto-trait-6.rs | 59 +++++++++++++++ ...-ranked-auto-trait-7.no_assumptions.stderr | 8 +++ .../async-await/higher-ranked-auto-trait-7.rs | 33 +++++++++ ...-ranked-auto-trait-8.no_assumptions.stderr | 10 +++ .../async-await/higher-ranked-auto-trait-8.rs | 27 +++++++ ...-ranked-auto-trait-9.no_assumptions.stderr | 11 +++ .../async-await/higher-ranked-auto-trait-9.rs | 44 ++++++++++++ 38 files changed, 1206 insertions(+) create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-1.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-1.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-10.assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-10.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-10.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-11.assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-11.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-11.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-12.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-13.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-14.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-14.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-15.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-16.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-17.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-17.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-2.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-2.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-3.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-3.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-4.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-4.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-5.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-6.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-7.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-7.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-8.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-8.rs create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-9.no_assumptions.stderr create mode 100644 tests/ui/async-await/higher-ranked-auto-trait-9.rs diff --git a/tests/ui/async-await/higher-ranked-auto-trait-1.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-1.no_assumptions.stderr new file mode 100644 index 000000000000..b298a3bf2153 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-1.no_assumptions.stderr @@ -0,0 +1,38 @@ +error[E0308]: mismatched types + --> $DIR/higher-ranked-auto-trait-1.rs:37:5 + | +LL | / async { +LL | | let _y = &(); +LL | | let _x = filter(FilterMap { +LL | | f: || async move { *_y }, +... | +LL | | drop(_x); +LL | | } + | |_____^ one type is more general than the other + | + = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}` + found `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}` + = note: no two async blocks, even if identical, have the same type + = help: consider pinning your async block and casting it to a trait object + +error[E0308]: mismatched types + --> $DIR/higher-ranked-auto-trait-1.rs:37:5 + | +LL | / async { +LL | | let _y = &(); +LL | | let _x = filter(FilterMap { +LL | | f: || async move { *_y }, +... | +LL | | drop(_x); +LL | | } + | |_____^ one type is more general than the other + | + = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}` + found `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}` + = note: no two async blocks, even if identical, have the same type + = help: consider pinning your async block and casting it to a trait object + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/higher-ranked-auto-trait-1.rs b/tests/ui/async-await/higher-ranked-auto-trait-1.rs new file mode 100644 index 000000000000..740f7e292454 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-1.rs @@ -0,0 +1,48 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 + +use std::future::Future; +use std::marker::PhantomData; + +trait Stream { + type Item; +} + +struct Filter { + pending_item: St::Item, +} + +fn filter(_: St) -> Filter { + unimplemented!(); +} + +struct FilterMap { + f: F, + pending: PhantomData, +} + +impl Stream for FilterMap +where + F: FnMut() -> Fut, + Fut: Future, +{ + type Item = (); +} + +pub fn get_foo() -> impl Future + Send { + async { + let _y = &(); + let _x = filter(FilterMap { + f: || async move { *_y }, + pending: PhantomData, + }); + async {}.await; + drop(_x); + } +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-10.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-10.assumptions.stderr new file mode 100644 index 000000000000..6fcf1b1eac17 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-10.assumptions.stderr @@ -0,0 +1,21 @@ +error: implementation of `Foo` is not general enough + --> $DIR/higher-ranked-auto-trait-10.rs:32:5 + | +LL | Box::new(async move { get_foo(x).await }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | + = note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`... + = note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2` + +error: implementation of `Foo` is not general enough + --> $DIR/higher-ranked-auto-trait-10.rs:32:5 + | +LL | Box::new(async move { get_foo(x).await }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | + = note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`... + = note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-10.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-10.no_assumptions.stderr new file mode 100644 index 000000000000..6fcf1b1eac17 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-10.no_assumptions.stderr @@ -0,0 +1,21 @@ +error: implementation of `Foo` is not general enough + --> $DIR/higher-ranked-auto-trait-10.rs:32:5 + | +LL | Box::new(async move { get_foo(x).await }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | + = note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`... + = note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2` + +error: implementation of `Foo` is not general enough + --> $DIR/higher-ranked-auto-trait-10.rs:32:5 + | +LL | Box::new(async move { get_foo(x).await }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | + = note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`... + = note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-10.rs b/tests/ui/async-await/higher-ranked-auto-trait-10.rs new file mode 100644 index 000000000000..4bfa27961abd --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-10.rs @@ -0,0 +1,35 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] known-bug: unknown +//@[no_assumptions] known-bug: #110338 + +use std::any::Any; +use std::future::Future; + +trait Foo<'a>: Sized { + type Error; + fn foo(x: &'a str) -> Result; +} + +impl<'a> Foo<'a> for &'a str { + type Error = (); + + fn foo(x: &'a str) -> Result { + Ok(x) + } +} + +async fn get_foo<'a, T>(x: &'a str) -> Result>::Error> +where + T: Foo<'a>, +{ + Foo::foo(x) +} + +fn bar<'a>(x: &'a str) -> Box> + Send + 'a> { + Box::new(async move { get_foo(x).await }) +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-11.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-11.assumptions.stderr new file mode 100644 index 000000000000..d39843f628c4 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-11.assumptions.stderr @@ -0,0 +1,20 @@ +error: lifetime may not live long enough + --> $DIR/higher-ranked-auto-trait-11.rs:27:9 + | +LL | impl<'a, T> Foo<'a> for MyType + | -- lifetime `'a` defined here +... +LL | Box::pin(async move { >::foo().await }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'a` must outlive `'static` + +error: implementation of `Send` is not general enough + --> $DIR/higher-ranked-auto-trait-11.rs:27:9 + | +LL | Box::pin(async move { >::foo().await }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough + | + = note: `Send` would have to be implemented for the type `>::Future`, for any lifetime `'0`... + = note: ...but `Send` is actually implemented for the type `>::Future`, for some specific lifetime `'1` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-11.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-11.no_assumptions.stderr new file mode 100644 index 000000000000..d39843f628c4 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-11.no_assumptions.stderr @@ -0,0 +1,20 @@ +error: lifetime may not live long enough + --> $DIR/higher-ranked-auto-trait-11.rs:27:9 + | +LL | impl<'a, T> Foo<'a> for MyType + | -- lifetime `'a` defined here +... +LL | Box::pin(async move { >::foo().await }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'a` must outlive `'static` + +error: implementation of `Send` is not general enough + --> $DIR/higher-ranked-auto-trait-11.rs:27:9 + | +LL | Box::pin(async move { >::foo().await }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough + | + = note: `Send` would have to be implemented for the type `>::Future`, for any lifetime `'0`... + = note: ...but `Send` is actually implemented for the type `>::Future`, for some specific lifetime `'1` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-11.rs b/tests/ui/async-await/higher-ranked-auto-trait-11.rs new file mode 100644 index 000000000000..3aebdd8224da --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-11.rs @@ -0,0 +1,31 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] known-bug: unknown +//@[no_assumptions] known-bug: #110338 + +use core::pin::Pin; +use std::future::Future; + +pub trait Foo<'a> { + type Future: Future; + + fn foo() -> Self::Future; +} + +struct MyType(T); + +impl<'a, T> Foo<'a> for MyType +where + T: Foo<'a>, + T::Future: Send, +{ + type Future = Pin + Send + 'a>>; + + fn foo() -> Self::Future { + Box::pin(async move { >::foo().await }) + } +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr new file mode 100644 index 000000000000..63e71cbc40c7 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr @@ -0,0 +1,18 @@ +error: implementation of `Robot` is not general enough + --> $DIR/higher-ranked-auto-trait-12.rs:31:20 + | +LL | let _my_task = this_is_send(async move { + | ____________________^ +LL | | let _my_iter = IRobot { +LL | | id: 32, +LL | | robot: source, +LL | | }; +LL | | yield_now().await; +LL | | }); + | |______^ implementation of `Robot` is not general enough + | + = note: `Box<(dyn Robot + Send + '0)>` must implement `Robot`, for any lifetime `'0`... + = note: ...but `Robot` is actually implemented for the type `Box<(dyn Robot + Send + 'static)>` + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-12.rs b/tests/ui/async-await/higher-ranked-auto-trait-12.rs new file mode 100644 index 000000000000..b1cca5cbb005 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-12.rs @@ -0,0 +1,40 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 + +pub trait Robot { + type Id; +} + +pub type DynRobot = Box + Send>; + +impl Robot for DynRobot { + type Id = u32; +} + +struct IRobot { + id: R::Id, + robot: R, +} + +// stand-in for tokio::spawn +fn this_is_send(value: T) -> T { + value +} + +async fn yield_now() {} + +fn test(source: DynRobot) { + let _my_task = this_is_send(async move { + let _my_iter = IRobot { + id: 32, + robot: source, + }; + yield_now().await; + }); +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr new file mode 100644 index 000000000000..f69218740dcc --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr @@ -0,0 +1,41 @@ +error: implementation of `Getter` is not general enough + --> $DIR/higher-ranked-auto-trait-13.rs:65:5 + | +LL | assert_send(my_send_async_method(struct_with_lifetime, data)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | + = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` + +error: implementation of `Getter` is not general enough + --> $DIR/higher-ranked-auto-trait-13.rs:65:5 + | +LL | assert_send(my_send_async_method(struct_with_lifetime, data)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | + = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: implementation of `Getter` is not general enough + --> $DIR/higher-ranked-auto-trait-13.rs:65:5 + | +LL | assert_send(my_send_async_method(struct_with_lifetime, data)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | + = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: implementation of `Getter` is not general enough + --> $DIR/higher-ranked-auto-trait-13.rs:65:5 + | +LL | assert_send(my_send_async_method(struct_with_lifetime, data)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | + = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr new file mode 100644 index 000000000000..cfbdaa8ad4be --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr @@ -0,0 +1,60 @@ +error: implementation of `Getter` is not general enough + --> $DIR/higher-ranked-auto-trait-13.rs:65:5 + | +LL | assert_send(my_send_async_method(struct_with_lifetime, data)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | + = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` + +error: implementation of `Getter` is not general enough + --> $DIR/higher-ranked-auto-trait-13.rs:65:5 + | +LL | assert_send(my_send_async_method(struct_with_lifetime, data)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | + = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: implementation of `Callable` is not general enough + --> $DIR/higher-ranked-auto-trait-13.rs:65:5 + | +LL | assert_send(my_send_async_method(struct_with_lifetime, data)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Callable` is not general enough + | + = note: `Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`... + = note: ...but `Callable<'1>` is actually implemented for the type `ConstructableImpl<'1>`, for some specific lifetime `'1` + +error: implementation of `Getter` is not general enough + --> $DIR/higher-ranked-auto-trait-13.rs:65:5 + | +LL | assert_send(my_send_async_method(struct_with_lifetime, data)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | + = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: implementation of `Getter` is not general enough + --> $DIR/higher-ranked-auto-trait-13.rs:65:5 + | +LL | assert_send(my_send_async_method(struct_with_lifetime, data)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | + = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: implementation of `Callable` is not general enough + --> $DIR/higher-ranked-auto-trait-13.rs:65:5 + | +LL | assert_send(my_send_async_method(struct_with_lifetime, data)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Callable` is not general enough + | + = note: `Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`... + = note: ...but `Callable<'1>` is actually implemented for the type `ConstructableImpl<'1>`, for some specific lifetime `'1` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-13.rs b/tests/ui/async-await/higher-ranked-auto-trait-13.rs new file mode 100644 index 000000000000..4bce0f5197f8 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-13.rs @@ -0,0 +1,68 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] known-bug: unknown +//@[no_assumptions] known-bug: #110338 + +use std::marker::PhantomData; + +trait Callable<'a>: Send + Sync { + fn callable(data: &'a [u8]); +} + +trait Getter<'a>: Send + Sync { + type ItemSize: Send + Sync; + + fn get(data: &'a [u8]); +} + +struct List<'a, A: Getter<'a>> { + data: &'a [u8], + item_size: A::ItemSize, // Removing this member causes the code to compile + phantom: PhantomData
, +} + +struct GetterImpl<'a, T: Callable<'a> + 'a> { + p: PhantomData<&'a T>, +} + +impl<'a, T: Callable<'a> + 'a> Getter<'a> for GetterImpl<'a, T> { + type ItemSize = (); + + fn get(data: &'a [u8]) { + ::callable(data); + } +} + +struct ConstructableImpl<'a> { + _data: &'a [u8], +} + +impl<'a> Callable<'a> for ConstructableImpl<'a> { + fn callable(_: &'a [u8]) {} +} + +struct StructWithLifetime<'a> { + marker: &'a PhantomData, +} + +async fn async_method() {} + +fn assert_send(_: impl Send + Sync) {} + +// This async method ought to be send, but is not +async fn my_send_async_method(_struct_with_lifetime: &mut StructWithLifetime<'_>, data: &Vec) { + let _named = + List::<'_, GetterImpl>> { data, item_size: (), phantom: PhantomData }; + // Moving the await point above the constructed of _named, causes + // the method to become send, even though _named is Send + Sync + async_method().await; + assert_send(_named); +} + +fn dummy(struct_with_lifetime: &mut StructWithLifetime<'_>, data: &Vec) { + assert_send(my_send_async_method(struct_with_lifetime, data)); +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-14.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-14.no_assumptions.stderr new file mode 100644 index 000000000000..b47db2b19ffe --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-14.no_assumptions.stderr @@ -0,0 +1,33 @@ +error: implementation of `FnOnce` is not general enough + --> $DIR/higher-ranked-auto-trait-14.rs:20:5 + | +LL | / async move { +LL | | let xs = unique_x.union(&cached) +LL | | // .copied() // works +LL | | .map(|x| *x) // error +LL | | ; +LL | | let blah = val.blah(xs.into_iter()).await; +LL | | } + | |_____^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'0 u32) -> u32` must implement `FnOnce<(&'1 u32,)>`, for any two lifetimes `'0` and `'1`... + = note: ...but it actually implements `FnOnce<(&u32,)>` + +error: implementation of `FnOnce` is not general enough + --> $DIR/higher-ranked-auto-trait-14.rs:20:5 + | +LL | / async move { +LL | | let xs = unique_x.union(&cached) +LL | | // .copied() // works +LL | | .map(|x| *x) // error +LL | | ; +LL | | let blah = val.blah(xs.into_iter()).await; +LL | | } + | |_____^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'0 u32) -> u32` must implement `FnOnce<(&'1 u32,)>`, for any two lifetimes `'0` and `'1`... + = note: ...but it actually implements `FnOnce<(&u32,)>` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-14.rs b/tests/ui/async-await/higher-ranked-auto-trait-14.rs new file mode 100644 index 000000000000..5ed12cd6e38c --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-14.rs @@ -0,0 +1,29 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 + +use std::collections::HashSet; +use std::future::Future; + +trait MyTrait { + fn blah(&self, x: impl Iterator) -> impl Future + Send; +} + +fn foo( + val: T, + unique_x: HashSet, +) -> impl Future + Send { + let cached = HashSet::new(); + async move { + let xs = unique_x.union(&cached) + // .copied() // works + .map(|x| *x) // error + ; + let blah = val.blah(xs.into_iter()).await; + } +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr new file mode 100644 index 000000000000..b4f3570d9f2d --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr @@ -0,0 +1,21 @@ +error: implementation of `FnOnce` is not general enough + --> $DIR/higher-ranked-auto-trait-15.rs:20:5 + | +LL | require_send(future); + | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'0 Vec) -> std::slice::Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... + = note: ...but it actually implements `FnOnce<(&Vec,)>` + +error: implementation of `FnOnce` is not general enough + --> $DIR/higher-ranked-auto-trait-15.rs:20:5 + | +LL | require_send(future); + | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'0 Vec) -> std::slice::Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... + = note: ...but it actually implements `FnOnce<(&Vec,)>` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-15.rs b/tests/ui/async-await/higher-ranked-auto-trait-15.rs new file mode 100644 index 000000000000..153fcac4c3ae --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-15.rs @@ -0,0 +1,21 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 + +async fn listen() { + let things: Vec> = vec![]; + for _ in things.iter().map(|n| n.iter()).flatten() { + // comment this line and everything compiles + async {}.await; + } +} + +fn require_send(_x: T) {} + +fn main() { + let future = listen(); + require_send(future); +} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr new file mode 100644 index 000000000000..412c31b1bd84 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr @@ -0,0 +1,25 @@ +error: implementation of `AsyncFnOnce` is not general enough + --> $DIR/higher-ranked-auto-trait-16.rs:18:5 + | +LL | / assert_send(async { +LL | | commit_if_ok(&mut ctxt, async |_| todo!()).await; +LL | | }); + | |______^ implementation of `AsyncFnOnce` is not general enough + | + = note: `{async closure@$DIR/higher-ranked-auto-trait-16.rs:19:33: 19:42}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... + = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>` + +error: implementation of `AsyncFnOnce` is not general enough + --> $DIR/higher-ranked-auto-trait-16.rs:18:5 + | +LL | / assert_send(async { +LL | | commit_if_ok(&mut ctxt, async |_| todo!()).await; +LL | | }); + | |______^ implementation of `AsyncFnOnce` is not general enough + | + = note: `{async closure@$DIR/higher-ranked-auto-trait-16.rs:19:33: 19:42}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... + = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr new file mode 100644 index 000000000000..412c31b1bd84 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr @@ -0,0 +1,25 @@ +error: implementation of `AsyncFnOnce` is not general enough + --> $DIR/higher-ranked-auto-trait-16.rs:18:5 + | +LL | / assert_send(async { +LL | | commit_if_ok(&mut ctxt, async |_| todo!()).await; +LL | | }); + | |______^ implementation of `AsyncFnOnce` is not general enough + | + = note: `{async closure@$DIR/higher-ranked-auto-trait-16.rs:19:33: 19:42}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... + = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>` + +error: implementation of `AsyncFnOnce` is not general enough + --> $DIR/higher-ranked-auto-trait-16.rs:18:5 + | +LL | / assert_send(async { +LL | | commit_if_ok(&mut ctxt, async |_| todo!()).await; +LL | | }); + | |______^ implementation of `AsyncFnOnce` is not general enough + | + = note: `{async closure@$DIR/higher-ranked-auto-trait-16.rs:19:33: 19:42}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... + = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-16.rs b/tests/ui/async-await/higher-ranked-auto-trait-16.rs new file mode 100644 index 000000000000..2b206f0a4c57 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-16.rs @@ -0,0 +1,23 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] known-bug: unknown +//@[no_assumptions] known-bug: #110338 + +fn assert_send(_: T) {} + +#[derive(Clone)] +struct Ctxt<'a>(&'a ()); + +async fn commit_if_ok<'a>(ctxt: &mut Ctxt<'a>, f: impl AsyncFnOnce(&mut Ctxt<'a>)) { + f(&mut ctxt.clone()).await; +} + +fn operation(mut ctxt: Ctxt<'_>) { + assert_send(async { + commit_if_ok(&mut ctxt, async |_| todo!()).await; + }); +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-17.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-17.no_assumptions.stderr new file mode 100644 index 000000000000..152900ca1ae9 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-17.no_assumptions.stderr @@ -0,0 +1,29 @@ +error: implementation of `FnOnce` is not general enough + --> $DIR/higher-ranked-auto-trait-17.rs:12:5 + | +LL | / async move { +LL | | let iter = Adaptor::new(a.iter().map(|_: &()| {})); +LL | | std::future::pending::<()>().await; +LL | | drop(iter); +LL | | } + | |_____^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'0 ())` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... + = note: ...but it actually implements `FnOnce<(&(),)>` + +error: implementation of `FnOnce` is not general enough + --> $DIR/higher-ranked-auto-trait-17.rs:12:5 + | +LL | / async move { +LL | | let iter = Adaptor::new(a.iter().map(|_: &()| {})); +LL | | std::future::pending::<()>().await; +LL | | drop(iter); +LL | | } + | |_____^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'0 ())` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... + = note: ...but it actually implements `FnOnce<(&(),)>` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-17.rs b/tests/ui/async-await/higher-ranked-auto-trait-17.rs new file mode 100644 index 000000000000..152432466c00 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-17.rs @@ -0,0 +1,30 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 + +// Using `impl Future` instead of `async to ensure that the Future is Send. +// +// In the original code `a` would be `&[T]`. For more minimization I've removed the reference. +fn foo(a: [(); 0]) -> impl std::future::Future + Send { + async move { + let iter = Adaptor::new(a.iter().map(|_: &()| {})); + std::future::pending::<()>().await; + drop(iter); + } +} + +struct Adaptor { + iter: T, + v: T::Item, +} + +impl Adaptor { + pub fn new(_: T) -> Self { + Self { iter: todo!(), v: todo!() } + } +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-2.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-2.no_assumptions.stderr new file mode 100644 index 000000000000..2fc44412b9da --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-2.no_assumptions.stderr @@ -0,0 +1,49 @@ +error: lifetime bound not satisfied + --> $DIR/higher-ranked-auto-trait-2.rs:16:9 + | +LL | / async move { +LL | | // asks for an unspecified lifetime to outlive itself? weird diagnostics +LL | | self.run(t).await; +LL | | } + | |_________^ + | + = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) + +error: lifetime bound not satisfied + --> $DIR/higher-ranked-auto-trait-2.rs:16:9 + | +LL | / async move { +LL | | // asks for an unspecified lifetime to outlive itself? weird diagnostics +LL | | self.run(t).await; +LL | | } + | |_________^ + | + = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: lifetime bound not satisfied + --> $DIR/higher-ranked-auto-trait-2.rs:16:9 + | +LL | / async move { +LL | | // asks for an unspecified lifetime to outlive itself? weird diagnostics +LL | | self.run(t).await; +LL | | } + | |_________^ + | + = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: lifetime bound not satisfied + --> $DIR/higher-ranked-auto-trait-2.rs:16:9 + | +LL | / async move { +LL | | // asks for an unspecified lifetime to outlive itself? weird diagnostics +LL | | self.run(t).await; +LL | | } + | |_________^ + | + = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-2.rs b/tests/ui/async-await/higher-ranked-auto-trait-2.rs new file mode 100644 index 000000000000..6c75597265bc --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-2.rs @@ -0,0 +1,23 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 + +use std::future::Future; + +pub trait Foo: Sync { + fn run<'a, 'b: 'a, T: Sync>(&'a self, _: &'b T) -> impl Future + 'a + Send; +} + +pub trait FooExt: Foo { + fn run_via<'a, 'b: 'a, T: Sync>(&'a self, t: &'b T) -> impl Future + 'a + Send { + async move { + // asks for an unspecified lifetime to outlive itself? weird diagnostics + self.run(t).await; + } + } +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-3.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-3.no_assumptions.stderr new file mode 100644 index 000000000000..c5c98ac807ea --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-3.no_assumptions.stderr @@ -0,0 +1,12 @@ +error: lifetime bound not satisfied + --> $DIR/higher-ranked-auto-trait-3.rs:66:9 + | +LL | / async { +LL | | self.fi_2.get_iter(cx).await; +LL | | } + | |_________^ + | + = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-3.rs b/tests/ui/async-await/higher-ranked-auto-trait-3.rs new file mode 100644 index 000000000000..d42d42366805 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-3.rs @@ -0,0 +1,72 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 + +#![feature(impl_trait_in_assoc_type)] + +use std::future::Future; + +pub trait FutureIterator: 'static { + type Iterator; + + type Future<'s, 'cx>: Future + Send + 'cx + where + 's: 'cx; + + fn get_iter<'s, 'cx>(&'s self, info: &'cx ()) -> Self::Future<'s, 'cx>; +} + +trait IterCaller: 'static { + type Future1<'cx>: Future + Send + 'cx; + type Future2<'cx>: Future + Send + 'cx; + + fn call_1<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future1<'cx> + where + 's: 'cx; + fn call_2<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future2<'cx> + where + 's: 'cx; +} + +struct UseIter { + fi_1: FI1, + fi_2: FI2, +} + +impl IterCaller for UseIter +where + FI1: FutureIterator + 'static + Send + Sync, + for<'s, 'cx> FI1::Future<'s, 'cx>: Send, + FI2: FutureIterator + 'static + Send + Sync, +{ + type Future1<'cx> = impl Future + Send + 'cx + where + Self: 'cx; + + type Future2<'cx> = impl Future + Send + 'cx + where + Self: 'cx; + + fn call_1<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future1<'cx> + where + 's: 'cx, + { + async { + self.fi_1.get_iter(cx).await; + } + } + + fn call_2<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future2<'cx> + where + 's: 'cx, + { + async { + self.fi_2.get_iter(cx).await; + } + } +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-4.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-4.no_assumptions.stderr new file mode 100644 index 000000000000..5aa5b83655a5 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-4.no_assumptions.stderr @@ -0,0 +1,10 @@ +error: higher-ranked lifetime error + --> $DIR/higher-ranked-auto-trait-4.rs:29:5 + | +LL | / async { +LL | | let _ = evil_function::().await; +LL | | } + | |_____^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-4.rs b/tests/ui/async-await/higher-ranked-auto-trait-4.rs new file mode 100644 index 000000000000..0586af41e9e2 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-4.rs @@ -0,0 +1,34 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 + +use std::future::Future; + +trait BoringTrait {} + +trait TraitWithAssocType { + type Assoc; +} + +impl TraitWithAssocType<()> for T +where + T: ?Sized + 'static, +{ + type Assoc = (); +} + +fn evil_function + ?Sized, I>() +-> impl Future> { + async { Ok(()) } +} + +fn fails_to_compile() -> impl std::future::Future + Send { + async { + let _ = evil_function::().await; + } +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr new file mode 100644 index 000000000000..8fa3c7483c89 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr @@ -0,0 +1,13 @@ +error: implementation of `Send` is not general enough + --> $DIR/higher-ranked-auto-trait-5.rs:13:5 + | +LL | / assert_send(async { +LL | | call_me.call().await; +LL | | }); + | |______^ implementation of `Send` is not general enough + | + = note: `Send` would have to be implemented for the type `&'0 str`, for any lifetime `'0`... + = note: ...but `Send` is actually implemented for the type `&'1 str`, for some specific lifetime `'1` + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-5.rs b/tests/ui/async-await/higher-ranked-auto-trait-5.rs new file mode 100644 index 000000000000..9a8b3f4357c0 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-5.rs @@ -0,0 +1,54 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 + +use std::future::Future; + +fn main() { + let call_me = Wrap(CallMeImpl { value: "test" }); + + assert_send(async { + call_me.call().await; + }); +} + +pub fn assert_send(_future: F) +where + F: Future + Send, +{ +} + +pub trait CallMe { + fn call(&self) -> impl Future + Send; +} + +struct Wrap(T); + +impl CallMe for Wrap +where + S: CallMe + Send, +{ + // adding `+ Send` to this RPIT fixes the issue + fn call(&self) -> impl Future { + self.0.call() + } +} + +#[derive(Debug, Clone, Copy)] +pub struct CallMeImpl { + value: T, +} + +impl CallMe for CallMeImpl +where + // Can replace `Send` by `ToString`, `Clone`, whatever. When removing the + // `Send` bound, the compiler produces a higher-ranked lifetime error. + T: Send + 'static, +{ + fn call(&self) -> impl Future { + async {} + } +} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr new file mode 100644 index 000000000000..d1f2d9a07530 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr @@ -0,0 +1,50 @@ +error[E0308]: mismatched types + --> $DIR/higher-ranked-auto-trait-6.rs:16:5 + | +LL | Box::new(async { new(|| async { f().await }).await }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` + found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` + = note: no two async blocks, even if identical, have the same type + = help: consider pinning your async block and casting it to a trait object + +error[E0308]: mismatched types + --> $DIR/higher-ranked-auto-trait-6.rs:16:5 + | +LL | Box::new(async { new(|| async { f().await }).await }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` + found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` + = note: no two async blocks, even if identical, have the same type + = help: consider pinning your async block and casting it to a trait object + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0308]: mismatched types + --> $DIR/higher-ranked-auto-trait-6.rs:16:5 + | +LL | Box::new(async { new(|| async { f().await }).await }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` + found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` + = note: no two async blocks, even if identical, have the same type + = help: consider pinning your async block and casting it to a trait object + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0308]: mismatched types + --> $DIR/higher-ranked-auto-trait-6.rs:16:5 + | +LL | Box::new(async { new(|| async { f().await }).await }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` + found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` + = note: no two async blocks, even if identical, have the same type + = help: consider pinning your async block and casting it to a trait object + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/higher-ranked-auto-trait-6.rs b/tests/ui/async-await/higher-ranked-auto-trait-6.rs new file mode 100644 index 000000000000..2c6adf8938df --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-6.rs @@ -0,0 +1,59 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 + +use core::future::Future; +use core::marker::PhantomData; +use core::pin::Pin; +use core::task::{Context, Poll}; + +async fn f() {} + +pub fn fail<'a>() -> Box + Send + 'a> { + Box::new(async { new(|| async { f().await }).await }) +} + +fn new(_a: A) -> F +where + A: Fn() -> B, +{ + F { _i: PhantomData } +} + +trait Stream { + type Item; +} + +struct T { + _a: PhantomData, + _b: PhantomData, +} + +impl Stream for T +where + A: Fn() -> B, +{ + type Item = B; +} + +struct F +where + A: Fn() -> B, +{ + _i: PhantomData< as Stream>::Item>, +} + +impl Future for F +where + A: Fn() -> B, +{ + type Output = (); + fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll { + unimplemented!() + } +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-7.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-7.no_assumptions.stderr new file mode 100644 index 000000000000..dcb8075566e6 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-7.no_assumptions.stderr @@ -0,0 +1,8 @@ +error: `S` does not live long enough + --> $DIR/higher-ranked-auto-trait-7.rs:26:5 + | +LL | future::<'a, S, _>(async move { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-7.rs b/tests/ui/async-await/higher-ranked-auto-trait-7.rs new file mode 100644 index 000000000000..abded5a88d3a --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-7.rs @@ -0,0 +1,33 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 + +#![allow(dropping_copy_types)] + +use std::{future::Future, marker::PhantomData}; + +trait Trait { + type Associated<'a>: Send + where + Self: 'a; +} + +fn future<'a, S: Trait + 'a, F>(f: F) -> F +where + F: Future + Send, +{ + f +} + +fn foo<'a, S: Trait + 'a>() { + future::<'a, S, _>(async move { + let result: PhantomData> = PhantomData; + async {}.await; + drop(result); + }); +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-8.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-8.no_assumptions.stderr new file mode 100644 index 000000000000..6208675117b7 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-8.no_assumptions.stderr @@ -0,0 +1,10 @@ +error: higher-ranked lifetime error + --> $DIR/higher-ranked-auto-trait-8.rs:26:5 + | +LL | needs_send(use_my_struct(second_struct)); // ERROR + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: could not prove `impl Future: Send` + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-8.rs b/tests/ui/async-await/higher-ranked-auto-trait-8.rs new file mode 100644 index 000000000000..91cef204e44b --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-8.rs @@ -0,0 +1,27 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 + +fn needs_send(_val: T) {} +async fn use_async(_val: T) {} + +struct MyStruct<'a, T: 'a> { + val: &'a T, +} + +unsafe impl<'a, T: 'a> Send for MyStruct<'a, T> {} + +async fn use_my_struct(val: MyStruct<'static, &'static u8>) { + use_async(val).await; +} + +fn main() { + let first_struct: MyStruct<'static, &'static u8> = MyStruct { val: &&26 }; + let second_struct: MyStruct<'static, &'static u8> = MyStruct { val: &&27 }; + + needs_send(first_struct); + needs_send(use_my_struct(second_struct)); // ERROR +} diff --git a/tests/ui/async-await/higher-ranked-auto-trait-9.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-9.no_assumptions.stderr new file mode 100644 index 000000000000..809cbcf0cad1 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-9.no_assumptions.stderr @@ -0,0 +1,11 @@ +error: implementation of `Debug` is not general enough + --> $DIR/higher-ranked-auto-trait-9.rs:43:50 + | +LL | let fut: &(dyn Future + Send) = &fut as _; + | ^^^^^^^^^ implementation of `Debug` is not general enough + | + = note: `(dyn Any + '0)` must implement `Debug`, for any lifetime `'0`... + = note: ...but `Debug` is actually implemented for the type `(dyn Any + 'static)` + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-9.rs b/tests/ui/async-await/higher-ranked-auto-trait-9.rs new file mode 100644 index 000000000000..66edbf23f2b2 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-auto-trait-9.rs @@ -0,0 +1,44 @@ +// Repro for . +//@ edition: 2021 +//@ revisions: assumptions no_assumptions +//@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions] check-pass +//@[no_assumptions] known-bug: #110338 + +use std::any::Any; +use std::fmt; +use std::future::Future; + +pub trait Foo { + type Item; +} + +impl Foo for F +where + Self: FnOnce() -> I, + I: fmt::Debug, +{ + type Item = I; +} + +async fn foo_item(_: F) -> F::Item { + unimplemented!() +} + +fn main() { + let fut = async { + let callback = || -> Box { unimplemented!() }; + + // Using plain fn instead of a closure fixes the error, + // though you obviously can't capture any state... + // fn callback() -> Box { + // todo!() + // } + + foo_item(callback).await; + }; + + // Removing `+ Send` bound also fixes the error, + // though at the cost of loosing `Send`ability... + let fut: &(dyn Future + Send) = &fut as _; +} From 3634f46fdb50887dd0f6877cab1d7f9cf45458af Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 15 Jul 2025 16:01:43 +0000 Subject: [PATCH 198/363] Add alias for ArgOutlivesPredicate --- .../src/type_check/constraint_conversion.rs | 6 +++--- compiler/rustc_hir_analysis/src/outlives/utils.rs | 3 +-- .../rustc_infer/src/infer/canonical/query_response.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 4 ++-- compiler/rustc_infer/src/infer/outlives/env.rs | 8 +++----- .../rustc_infer/src/infer/outlives/obligations.rs | 11 +++-------- compiler/rustc_middle/src/infer/canonical.rs | 5 ++--- compiler/rustc_middle/src/ty/context.rs | 10 +++++----- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/predicate.rs | 1 + compiler/rustc_middle/src/ty/structural_impls.rs | 2 +- compiler/rustc_trait_selection/src/solve/delegate.rs | 4 +--- .../rustc_trait_selection/src/traits/select/mod.rs | 2 +- compiler/rustc_traits/src/coroutine_witnesses.rs | 2 +- 14 files changed, 26 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 989d2cc70dd9..9bb96b94506a 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -126,9 +126,9 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { fn convert( &mut self, - predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, + predicate: ty::ArgOutlivesPredicate<'tcx>, constraint_category: ConstraintCategory<'tcx>, - higher_ranked_assumptions: &FxHashSet>>, + higher_ranked_assumptions: &FxHashSet>, ) { let tcx = self.infcx.tcx; debug!("generate: constraints at: {:#?}", self.locations); @@ -282,7 +282,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { &self, ty: Ty<'tcx>, next_outlives_predicates: &mut Vec<( - ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, + ty::ArgOutlivesPredicate<'tcx>, ConstraintCategory<'tcx>, )>, ) -> Ty<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index 301f5de9424e..99a633e2b7d1 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -7,8 +7,7 @@ use smallvec::smallvec; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred /// must be added to the struct header. -pub(crate) type RequiredPredicates<'tcx> = - FxIndexMap>, Span>; +pub(crate) type RequiredPredicates<'tcx> = FxIndexMap, Span>; /// Given a requirement `T: 'a` or `'b: 'a`, deduce the /// outlives_component and add it to `required_predicates` diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index fed569761280..6be53c948c84 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -590,7 +590,7 @@ pub fn make_query_region_constraints<'tcx>( tcx: TyCtxt<'tcx>, outlives_obligations: Vec>, region_constraints: &RegionConstraintData<'tcx>, - assumptions: Vec>>, + assumptions: Vec>, ) -> QueryRegionConstraints<'tcx> { let RegionConstraintData { constraints, verifys } = region_constraints; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 458b21da6ce9..2d269e320b64 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -154,7 +154,7 @@ pub struct InferCtxtInner<'tcx> { /// are deduced from the well-formedness of the witness's types, and are /// necessary because of the way we anonymize the regions in a coroutine, /// which may cause types to no longer be considered well-formed. - region_assumptions: Vec>>, + region_assumptions: Vec>, /// Caches for opaque type inference. opaque_type_storage: OpaqueTypeStorage<'tcx>, @@ -183,7 +183,7 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] - pub fn region_assumptions(&self) -> &[ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>] { + pub fn region_assumptions(&self) -> &[ty::ArgOutlivesPredicate<'tcx>] { &self.region_assumptions } diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 2175ff1b4ae4..47b738a40796 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -41,7 +41,7 @@ pub struct OutlivesEnvironment<'tcx> { known_type_outlives: Vec>, /// Assumptions that come from the well-formedness of coroutines that we prove /// auto trait bounds for during the type checking of this body. - higher_ranked_assumptions: FxHashSet>>, + higher_ranked_assumptions: FxHashSet>, } /// "Region-bound pairs" tracks outlives relations that are known to @@ -55,7 +55,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { param_env: ty::ParamEnv<'tcx>, known_type_outlives: Vec>, extra_bounds: impl IntoIterator>, - higher_ranked_assumptions: FxHashSet>>, + higher_ranked_assumptions: FxHashSet>, ) -> Self { let mut region_relation = TransitiveRelationBuilder::default(); let mut region_bound_pairs = RegionBoundPairs::default(); @@ -108,9 +108,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { &self.known_type_outlives } - pub fn higher_ranked_assumptions( - &self, - ) -> &FxHashSet>> { + pub fn higher_ranked_assumptions(&self) -> &FxHashSet> { &self.higher_ranked_assumptions } } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 1ca59c8d1301..a8520c0e71dd 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -84,7 +84,7 @@ use crate::traits::{ObligationCause, ObligationCauseCode}; impl<'tcx> InferCtxt<'tcx> { pub fn register_outlives_constraint( &self, - ty::OutlivesPredicate(arg, r2): ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, + ty::OutlivesPredicate(arg, r2): ty::ArgOutlivesPredicate<'tcx>, cause: &ObligationCause<'tcx>, ) { match arg.kind() { @@ -170,18 +170,13 @@ impl<'tcx> InferCtxt<'tcx> { std::mem::take(&mut self.inner.borrow_mut().region_obligations) } - pub fn register_region_assumption( - &self, - assumption: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, - ) { + pub fn register_region_assumption(&self, assumption: ty::ArgOutlivesPredicate<'tcx>) { let mut inner = self.inner.borrow_mut(); inner.undo_log.push(UndoLog::PushRegionAssumption); inner.region_assumptions.push(assumption); } - pub fn take_registered_region_assumptions( - &self, - ) -> Vec>> { + pub fn take_registered_region_assumptions(&self) -> Vec> { std::mem::take(&mut self.inner.borrow_mut().region_assumptions) } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 8ce2789cb8e1..4fe4c2dadee1 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -81,7 +81,7 @@ pub struct QueryResponse<'tcx, R> { #[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct QueryRegionConstraints<'tcx> { pub outlives: Vec>, - pub assumptions: Vec>>, + pub assumptions: Vec>, } impl QueryRegionConstraints<'_> { @@ -135,8 +135,7 @@ impl<'tcx, R> QueryResponse<'tcx, R> { } } -pub type QueryOutlivesConstraint<'tcx> = - (ty::OutlivesPredicate<'tcx, GenericArg<'tcx>>, ConstraintCategory<'tcx>); +pub type QueryOutlivesConstraint<'tcx> = (ty::ArgOutlivesPredicate<'tcx>, ConstraintCategory<'tcx>); #[derive(Default)] pub struct CanonicalParamEnvCache<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5a1d8d215d23..5570ba1d9127 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -162,7 +162,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type BoundRegion = ty::BoundRegion; type PlaceholderRegion = ty::PlaceholderRegion; - type RegionAssumptions = &'tcx ty::List>>; + type RegionAssumptions = &'tcx ty::List>; type ParamEnv = ty::ParamEnv<'tcx>; type Predicate = Predicate<'tcx>; @@ -876,7 +876,7 @@ pub struct CtxtInterners<'tcx> { offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>, valtree: InternedSet<'tcx, ty::ValTreeKind<'tcx>>, patterns: InternedSet<'tcx, List>>, - outlives: InternedSet<'tcx, List>>>, + outlives: InternedSet<'tcx, List>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -2696,7 +2696,7 @@ slice_interners!( captures: intern_captures(&'tcx ty::CapturedPlace<'tcx>), offset_of: pub mk_offset_of((VariantIdx, FieldIdx)), patterns: pub mk_patterns(Pattern<'tcx>), - outlives: pub mk_outlives(ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>), + outlives: pub mk_outlives(ty::ArgOutlivesPredicate<'tcx>), ); impl<'tcx> TyCtxt<'tcx> { @@ -3116,8 +3116,8 @@ impl<'tcx> TyCtxt<'tcx> { where I: Iterator, T: CollectAndApply< - ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, - &'tcx ty::List>>, + ty::ArgOutlivesPredicate<'tcx>, + &'tcx ty::List>, >, { T::collect_and_apply(iter, |xs| self.mk_outlives(xs)) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6e8f1e8fdd5b..a7cde2ad4854 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -88,7 +88,7 @@ pub use self::opaque_types::OpaqueTypeKey; pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ - AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate, + AliasTerm, ArgOutlivesPredicate, Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, HostEffectPredicate, NormalizesTo, OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef, diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index bc2ac42b6b1f..26f4282249e5 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -26,6 +26,7 @@ pub type SubtypePredicate<'tcx> = ir::SubtypePredicate>; pub type OutlivesPredicate<'tcx, T> = ir::OutlivesPredicate, T>; pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, ty::Region<'tcx>>; pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, Ty<'tcx>>; +pub type ArgOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>; pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>; pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>; pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 55aec0efd0f9..ab31d9434080 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -802,5 +802,5 @@ list_fold! { &'tcx ty::List> : mk_poly_existential_predicates, &'tcx ty::List> : mk_place_elems, &'tcx ty::List> : mk_patterns, - &'tcx ty::List>> : mk_outlives, + &'tcx ty::List> : mk_outlives, } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 670589faf9c9..17429e15cce0 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -206,9 +206,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect()) } - fn make_deduplicated_outlives_constraints( - &self, - ) -> Vec>> { + fn make_deduplicated_outlives_constraints(&self) -> Vec> { // Cannot use `take_registered_region_obligations` as we may compute the response // inside of a `probe` whenever we have multiple choices inside of the solver. let region_obligations = self.0.inner.borrow().region_obligations().to_owned(); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b46fa9a44d36..e05782e41fb3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -3148,5 +3148,5 @@ pub(crate) enum ProjectionMatchesProjection { #[derive(Clone, Debug, TypeFoldable, TypeVisitable)] pub(crate) struct AutoImplConstituents<'tcx> { pub types: Vec>, - pub assumptions: Vec>>, + pub assumptions: Vec>, } diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index 9e487e380a9d..87d17f3e131a 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -47,7 +47,7 @@ fn compute_assumptions<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, bound_tys: &'tcx ty::List>, -) -> &'tcx ty::List>> { +) -> &'tcx ty::List> { let infcx = tcx.infer_ctxt().build(ty::TypingMode::Analysis { defining_opaque_types_and_generators: ty::List::empty(), }); From e7f5bbe7438019ac6af84ce4f8cc04ab2df8c744 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 14 Jul 2025 17:16:47 +0530 Subject: [PATCH 199/363] remove description from rust toml struct --- src/bootstrap/src/core/config/config.rs | 4 ++-- src/bootstrap/src/core/config/toml/rust.rs | 20 +------------------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 28958b60fc32..f0bba8a191e5 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -697,7 +697,7 @@ impl Config { config.change_id = toml.change_id.inner; let Build { - mut description, + description, build, host, target, @@ -942,7 +942,7 @@ impl Config { config.rust_profile_use = flags_rust_profile_use; config.rust_profile_generate = flags_rust_profile_generate; - config.apply_rust_config(toml.rust, flags_warnings, &mut description); + config.apply_rust_config(toml.rust, flags_warnings); config.reproducible_artifacts = flags_reproducible_artifact; config.description = description; diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index 0fae235bb93f..307aa52294ba 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -36,8 +36,6 @@ define_config! { incremental: Option = "incremental", default_linker: Option = "default-linker", channel: Option = "channel", - // FIXME: Remove this field at Q2 2025, it has been replaced by build.description - description: Option = "description", musl_root: Option = "musl-root", rpath: Option = "rpath", strip: Option = "strip", @@ -320,7 +318,6 @@ pub fn check_incompatible_options_for_ci_rustc( jemalloc, rpath, channel, - description, default_linker, std_features, @@ -388,7 +385,6 @@ pub fn check_incompatible_options_for_ci_rustc( err!(current_rust_config.std_features, std_features, "rust"); warn!(current_rust_config.channel, channel, "rust"); - warn!(current_rust_config.description, description, "rust"); Ok(()) } @@ -415,12 +411,7 @@ pub(crate) fn validate_codegen_backends(backends: Vec, section: &str) -> } impl Config { - pub fn apply_rust_config( - &mut self, - toml_rust: Option, - warnings: Warnings, - description: &mut Option, - ) { + pub fn apply_rust_config(&mut self, toml_rust: Option, warnings: Warnings) { let mut debug = None; let mut rustc_debug_assertions = None; let mut std_debug_assertions = None; @@ -459,7 +450,6 @@ impl Config { randomize_layout, default_linker, channel: _, // already handled above - description: rust_description, musl_root, rpath, verbose_tests, @@ -552,14 +542,6 @@ impl Config { set(&mut self.jemalloc, jemalloc); set(&mut self.test_compare_mode, test_compare_mode); set(&mut self.backtrace, backtrace); - if rust_description.is_some() { - eprintln!( - "Warning: rust.description is deprecated. Use build.description instead." - ); - } - if description.is_none() { - *description = rust_description; - } set(&mut self.rust_dist_src, dist_src); set(&mut self.verbose_tests, verbose_tests); // in the case "false" is set explicitly, do not overwrite the command line args From 76967afd3bd491be8ac99f972bd79a7028852344 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 14 Jul 2025 17:20:10 +0530 Subject: [PATCH 200/363] remove ccache from llvm --- src/bootstrap/src/core/config/config.rs | 4 ++-- src/bootstrap/src/core/config/toml/llvm.rs | 16 +--------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index f0bba8a191e5..22a75183404f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -749,7 +749,7 @@ impl Config { compiletest_diff_tool, compiletest_use_stage0_libtest, tidy_extra_checks, - mut ccache, + ccache, exclude, } = toml.build.unwrap_or_default(); @@ -963,7 +963,7 @@ impl Config { config.channel = channel; } - config.apply_llvm_config(toml.llvm, &mut ccache); + config.apply_llvm_config(toml.llvm); config.apply_gcc_config(toml.gcc); diff --git a/src/bootstrap/src/core/config/toml/llvm.rs b/src/bootstrap/src/core/config/toml/llvm.rs index 4774e202bd83..1f0cecd145c7 100644 --- a/src/bootstrap/src/core/config/toml/llvm.rs +++ b/src/bootstrap/src/core/config/toml/llvm.rs @@ -17,8 +17,6 @@ define_config! { tests: Option = "tests", enzyme: Option = "enzyme", plugins: Option = "plugins", - // FIXME: Remove this field at Q2 2025, it has been replaced by build.ccache - ccache: Option = "ccache", static_libstdcpp: Option = "static-libstdcpp", libzstd: Option = "libzstd", ninja: Option = "ninja", @@ -97,7 +95,6 @@ pub fn check_incompatible_options_for_ci_llvm( assertions: _, tests: _, plugins, - ccache: _, static_libstdcpp: _, libzstd, ninja: _, @@ -149,11 +146,7 @@ pub fn check_incompatible_options_for_ci_llvm( } impl Config { - pub fn apply_llvm_config( - &mut self, - toml_llvm: Option, - ccache: &mut Option, - ) { + pub fn apply_llvm_config(&mut self, toml_llvm: Option) { let mut llvm_tests = None; let mut llvm_enzyme = None; let mut llvm_offload = None; @@ -168,7 +161,6 @@ impl Config { tests, enzyme, plugins, - ccache: llvm_ccache, static_libstdcpp, libzstd, ninja, @@ -191,13 +183,7 @@ impl Config { download_ci_llvm, build_config, } = llvm; - if llvm_ccache.is_some() { - eprintln!("Warning: llvm.ccache is deprecated. Use build.ccache instead."); - } - if ccache.is_none() { - *ccache = llvm_ccache; - } set(&mut self.ninja_in_file, ninja); llvm_tests = tests; llvm_enzyme = enzyme; From 3f2dc2bd1a2e0120b868911497ddbd8e43f3a9fa Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 8 Jul 2025 00:20:57 +0800 Subject: [PATCH 201/363] add `const_make_global`; err for `const_allocate` ptrs if didn't call Co-Authored-By: Ralf Jung Co-Authored-By: Oli Scherer --- compiler/rustc_const_eval/messages.ftl | 11 ++++ .../rustc_const_eval/src/const_eval/error.rs | 32 +++++++++- .../src/const_eval/eval_queries.rs | 2 +- .../src/const_eval/machine.rs | 19 ++++-- compiler/rustc_const_eval/src/errors.rs | 8 +++ .../rustc_const_eval/src/interpret/intern.rs | 58 +++++++++++++++++-- .../rustc_const_eval/src/interpret/memory.rs | 44 ++++++++++++++ .../src/util/check_validity_requirement.rs | 10 ++-- .../rustc_hir_analysis/src/check/intrinsic.rs | 3 + .../rustc_middle/src/mir/interpret/error.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + library/alloc/src/boxed/thin.rs | 7 ++- library/core/src/intrinsics/mod.rs | 9 +++ .../heap/alloc_intrinsic_nontransient.rs | 4 +- .../heap/alloc_intrinsic_uninit.32bit.stderr | 2 +- .../heap/alloc_intrinsic_uninit.64bit.stderr | 2 +- .../const-eval/heap/alloc_intrinsic_uninit.rs | 5 +- .../heap/alloc_intrinsic_untyped.rs | 1 + .../heap/alloc_intrinsic_untyped.stderr | 10 +++- .../const-eval/heap/dealloc_intrinsic.rs | 2 +- .../const-eval/heap/make-global-dangling.rs | 16 +++++ .../heap/make-global-dangling.stderr | 15 +++++ .../const-eval/heap/make-global-other.rs | 13 +++++ .../const-eval/heap/make-global-other.stderr | 9 +++ .../const-eval/heap/make-global-twice.rs | 16 +++++ .../const-eval/heap/make-global-twice.stderr | 9 +++ .../ui/consts/const-eval/heap/make-global.rs | 21 +++++++ .../heap/ptr_made_global_mutated.rs | 14 +++++ .../heap/ptr_made_global_mutated.stderr | 9 +++ .../const-eval/heap/ptr_not_made_global.rs | 19 ++++++ .../heap/ptr_not_made_global.stderr | 18 ++++++ 31 files changed, 361 insertions(+), 30 deletions(-) create mode 100644 tests/ui/consts/const-eval/heap/make-global-dangling.rs create mode 100644 tests/ui/consts/const-eval/heap/make-global-dangling.stderr create mode 100644 tests/ui/consts/const-eval/heap/make-global-other.rs create mode 100644 tests/ui/consts/const-eval/heap/make-global-other.stderr create mode 100644 tests/ui/consts/const-eval/heap/make-global-twice.rs create mode 100644 tests/ui/consts/const-eval/heap/make-global-twice.stderr create mode 100644 tests/ui/consts/const-eval/heap/make-global.rs create mode 100644 tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs create mode 100644 tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr create mode 100644 tests/ui/consts/const-eval/heap/ptr_not_made_global.rs create mode 100644 tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index b767ca9a3c25..046378840118 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -56,6 +56,17 @@ const_eval_const_context = {$kind -> *[other] {""} } +const_eval_const_heap_ptr_in_final = encountered `const_allocate` pointer in final value that was not made global + .note = use `const_make_global` to make allocated pointers immutable before returning + +const_eval_const_make_global_ptr_already_made_global = attempting to call `const_make_global` twice on the same allocation {$alloc} + +const_eval_const_make_global_ptr_is_non_heap = pointer passed to `const_make_global` does not point to a heap allocation: {$ptr} + +const_eval_const_make_global_with_dangling_ptr = pointer passed to `const_make_global` is dangling: {$ptr} + +const_eval_const_make_global_with_offset = making {$ptr} global which does not point to the beginning of an object + const_eval_copy_nonoverlapping_overlapping = `copy_nonoverlapping` called on overlapping ranges diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 08fc03d9c464..5b07b7c13c1a 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -2,7 +2,7 @@ use std::mem; use rustc_errors::{Diag, DiagArgName, DiagArgValue, DiagMessage, IntoDiagArg}; use rustc_middle::mir::AssertKind; -use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo}; +use rustc_middle::mir::interpret::{AllocId, Provenance, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::LayoutError; use rustc_middle::ty::{ConstInt, TyCtxt}; @@ -22,8 +22,22 @@ pub enum ConstEvalErrKind { ModifiedGlobal, RecursiveStatic, AssertFailure(AssertKind), - Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, + Panic { + msg: Symbol, + line: u32, + col: u32, + file: Symbol, + }, WriteThroughImmutablePointer, + /// Called `const_make_global` twice. + ConstMakeGlobalPtrAlreadyMadeGlobal(AllocId), + /// Called `const_make_global` on a non-heap pointer. + ConstMakeGlobalPtrIsNonHeap(String), + /// Called `const_make_global` on a dangling pointer. + ConstMakeGlobalWithDanglingPtr(String), + /// Called `const_make_global` on a pointer that does not start at the + /// beginning of an object. + ConstMakeGlobalWithOffset(String), } impl MachineStopType for ConstEvalErrKind { @@ -38,6 +52,12 @@ impl MachineStopType for ConstEvalErrKind { RecursiveStatic => const_eval_recursive_static, AssertFailure(x) => x.diagnostic_message(), WriteThroughImmutablePointer => const_eval_write_through_immutable_pointer, + ConstMakeGlobalPtrAlreadyMadeGlobal { .. } => { + const_eval_const_make_global_ptr_already_made_global + } + ConstMakeGlobalPtrIsNonHeap(_) => const_eval_const_make_global_ptr_is_non_heap, + ConstMakeGlobalWithDanglingPtr(_) => const_eval_const_make_global_with_dangling_ptr, + ConstMakeGlobalWithOffset(_) => const_eval_const_make_global_with_offset, } } fn add_args(self: Box, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) { @@ -51,6 +71,14 @@ impl MachineStopType for ConstEvalErrKind { Panic { msg, .. } => { adder("msg".into(), msg.into_diag_arg(&mut None)); } + ConstMakeGlobalPtrIsNonHeap(ptr) + | ConstMakeGlobalWithOffset(ptr) + | ConstMakeGlobalWithDanglingPtr(ptr) => { + adder("ptr".into(), ptr.into_diag_arg(&mut None)); + } + ConstMakeGlobalPtrAlreadyMadeGlobal(alloc) => { + adder("alloc".into(), alloc.into_diag_arg(&mut None)); + } } } } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 4bd4b4930090..32209ff43679 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -93,7 +93,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( // Since evaluation had no errors, validate the resulting constant. const_validate_mplace(ecx, &ret, cid)?; - // Only report this after validation, as validaiton produces much better diagnostics. + // Only report this after validation, as validation produces much better diagnostics. // FIXME: ensure validation always reports this and stop making interning care about it. match intern_result { diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 52fc898192ad..4e952b043fbc 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -169,13 +169,15 @@ pub type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>; #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum MemoryKind { - Heap, + Heap { was_made_global: bool }, } impl fmt::Display for MemoryKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - MemoryKind::Heap => write!(f, "heap allocation"), + MemoryKind::Heap { was_made_global } => { + write!(f, "heap allocation{}", if *was_made_global { " (made global)" } else { "" }) + } } } } @@ -184,7 +186,7 @@ impl interpret::MayLeak for MemoryKind { #[inline(always)] fn may_leak(self) -> bool { match self { - MemoryKind::Heap => false, + MemoryKind::Heap { was_made_global } => was_made_global, } } } @@ -420,7 +422,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { let ptr = ecx.allocate_ptr( Size::from_bytes(size), align, - interpret::MemoryKind::Machine(MemoryKind::Heap), + interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }), AllocInit::Uninit, )?; ecx.write_pointer(ptr, dest)?; @@ -453,10 +455,17 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ecx.deallocate_ptr( ptr, Some((size, align)), - interpret::MemoryKind::Machine(MemoryKind::Heap), + interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }), )?; } } + + sym::const_make_global => { + let ptr = ecx.read_pointer(&args[0])?; + ecx.make_const_heap_ptr_global(ptr)?; + ecx.write_pointer(ptr, dest)?; + } + // The intrinsic represents whether the value is known to the optimizer (LLVM). // We're not doing any optimizations here, so there is no optimizer that could know the value. // (We know the value here in the machine of course, but this is the runtime of that code, diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 49cd71387486..b6a64035261e 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -43,6 +43,14 @@ pub(crate) struct MutablePtrInFinal { pub kind: InternKind, } +#[derive(Diagnostic)] +#[diag(const_eval_const_heap_ptr_in_final)] +#[note] +pub(crate) struct ConstHeapPtrInFinal { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(const_eval_unstable_in_stable_exposed)] pub(crate) struct UnstableInStableExposed { diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index f0f958d069ee..85524949053c 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -31,7 +31,7 @@ use super::{ }; use crate::const_eval; use crate::const_eval::DummyMachine; -use crate::errors::NestedStaticInThreadLocal; +use crate::errors::{ConstHeapPtrInFinal, NestedStaticInThreadLocal}; pub trait CompileTimeMachine<'tcx, T> = Machine< 'tcx, @@ -55,6 +55,35 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> { } } +pub enum DisallowInternReason { + ConstHeap, +} + +/// A trait for controlling whether memory allocated in the interpreter can be interned. +/// +/// This prevents us from interning `const_allocate` pointers that have not been made +/// global through `const_make_global`. +pub trait CanIntern { + fn disallows_intern(&self) -> Option; +} + +impl CanIntern for const_eval::MemoryKind { + fn disallows_intern(&self) -> Option { + match self { + const_eval::MemoryKind::Heap { was_made_global: false } => { + Some(DisallowInternReason::ConstHeap) + } + const_eval::MemoryKind::Heap { was_made_global: true } => None, + } + } +} + +impl CanIntern for ! { + fn disallows_intern(&self) -> Option { + *self + } +} + /// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory. /// /// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the @@ -62,7 +91,7 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> { /// already mutable (as a sanity check). /// /// Returns an iterator over all relocations referred to by this allocation. -fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( +fn intern_shallow<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>( ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, mutability: Mutability, @@ -71,9 +100,26 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( trace!("intern_shallow {:?}", alloc_id); // remove allocation // FIXME(#120456) - is `swap_remove` correct? - let Some((_kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else { + let Some((kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else { return Err(()); }; + + match kind { + MemoryKind::Machine(x) if let Some(reason) = x.disallows_intern() => match reason { + // attempting to intern a `const_allocate`d pointer that was not made global via + // `const_make_global`. We emit an error here but don't return an `Err`. The `Err` + // is for pointers that we can't intern at all (i.e. dangling pointers). We still + // (recursively) intern this pointer because we don't have to worry about the + // additional paperwork involved with _not_ interning it, such as storing it in + // the dead memory map and having to deal with additional "dangling pointer" + // messages if someone tries to store the non-made-global ptr in the final value. + DisallowInternReason::ConstHeap => { + ecx.tcx.dcx().emit_err(ConstHeapPtrInFinal { span: ecx.tcx.span }); + } + }, + MemoryKind::Machine(_) | MemoryKind::Stack | MemoryKind::CallerLocation => {} + } + // Set allocation mutability as appropriate. This is used by LLVM to put things into // read-only memory, and also by Miri when evaluating other globals that // access this one. @@ -99,7 +145,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( } else { ecx.tcx.set_alloc_id_memory(alloc_id, alloc); } - Ok(alloc.0.0.provenance().ptrs().iter().map(|&(_, prov)| prov)) + Ok(alloc.inner().provenance().ptrs().iter().map(|&(_, prov)| prov)) } /// Creates a new `DefId` and feeds all the right queries to make this `DefId` @@ -181,7 +227,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval } InternKind::Static(Mutability::Not) => { ( - // Outermost allocation is mutable if `!Freeze`. + // Outermost allocation is mutable if `!Freeze` i.e. contains interior mutable types. if ret.layout.ty.is_freeze(*ecx.tcx, ecx.typing_env) { Mutability::Not } else { @@ -321,7 +367,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval /// Intern `ret`. This function assumes that `ret` references no other allocation. #[instrument(level = "debug", skip(ecx))] -pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>( +pub fn intern_const_alloc_for_constprop<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>( ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, ) -> InterpResult<'tcx, ()> { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 6414821e21d0..50578e13a7a8 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -26,6 +26,7 @@ use super::{ Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, }; +use crate::const_eval::ConstEvalErrKind; use crate::fluent_generated as fluent; #[derive(Debug, PartialEq, Copy, Clone)] @@ -311,6 +312,49 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(new_ptr) } + /// mark the `const_allocate`d pointer immutable so we can intern it. + pub fn make_const_heap_ptr_global( + &mut self, + ptr: Pointer>, + ) -> InterpResult<'tcx> + where + M: Machine<'tcx, MemoryKind = crate::const_eval::MemoryKind>, + { + let (alloc_id, offset, _) = self.ptr_get_alloc_id(ptr, 0)?; + if offset.bytes() != 0 { + return Err(ConstEvalErrKind::ConstMakeGlobalWithOffset(format!("{ptr:?}"))).into(); + } + + let not_local_heap = + matches!(self.tcx.try_get_global_alloc(alloc_id), Some(GlobalAlloc::Memory(_))); + + if not_local_heap { + return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(format!("{ptr:?}"))).into(); + } + + let (kind, alloc) = self.memory.alloc_map.get_mut_or(alloc_id, || { + Err(ConstEvalErrKind::ConstMakeGlobalWithDanglingPtr(format!("{ptr:?}"))) + })?; + + alloc.mutability = Mutability::Not; + + match kind { + MemoryKind::Stack | MemoryKind::CallerLocation => { + return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(format!("{ptr:?}"))) + .into(); + } + MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global }) => { + if *was_made_global { + return Err(ConstEvalErrKind::ConstMakeGlobalPtrAlreadyMadeGlobal(alloc_id)) + .into(); + } + *was_made_global = true; + } + } + + interp_ok(()) + } + #[instrument(skip(self), level = "debug")] pub fn deallocate_ptr( &mut self, diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 4ca39bbc68ec..1c2167a50fd2 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -52,9 +52,8 @@ fn check_validity_requirement_strict<'tcx>( let mut cx = InterpCx::new(cx.tcx(), DUMMY_SP, cx.typing_env, machine); - let allocated = cx - .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap)) - .expect("OOM: failed to allocate for uninit check"); + let allocated = + cx.allocate(ty, MemoryKind::Stack).expect("OOM: failed to allocate for uninit check"); if kind == ValidityRequirement::Zero { cx.write_bytes_ptr( @@ -185,7 +184,10 @@ pub(crate) fn validate_scalar_in_layout<'tcx>( bug!("could not compute layout of {scalar:?}:{ty:?}") }; let allocated = cx - .allocate(layout, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap)) + .allocate( + layout, + MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global: false }), + ) .expect("OOM: failed to allocate for uninit check"); cx.write_scalar(scalar, &allocated).unwrap(); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index dcab6ef1c5a5..6e5fe3823ab5 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -422,6 +422,9 @@ pub(crate) fn check_intrinsic_type( vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize], tcx.types.unit, ), + sym::const_make_global => { + (0, 0, vec![Ty::new_mut_ptr(tcx, tcx.types.u8)], Ty::new_imm_ptr(tcx, tcx.types.u8)) + } sym::ptr_offset_from => ( 1, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 71e0c943fbbb..3e68afbfabd0 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -257,7 +257,7 @@ pub enum InvalidProgramInfo<'tcx> { /// Details of why a pointer had to be in-bounds. #[derive(Debug, Copy, Clone)] pub enum CheckInAllocMsg { - /// We are access memory. + /// We are accessing memory. MemoryAccess, /// We are doing pointer arithmetic. InboundsPointerArithmetic, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b12edf426c1..599ef9aba2ab 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -715,6 +715,7 @@ symbols! { const_indexing, const_let, const_loop, + const_make_global, const_mut_refs, const_panic, const_panic_fmt, diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 21425b9846e4..1cce36606d2c 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -5,7 +5,7 @@ use core::error::Error; use core::fmt::{self, Debug, Display, Formatter}; #[cfg(not(no_global_oom_handling))] -use core::intrinsics::const_allocate; +use core::intrinsics::{const_allocate, const_make_global}; use core::marker::PhantomData; #[cfg(not(no_global_oom_handling))] use core::marker::Unsize; @@ -340,9 +340,10 @@ impl WithHeader { alloc.add(metadata_offset).cast(); // SAFETY: `*metadata_ptr` is within the allocation. metadata_ptr.write(ptr::metadata::(ptr::dangling::() as *const Dyn)); - + // SAFETY: valid heap allocation + const_make_global(alloc); // SAFETY: we have just written the metadata. - &*(metadata_ptr) + &*metadata_ptr } }; diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index c2e4b751c65f..038c705d5b50 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2533,6 +2533,15 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) // Runtime NOP } +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[miri::intrinsic_fallback_is_spec] +pub const unsafe fn const_make_global(ptr: *mut u8) -> *const u8 { + // const eval overrides this function; at runtime, it is a NOP. + ptr +} + /// Returns whether we should perform contract-checking at runtime. /// /// This is meant to be similar to the ub_checks intrinsic, in terms diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs index 83ed496ac2c2..fa49990abfd8 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs @@ -8,11 +8,11 @@ const FOO_RAW: *const i32 = foo(); const fn foo() -> &'static i32 { let t = unsafe { - let i = intrinsics::const_allocate(4, 4) as * mut i32; + let i = intrinsics::const_allocate(4, 4) as *mut i32; *i = 20; i }; - unsafe { &*t } + unsafe { &*(intrinsics::const_make_global(t as *mut u8) as *mut i32) } } fn main() { assert_eq!(*FOO, 20); diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr index 11ed0841a003..a8c7ee93971e 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr @@ -1,7 +1,7 @@ error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected an integer --> $DIR/alloc_intrinsic_uninit.rs:7:1 | -LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; +LL | const BAR: &i32 = unsafe { | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr index 691bde87d2f2..47e1c22cc2c1 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr @@ -1,7 +1,7 @@ error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected an integer --> $DIR/alloc_intrinsic_uninit.rs:7:1 | -LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; +LL | const BAR: &i32 = unsafe { | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs index ffc35ca1ddce..2736cdeed8c8 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs @@ -4,6 +4,7 @@ #![feature(const_heap)] use std::intrinsics; -const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; -//~^ ERROR: uninitialized memory +const BAR: &i32 = unsafe { //~ ERROR: uninitialized memory + &*(intrinsics::const_make_global(intrinsics::const_allocate(4, 4)) as *mut i32) +}; fn main() {} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs index 26cb69e458b6..201fa7150229 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs @@ -7,5 +7,6 @@ use std::intrinsics; const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; //~^ error: mutable pointer in final value of constant +//~| error: encountered `const_allocate` pointer in final value that was not made global fn main() {} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr index 0dc49dc3cd86..e69d27e48c81 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr @@ -1,8 +1,16 @@ +error: encountered `const_allocate` pointer in final value that was not made global + --> $DIR/alloc_intrinsic_untyped.rs:8:1 + | +LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: use `const_make_global` to make allocated pointers immutable before returning + error: encountered mutable pointer in final value of constant --> $DIR/alloc_intrinsic_untyped.rs:8:1 | LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs index 3cc035c66d33..515e12d2b771 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs @@ -12,7 +12,7 @@ const _X: () = unsafe { const Y: &u32 = unsafe { let ptr = intrinsics::const_allocate(4, 4) as *mut u32; *ptr = 42; - &*ptr + &*(intrinsics::const_make_global(ptr as *mut u8) as *const u32) }; const Z: &u32 = &42; diff --git a/tests/ui/consts/const-eval/heap/make-global-dangling.rs b/tests/ui/consts/const-eval/heap/make-global-dangling.rs new file mode 100644 index 000000000000..4099e6e13ed8 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-dangling.rs @@ -0,0 +1,16 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const Y: &u32 = unsafe { + &*(intrinsics::const_make_global(std::ptr::null_mut()) as *const u32) + //~^ error: pointer not dereferenceable +}; + +const Z: &u32 = unsafe { + &*(intrinsics::const_make_global(std::ptr::dangling_mut()) as *const u32) + //~^ error: pointer not dereferenceable +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/make-global-dangling.stderr b/tests/ui/consts/const-eval/heap/make-global-dangling.stderr new file mode 100644 index 000000000000..4a5f59b98551 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-dangling.stderr @@ -0,0 +1,15 @@ +error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got null pointer + --> $DIR/make-global-dangling.rs:7:8 + | +LL | &*(intrinsics::const_make_global(std::ptr::null_mut()) as *const u32) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here + +error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + --> $DIR/make-global-dangling.rs:12:8 + | +LL | &*(intrinsics::const_make_global(std::ptr::dangling_mut()) as *const u32) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Z` failed here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/make-global-other.rs b/tests/ui/consts/const-eval/heap/make-global-other.rs new file mode 100644 index 000000000000..dd5d27cc968c --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-other.rs @@ -0,0 +1,13 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const X: &i32 = &0; + +const Y: &i32 = unsafe { + &*(intrinsics::const_make_global(X as *const i32 as *mut u8) as *const i32) + //~^ error: pointer passed to `const_make_global` does not point to a heap allocation: ALLOC0 +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/make-global-other.stderr b/tests/ui/consts/const-eval/heap/make-global-other.stderr new file mode 100644 index 000000000000..572230afe3b4 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-other.stderr @@ -0,0 +1,9 @@ +error[E0080]: pointer passed to `const_make_global` does not point to a heap allocation: ALLOC0 + --> $DIR/make-global-other.rs:9:8 + | +LL | &*(intrinsics::const_make_global(X as *const i32 as *mut u8) as *const i32) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/make-global-twice.rs b/tests/ui/consts/const-eval/heap/make-global-twice.rs new file mode 100644 index 000000000000..36d779ad034a --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-twice.rs @@ -0,0 +1,16 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const Y: &i32 = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + let i = ptr as *mut i32; + *i = 20; + intrinsics::const_make_global(ptr); + intrinsics::const_make_global(ptr); + //~^ error: attempting to call `const_make_global` twice on the same allocation ALLOC0 + &*i +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/make-global-twice.stderr b/tests/ui/consts/const-eval/heap/make-global-twice.stderr new file mode 100644 index 000000000000..35d2385d9e07 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-twice.stderr @@ -0,0 +1,9 @@ +error[E0080]: attempting to call `const_make_global` twice on the same allocation ALLOC0 + --> $DIR/make-global-twice.rs:11:5 + | +LL | intrinsics::const_make_global(ptr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/make-global.rs b/tests/ui/consts/const-eval/heap/make-global.rs new file mode 100644 index 000000000000..b26fe2434ab8 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global.rs @@ -0,0 +1,21 @@ +//@ run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +use std::intrinsics; + +const FOO: &i32 = foo(); +const FOO_RAW: *const i32 = foo(); + +const fn foo() -> &'static i32 { + unsafe { + let ptr = intrinsics::const_allocate(4, 4); + let t = ptr as *mut i32; + *t = 20; + intrinsics::const_make_global(ptr); + &*t + } +} +fn main() { + assert_eq!(*FOO, 20); + assert_eq!(unsafe { *FOO_RAW }, 20); +} diff --git a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs new file mode 100644 index 000000000000..75f2d87d4d05 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs @@ -0,0 +1,14 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +use std::intrinsics; + +const A: &u8 = unsafe { + let ptr = intrinsics::const_allocate(1, 1); + *ptr = 1; + let ptr: *const u8 = intrinsics::const_make_global(ptr); + *(ptr as *mut u8) = 2; + //~^ error: writing to ALLOC0 which is read-only + &*ptr +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr new file mode 100644 index 000000000000..15af44b74d51 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr @@ -0,0 +1,9 @@ +error[E0080]: writing to ALLOC0 which is read-only + --> $DIR/ptr_made_global_mutated.rs:9:5 + | +LL | *(ptr as *mut u8) = 2; + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `A` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs b/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs new file mode 100644 index 000000000000..4b0499d41065 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs @@ -0,0 +1,19 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +use std::intrinsics; + +const FOO: &i32 = foo(); +//~^ error: encountered `const_allocate` pointer in final value that was not made global +const FOO_RAW: *const i32 = foo(); +//~^ error: encountered `const_allocate` pointer in final value that was not made global + +const fn foo() -> &'static i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as *mut i32; + *i = 20; + i + }; + unsafe { &*t } +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr b/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr new file mode 100644 index 000000000000..569a8be3e8ce --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr @@ -0,0 +1,18 @@ +error: encountered `const_allocate` pointer in final value that was not made global + --> $DIR/ptr_not_made_global.rs:5:1 + | +LL | const FOO: &i32 = foo(); + | ^^^^^^^^^^^^^^^ + | + = note: use `const_make_global` to make allocated pointers immutable before returning + +error: encountered `const_allocate` pointer in final value that was not made global + --> $DIR/ptr_not_made_global.rs:7:1 + | +LL | const FOO_RAW: *const i32 = foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: use `const_make_global` to make allocated pointers immutable before returning + +error: aborting due to 2 previous errors + From 44b38ca45edc4bd826f4ef5e3fb2221cbd1649cd Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 10 Jul 2025 17:54:55 +0800 Subject: [PATCH 202/363] format pointer later instead of eagerly converting to string --- .../rustc_const_eval/src/const_eval/error.rs | 12 ++++++------ .../rustc_const_eval/src/interpret/memory.rs | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 5b07b7c13c1a..3e880d020013 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -11,8 +11,8 @@ use rustc_span::{Span, Symbol}; use super::CompileTimeMachine; use crate::errors::{self, FrameNote, ReportErrorExt}; use crate::interpret::{ - ErrorHandled, Frame, InterpErrorInfo, InterpErrorKind, MachineStopType, err_inval, - err_machine_stop, + CtfeProvenance, ErrorHandled, Frame, InterpErrorInfo, InterpErrorKind, MachineStopType, + Pointer, err_inval, err_machine_stop, }; /// The CTFE machine has some custom error kinds. @@ -32,12 +32,12 @@ pub enum ConstEvalErrKind { /// Called `const_make_global` twice. ConstMakeGlobalPtrAlreadyMadeGlobal(AllocId), /// Called `const_make_global` on a non-heap pointer. - ConstMakeGlobalPtrIsNonHeap(String), + ConstMakeGlobalPtrIsNonHeap(Pointer>), /// Called `const_make_global` on a dangling pointer. - ConstMakeGlobalWithDanglingPtr(String), + ConstMakeGlobalWithDanglingPtr(Pointer>), /// Called `const_make_global` on a pointer that does not start at the /// beginning of an object. - ConstMakeGlobalWithOffset(String), + ConstMakeGlobalWithOffset(Pointer>), } impl MachineStopType for ConstEvalErrKind { @@ -74,7 +74,7 @@ impl MachineStopType for ConstEvalErrKind { ConstMakeGlobalPtrIsNonHeap(ptr) | ConstMakeGlobalWithOffset(ptr) | ConstMakeGlobalWithDanglingPtr(ptr) => { - adder("ptr".into(), ptr.into_diag_arg(&mut None)); + adder("ptr".into(), format!("{ptr:?}").into_diag_arg(&mut None)); } ConstMakeGlobalPtrAlreadyMadeGlobal(alloc) => { adder("alloc".into(), alloc.into_diag_arg(&mut None)); diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 50578e13a7a8..08682dd193d1 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -315,33 +315,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// mark the `const_allocate`d pointer immutable so we can intern it. pub fn make_const_heap_ptr_global( &mut self, - ptr: Pointer>, + ptr: Pointer>, ) -> InterpResult<'tcx> where - M: Machine<'tcx, MemoryKind = crate::const_eval::MemoryKind>, + M: Machine<'tcx, MemoryKind = crate::const_eval::MemoryKind, Provenance = CtfeProvenance>, { let (alloc_id, offset, _) = self.ptr_get_alloc_id(ptr, 0)?; if offset.bytes() != 0 { - return Err(ConstEvalErrKind::ConstMakeGlobalWithOffset(format!("{ptr:?}"))).into(); + return Err(ConstEvalErrKind::ConstMakeGlobalWithOffset(ptr)).into(); } let not_local_heap = matches!(self.tcx.try_get_global_alloc(alloc_id), Some(GlobalAlloc::Memory(_))); if not_local_heap { - return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(format!("{ptr:?}"))).into(); + return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(ptr)).into(); } - let (kind, alloc) = self.memory.alloc_map.get_mut_or(alloc_id, || { - Err(ConstEvalErrKind::ConstMakeGlobalWithDanglingPtr(format!("{ptr:?}"))) - })?; + let (kind, alloc) = self + .memory + .alloc_map + .get_mut_or(alloc_id, || Err(ConstEvalErrKind::ConstMakeGlobalWithDanglingPtr(ptr)))?; alloc.mutability = Mutability::Not; match kind { MemoryKind::Stack | MemoryKind::CallerLocation => { - return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(format!("{ptr:?}"))) - .into(); + return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(ptr)).into(); } MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global }) => { if *was_made_global { From 306928fc11a7c7805cce78660aa41347476393ca Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 14 Jul 2025 21:08:03 +0530 Subject: [PATCH 203/363] update change tracking with warning on removal of fields. --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index d888a7863bcb..f802640a42d7 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -481,4 +481,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "The current `./x suggest` implementation has been removed due to it being quite broken and a lack of maintenance bandwidth, with no prejudice against re-implementing it in a more maintainable form.", }, + ChangeInfo { + change_id: 143926, + severity: ChangeSeverity::Warning, + summary: "Removed `rust.description` and `llvm.ccache` as it was deprecated in #137723 and #136941 long time ago.", + }, ]; From fd48b7b8dd911229b635f7969e6213b5af337b7d Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 13 Jul 2025 15:11:31 +0800 Subject: [PATCH 204/363] Comment more code and make tests clearer Co-Authored-By: Ralf Jung --- .../rustc_const_eval/src/const_eval/machine.rs | 6 +++++- .../rustc_const_eval/src/interpret/intern.rs | 13 ++++++------- .../rustc_const_eval/src/interpret/memory.rs | 16 +++++++++------- .../src/util/check_validity_requirement.rs | 11 +++++------ .../heap/alloc_intrinsic_nontransient.rs | 2 +- .../const-eval/heap/alloc_intrinsic_uninit.rs | 3 ++- .../const-eval/heap/make-global-dangling.rs | 2 ++ .../const-eval/heap/make-global-dangling.stderr | 4 ++-- .../consts/const-eval/heap/make-global-other.rs | 2 ++ .../const-eval/heap/make-global-other.stderr | 2 +- .../consts/const-eval/heap/make-global-twice.rs | 2 ++ .../const-eval/heap/make-global-twice.stderr | 2 +- .../const-eval/heap/ptr_made_global_mutated.rs | 1 + .../heap/ptr_made_global_mutated.stderr | 2 +- .../const-eval/heap/ptr_not_made_global.rs | 5 +++++ .../const-eval/heap/ptr_not_made_global.stderr | 4 ++-- ...sic_untyped.rs => ptr_not_made_global_mut.rs} | 0 ...ped.stderr => ptr_not_made_global_mut.stderr} | 4 ++-- 18 files changed, 49 insertions(+), 32 deletions(-) rename tests/ui/consts/const-eval/heap/{alloc_intrinsic_untyped.rs => ptr_not_made_global_mut.rs} (100%) rename tests/ui/consts/const-eval/heap/{alloc_intrinsic_untyped.stderr => ptr_not_made_global_mut.stderr} (85%) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 4e952b043fbc..0a6bdef2225e 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -169,7 +169,11 @@ pub type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>; #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum MemoryKind { - Heap { was_made_global: bool }, + Heap { + /// Indicates whether `make_global` was called on this allocation. + /// If this is `true`, the allocation must be immutable. + was_made_global: bool, + }, } impl fmt::Display for MemoryKind { diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 85524949053c..b8fcdc9b7ef0 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -106,13 +106,12 @@ fn intern_shallow<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>( match kind { MemoryKind::Machine(x) if let Some(reason) = x.disallows_intern() => match reason { - // attempting to intern a `const_allocate`d pointer that was not made global via - // `const_make_global`. We emit an error here but don't return an `Err`. The `Err` - // is for pointers that we can't intern at all (i.e. dangling pointers). We still - // (recursively) intern this pointer because we don't have to worry about the - // additional paperwork involved with _not_ interning it, such as storing it in - // the dead memory map and having to deal with additional "dangling pointer" - // messages if someone tries to store the non-made-global ptr in the final value. + // Attempting to intern a `const_allocate`d pointer that was not made global via + // `const_make_global`. This is an error, but if we return `Err` now, things + // become inconsistent because we already removed the allocation from `alloc_map`. + // So instead we just emit an error and then continue interning as usual. + // We *could* do this check before removing the allocation from `alloc_map`, but then + // it would be much harder to ensure that we only error once for each allocation. DisallowInternReason::ConstHeap => { ecx.tcx.dcx().emit_err(ConstHeapPtrInFinal { span: ecx.tcx.span }); } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 08682dd193d1..5f9f43a320b5 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -312,7 +312,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(new_ptr) } - /// mark the `const_allocate`d pointer immutable so we can intern it. + /// Mark the `const_allocate`d allocation `ptr` points to as immutable so we can intern it. pub fn make_const_heap_ptr_global( &mut self, ptr: Pointer>, @@ -325,20 +325,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return Err(ConstEvalErrKind::ConstMakeGlobalWithOffset(ptr)).into(); } - let not_local_heap = - matches!(self.tcx.try_get_global_alloc(alloc_id), Some(GlobalAlloc::Memory(_))); - - if not_local_heap { + if matches!(self.tcx.try_get_global_alloc(alloc_id), Some(_)) { + // This points to something outside the current interpreter. return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(ptr)).into(); } + // If we can't find it in `alloc_map` it must be dangling (because we don't use + // `extra_fn_ptr_map` in const-eval). let (kind, alloc) = self .memory .alloc_map .get_mut_or(alloc_id, || Err(ConstEvalErrKind::ConstMakeGlobalWithDanglingPtr(ptr)))?; - alloc.mutability = Mutability::Not; - + // Ensure this is actually a *heap* allocation, and record it as made-global. match kind { MemoryKind::Stack | MemoryKind::CallerLocation => { return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(ptr)).into(); @@ -352,6 +351,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } + // Prevent further mutation, this is now an immutable global. + alloc.mutability = Mutability::Not; + interp_ok(()) } diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 1c2167a50fd2..b1f295987505 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -52,6 +52,7 @@ fn check_validity_requirement_strict<'tcx>( let mut cx = InterpCx::new(cx.tcx(), DUMMY_SP, cx.typing_env, machine); + // It doesn't really matter which `MemoryKind` we use here, `Stack` is the least wrong. let allocated = cx.allocate(ty, MemoryKind::Stack).expect("OOM: failed to allocate for uninit check"); @@ -183,12 +184,10 @@ pub(crate) fn validate_scalar_in_layout<'tcx>( let Ok(layout) = cx.layout_of(ty) else { bug!("could not compute layout of {scalar:?}:{ty:?}") }; - let allocated = cx - .allocate( - layout, - MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global: false }), - ) - .expect("OOM: failed to allocate for uninit check"); + + // It doesn't really matter which `MemoryKind` we use here, `Stack` is the least wrong. + let allocated = + cx.allocate(layout, MemoryKind::Stack).expect("OOM: failed to allocate for uninit check"); cx.write_scalar(scalar, &allocated).unwrap(); diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs index fa49990abfd8..af24e463b505 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs @@ -12,7 +12,7 @@ const fn foo() -> &'static i32 { *i = 20; i }; - unsafe { &*(intrinsics::const_make_global(t as *mut u8) as *mut i32) } + unsafe { &*(intrinsics::const_make_global(t as *mut u8) as *const i32) } } fn main() { assert_eq!(*FOO, 20); diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs index 2736cdeed8c8..c54115de2045 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs @@ -5,6 +5,7 @@ use std::intrinsics; const BAR: &i32 = unsafe { //~ ERROR: uninitialized memory - &*(intrinsics::const_make_global(intrinsics::const_allocate(4, 4)) as *mut i32) + // Make the pointer immutable to avoid errors related to mutable pointers in constants. + &*(intrinsics::const_make_global(intrinsics::const_allocate(4, 4)) as *const i32) }; fn main() {} diff --git a/tests/ui/consts/const-eval/heap/make-global-dangling.rs b/tests/ui/consts/const-eval/heap/make-global-dangling.rs index 4099e6e13ed8..f4c5929bc416 100644 --- a/tests/ui/consts/const-eval/heap/make-global-dangling.rs +++ b/tests/ui/consts/const-eval/heap/make-global-dangling.rs @@ -1,3 +1,5 @@ +// Ensure that we can't call `const_make_global` on dangling pointers. + #![feature(core_intrinsics)] #![feature(const_heap)] diff --git a/tests/ui/consts/const-eval/heap/make-global-dangling.stderr b/tests/ui/consts/const-eval/heap/make-global-dangling.stderr index 4a5f59b98551..48c2796d0bf2 100644 --- a/tests/ui/consts/const-eval/heap/make-global-dangling.stderr +++ b/tests/ui/consts/const-eval/heap/make-global-dangling.stderr @@ -1,11 +1,11 @@ error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got null pointer - --> $DIR/make-global-dangling.rs:7:8 + --> $DIR/make-global-dangling.rs:9:8 | LL | &*(intrinsics::const_make_global(std::ptr::null_mut()) as *const u32) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/make-global-dangling.rs:12:8 + --> $DIR/make-global-dangling.rs:14:8 | LL | &*(intrinsics::const_make_global(std::ptr::dangling_mut()) as *const u32) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Z` failed here diff --git a/tests/ui/consts/const-eval/heap/make-global-other.rs b/tests/ui/consts/const-eval/heap/make-global-other.rs index dd5d27cc968c..4e2a59de13ed 100644 --- a/tests/ui/consts/const-eval/heap/make-global-other.rs +++ b/tests/ui/consts/const-eval/heap/make-global-other.rs @@ -1,3 +1,5 @@ +// Ensure that we can't call `const_make_global` on pointers not in the current interpreter. + #![feature(core_intrinsics)] #![feature(const_heap)] diff --git a/tests/ui/consts/const-eval/heap/make-global-other.stderr b/tests/ui/consts/const-eval/heap/make-global-other.stderr index 572230afe3b4..ed0d768cf379 100644 --- a/tests/ui/consts/const-eval/heap/make-global-other.stderr +++ b/tests/ui/consts/const-eval/heap/make-global-other.stderr @@ -1,5 +1,5 @@ error[E0080]: pointer passed to `const_make_global` does not point to a heap allocation: ALLOC0 - --> $DIR/make-global-other.rs:9:8 + --> $DIR/make-global-other.rs:11:8 | LL | &*(intrinsics::const_make_global(X as *const i32 as *mut u8) as *const i32) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here diff --git a/tests/ui/consts/const-eval/heap/make-global-twice.rs b/tests/ui/consts/const-eval/heap/make-global-twice.rs index 36d779ad034a..0cd617cea3e6 100644 --- a/tests/ui/consts/const-eval/heap/make-global-twice.rs +++ b/tests/ui/consts/const-eval/heap/make-global-twice.rs @@ -1,3 +1,5 @@ +// Ensure that we can't call `const_make_global` twice. + #![feature(core_intrinsics)] #![feature(const_heap)] diff --git a/tests/ui/consts/const-eval/heap/make-global-twice.stderr b/tests/ui/consts/const-eval/heap/make-global-twice.stderr index 35d2385d9e07..95cdb9694d8b 100644 --- a/tests/ui/consts/const-eval/heap/make-global-twice.stderr +++ b/tests/ui/consts/const-eval/heap/make-global-twice.stderr @@ -1,5 +1,5 @@ error[E0080]: attempting to call `const_make_global` twice on the same allocation ALLOC0 - --> $DIR/make-global-twice.rs:11:5 + --> $DIR/make-global-twice.rs:13:5 | LL | intrinsics::const_make_global(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here diff --git a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs index 75f2d87d4d05..bea2a5949c26 100644 --- a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs +++ b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs @@ -1,3 +1,4 @@ +// Ensure that once an allocation is "made global", we can no longer mutate it. #![feature(core_intrinsics)] #![feature(const_heap)] use std::intrinsics; diff --git a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr index 15af44b74d51..0e88ea77d1ca 100644 --- a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr +++ b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr @@ -1,5 +1,5 @@ error[E0080]: writing to ALLOC0 which is read-only - --> $DIR/ptr_made_global_mutated.rs:9:5 + --> $DIR/ptr_made_global_mutated.rs:10:5 | LL | *(ptr as *mut u8) = 2; | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `A` failed here diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs b/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs index 4b0499d41065..6980e92c2189 100644 --- a/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs @@ -1,3 +1,8 @@ +// Ensure that we reject interning `const_allocate`d allocations in the final value of constants +// if they have not been made global through `const_make_global`. The pointers are made *immutable* +// to focus the test on the missing `make_global`; `ptr_not_made_global_mut.rs` covers the case +// where the pointer remains mutable. + #![feature(core_intrinsics)] #![feature(const_heap)] use std::intrinsics; diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr b/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr index 569a8be3e8ce..cb2bb1e8cd85 100644 --- a/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr @@ -1,5 +1,5 @@ error: encountered `const_allocate` pointer in final value that was not made global - --> $DIR/ptr_not_made_global.rs:5:1 + --> $DIR/ptr_not_made_global.rs:10:1 | LL | const FOO: &i32 = foo(); | ^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | const FOO: &i32 = foo(); = note: use `const_make_global` to make allocated pointers immutable before returning error: encountered `const_allocate` pointer in final value that was not made global - --> $DIR/ptr_not_made_global.rs:7:1 + --> $DIR/ptr_not_made_global.rs:12:1 | LL | const FOO_RAW: *const i32 = foo(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.rs similarity index 100% rename from tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs rename to tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.rs diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr similarity index 85% rename from tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr rename to tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr index e69d27e48c81..eae79d24797a 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr @@ -1,5 +1,5 @@ error: encountered `const_allocate` pointer in final value that was not made global - --> $DIR/alloc_intrinsic_untyped.rs:8:1 + --> $DIR/ptr_not_made_global_mut.rs:8:1 | LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; | ^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 = note: use `const_make_global` to make allocated pointers immutable before returning error: encountered mutable pointer in final value of constant - --> $DIR/alloc_intrinsic_untyped.rs:8:1 + --> $DIR/ptr_not_made_global_mut.rs:8:1 | LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; | ^^^^^^^^^^^^^^^^^^^ From 078332fdc8e11f7ff8253c019085098538ec3c2a Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Fri, 20 Jun 2025 02:48:15 +0000 Subject: [PATCH 205/363] rustdoc-json: Structured attributes Implements https://www.github.com/rust-lang/rust/issues/141358. This has 2 primary benefits: 1. For rustdoc-json consumers, they no longer need to parse strings of attributes, but it's there in a structured and normalized way. 2. For rustc contributors, the output of HIR pretty printing is no longer a versioned thing in the output. People can work on https://github.com/rust-lang/rust/issues/131229 without needing to bump `FORMAT_VERSION`. (Over time, as the attribute refractor continues, I expect we'll add new things to `rustdoc_json_types::Attribute`. But this can be done separately to the rustc changes). --- src/librustdoc/clean/types.rs | 84 +++++----------- src/librustdoc/html/render/mod.rs | 6 +- src/librustdoc/html/render/print_item.rs | 3 +- src/librustdoc/json/conversions.rs | 99 ++++++++++++++++++- src/rustdoc-json-types/lib.rs | 89 ++++++++++++++++- .../attrs/automatically_derived.rs | 2 +- tests/rustdoc-json/attrs/cold.rs | 2 +- tests/rustdoc-json/attrs/export_name_2021.rs | 2 +- tests/rustdoc-json/attrs/export_name_2024.rs | 4 +- tests/rustdoc-json/attrs/inline.rs | 6 +- tests/rustdoc-json/attrs/link_section_2021.rs | 3 +- tests/rustdoc-json/attrs/link_section_2024.rs | 3 +- tests/rustdoc-json/attrs/must_use.rs | 4 +- tests/rustdoc-json/attrs/no_mangle_2021.rs | 2 +- tests/rustdoc-json/attrs/no_mangle_2024.rs | 2 +- tests/rustdoc-json/attrs/non_exhaustive.rs | 6 +- tests/rustdoc-json/attrs/optimize.rs | 6 +- tests/rustdoc-json/attrs/repr_align.rs | 3 +- tests/rustdoc-json/attrs/repr_c.rs | 18 +++- tests/rustdoc-json/attrs/repr_c_int_enum.rs | 11 +++ tests/rustdoc-json/attrs/repr_combination.rs | 25 +++-- tests/rustdoc-json/attrs/repr_int_enum.rs | 15 ++- tests/rustdoc-json/attrs/repr_packed.rs | 8 +- tests/rustdoc-json/attrs/target_feature.rs | 25 +++-- .../rustdoc-json/enums/discriminant/struct.rs | 2 +- .../rustdoc-json/enums/discriminant/tuple.rs | 2 +- tests/rustdoc-json/keyword_private.rs | 4 +- .../visibility/doc_hidden_documented.rs | 6 +- 28 files changed, 318 insertions(+), 124 deletions(-) create mode 100644 tests/rustdoc-json/attrs/repr_c_int_enum.rs diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 3ecd41db2ddc..20babc6168b9 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -759,79 +759,48 @@ impl Item { Some(tcx.visibility(def_id)) } - fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec { - const ALLOWED_ATTRIBUTES: &[Symbol] = - &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive]; + /// Get a list of attributes excluding `#[repr]` to display. + /// + /// Only used by the HTML output-format. + fn attributes_without_repr(&self) -> Vec { self.attrs .other_attrs .iter() - .filter_map(|attr| { - if let hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) = attr { + .filter_map(|attr| match attr { + hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => { Some(format!("#[link_section = \"{name}\"]")) } - // NoMangle is special cased, as it appears in HTML output, and we want to show it in source form, not HIR printing. - // It is also used by cargo-semver-checks. - else if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr { + hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => { Some("#[no_mangle]".to_string()) - } else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr - { - Some(format!("#[export_name = \"{name}\"]")) - } else if let hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) = attr { - Some("#[non_exhaustive]".to_string()) - } else if is_json { - match attr { - // rustdoc-json stores this in `Item::deprecation`, so we - // don't want it it `Item::attrs`. - hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => None, - // We have separate pretty-printing logic for `#[repr(..)]` attributes. - hir::Attribute::Parsed(AttributeKind::Repr { .. }) => None, - // target_feature is special-cased because cargo-semver-checks uses it - hir::Attribute::Parsed(AttributeKind::TargetFeature(features, _)) => { - let mut output = String::new(); - for (i, (feature, _)) in features.iter().enumerate() { - if i != 0 { - output.push_str(", "); - } - output.push_str(&format!("enable=\"{}\"", feature.as_str())); - } - Some(format!("#[target_feature({output})]")) - } - hir::Attribute::Parsed(AttributeKind::AutomaticallyDerived(..)) => { - Some("#[automatically_derived]".to_string()) - } - _ => Some({ - let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr); - assert_eq!(s.pop(), Some('\n')); - s - }), - } - } else { - if !attr.has_any_name(ALLOWED_ATTRIBUTES) { - return None; - } - Some( - rustc_hir_pretty::attribute_to_string(&tcx, attr) - .replace("\\\n", "") - .replace('\n', "") - .replace(" ", " "), - ) } + hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => { + Some(format!("#[export_name = \"{name}\"]")) + } + hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => { + Some("#[non_exhaustive]".to_string()) + } + _ => None, }) .collect() } - pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec { - let mut attrs = self.attributes_without_repr(tcx, is_json); + /// Get a list of attributes to display on this item. + /// + /// Only used by the HTML output-format. + pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec { + let mut attrs = self.attributes_without_repr(); - if let Some(repr_attr) = self.repr(tcx, cache, is_json) { + if let Some(repr_attr) = self.repr(tcx, cache) { attrs.push(repr_attr); } attrs } /// Returns a stringified `#[repr(...)]` attribute. - pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option { - repr_attributes(tcx, cache, self.def_id()?, self.type_(), is_json) + /// + /// Only used by the HTML output-format. + pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option { + repr_attributes(tcx, cache, self.def_id()?, self.type_()) } pub fn is_doc_hidden(&self) -> bool { @@ -843,12 +812,14 @@ impl Item { } } +/// Return a string representing the `#[repr]` attribute if present. +/// +/// Only used by the HTML output-format. pub(crate) fn repr_attributes( tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId, item_type: ItemType, - is_json: bool, ) -> Option { use rustc_abi::IntegerType; @@ -865,7 +836,6 @@ pub(crate) fn repr_attributes( // Render `repr(transparent)` iff the non-1-ZST field is public or at least one // field is public in case all fields are 1-ZST fields. let render_transparent = cache.document_private - || is_json || adt .all_fields() .find(|field| { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 70f3f54e4c05..06de4944d97d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1191,7 +1191,7 @@ fn render_assoc_item( // a whitespace prefix and newline. fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display { fmt::from_fn(move |f| { - for a in it.attributes(cx.tcx(), cx.cache(), false) { + for a in it.attributes(cx.tcx(), cx.cache()) { writeln!(f, "{prefix}{a}")?; } Ok(()) @@ -1207,7 +1207,7 @@ fn render_code_attribute(code_attr: CodeAttribute, w: &mut impl fmt::Write) { // When an attribute is rendered inside a tag, it is formatted using // a div to produce a newline after it. fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) { - for attr in it.attributes(cx.tcx(), cx.cache(), false) { + for attr in it.attributes(cx.tcx(), cx.cache()) { render_code_attribute(CodeAttribute(attr), w); } } @@ -1219,7 +1219,7 @@ fn render_repr_attributes_in_code( def_id: DefId, item_type: ItemType, ) { - if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type, false) { + if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) { render_code_attribute(CodeAttribute(repr), w); } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index e33bdc0db32f..667d39e9bc2f 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1487,12 +1487,11 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { self.cx.cache(), self.def_id, ItemType::Union, - false, ) { writeln!(f, "{repr}")?; }; } else { - for a in self.it.attributes(self.cx.tcx(), self.cx.cache(), false) { + for a in self.it.attributes(self.cx.tcx(), self.cx.cache()) { writeln!(f, "{a}")?; } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index e7163bead92e..0a84d8caa30f 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -5,10 +5,12 @@ use rustc_abi::ExternAbi; use rustc_ast::ast; use rustc_attr_data_structures::{self as attrs, DeprecatedSince}; +use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_hir::{HeaderSafety, Safety}; use rustc_metadata::rendered_const; +use rustc_middle::ty::TyCtxt; use rustc_middle::{bug, ty}; use rustc_span::{Pos, kw, sym}; use rustdoc_json_types::*; @@ -39,7 +41,12 @@ impl JsonRenderer<'_> { }) .collect(); let docs = item.opt_doc_value(); - let attrs = item.attributes(self.tcx, &self.cache, true); + let attrs = item + .attrs + .other_attrs + .iter() + .filter_map(|a| maybe_from_hir_attr(a, item.item_id, self.tcx)) + .collect(); let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); let clean::ItemInner { name, item_id, .. } = *item.inner; @@ -886,3 +893,93 @@ impl FromClean for ItemKind { } } } + +/// Maybe convert a attribute from hir to json. +/// +/// Returns `None` if the attribute shouldn't be in the output. +fn maybe_from_hir_attr( + attr: &hir::Attribute, + item_id: ItemId, + tcx: TyCtxt<'_>, +) -> Option { + use attrs::AttributeKind as AK; + + let kind = match attr { + hir::Attribute::Parsed(kind) => kind, + + hir::Attribute::Unparsed(_) => { + // FIXME: We should handle `#[doc(hidden)]`. + return Some(other_attr(tcx, attr)); + } + }; + + Some(match kind { + AK::Deprecation { .. } => return None, // Handled separately into Item::deprecation. + AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"), + + AK::MustUse { reason, span: _ } => { + Attribute::MustUse { reason: reason.map(|s| s.to_string()) } + } + AK::Repr { .. } => repr_attr( + tcx, + item_id.as_def_id().expect("all items that could have #[repr] have a DefId"), + ), + AK::ExportName { name, span: _ } => Attribute::ExportName(name.to_string()), + AK::LinkSection { name, span: _ } => Attribute::LinkSection(name.to_string()), + AK::TargetFeature(features, _span) => Attribute::TargetFeature { + enable: features.iter().map(|(feat, _span)| feat.to_string()).collect(), + }, + + AK::NoMangle(_) => Attribute::NoMangle, + AK::NonExhaustive(_) => Attribute::NonExhaustive, + AK::AutomaticallyDerived(_) => Attribute::AutomaticallyDerived, + + _ => other_attr(tcx, attr), + }) +} + +fn other_attr(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Attribute { + let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr); + assert_eq!(s.pop(), Some('\n')); + Attribute::Other(s) +} + +fn repr_attr(tcx: TyCtxt<'_>, def_id: DefId) -> Attribute { + let repr = tcx.adt_def(def_id).repr(); + + let kind = if repr.c() { + ReprKind::C + } else if repr.transparent() { + ReprKind::Transparent + } else if repr.simd() { + ReprKind::Simd + } else { + ReprKind::Rust + }; + + let align = repr.align.map(|a| a.bytes()); + let packed = repr.pack.map(|p| p.bytes()); + let int = repr.int.map(format_integer_type); + + Attribute::Repr(AttributeRepr { kind, align, packed, int }) +} + +fn format_integer_type(it: rustc_abi::IntegerType) -> String { + use rustc_abi::Integer::*; + use rustc_abi::IntegerType::*; + match it { + Pointer(true) => "isize", + Pointer(false) => "usize", + Fixed(I8, true) => "i8", + Fixed(I8, false) => "u8", + Fixed(I16, true) => "i16", + Fixed(I16, false) => "u16", + Fixed(I32, true) => "i32", + Fixed(I32, false) => "u32", + Fixed(I64, true) => "i64", + Fixed(I64, false) => "u64", + Fixed(I128, true) => "i128", + Fixed(I128, false) => "u128", + } + .to_owned() +} diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 0e72ddd9db1e..6235b0e8576f 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -37,8 +37,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: Pretty printing of no_mangle attributes changed -pub const FORMAT_VERSION: u32 = 53; +// Latest feature: Structured Attributes +pub const FORMAT_VERSION: u32 = 54; /// The root of the emitted JSON blob. /// @@ -195,13 +195,94 @@ pub struct Item { /// - `#[repr(C)]` and other reprs also appear as themselves, /// though potentially with a different order: e.g. `repr(i8, C)` may become `repr(C, i8)`. /// Multiple repr attributes on the same item may be combined into an equivalent single attr. - pub attrs: Vec, + pub attrs: Vec, /// Information about the item’s deprecation, if present. pub deprecation: Option, /// The type-specific fields describing this item. pub inner: ItemEnum, } +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +/// An attribute, e.g. `#[repr(C)]` +/// +/// This doesn't include: +/// - `#[doc = "Doc Comment"]` or `/// Doc comment`. These are in [`Item::docs`] instead. +/// - `#[deprecated]`. These are in [`Item::deprecation`] instead. +pub enum Attribute { + /// `#[non_exhaustive]` + NonExhaustive, + + /// `#[must_use]` + MustUse { reason: Option }, + + /// `#[export_name = "name"]` + ExportName(String), + + /// `#[link_section = "name"]` + LinkSection(String), + + /// `#[automatically_derived]` + AutomaticallyDerived, + + /// `#[repr]` + Repr(AttributeRepr), + + /// `#[no_mangle]` + NoMangle, + + /// #[target_feature(enable = "feature1", enable = "feature2")] + TargetFeature { enable: Vec }, + + /// Something else. + /// + /// Things here are explicitly *not* covered by the [`FORMAT_VERSION`] + /// constant, and may change without bumping the format version. + /// + /// As an implementation detail, this is currently either: + /// 1. A HIR debug printing, like `"#[attr = Optimize(Speed)]"` + /// 2. The attribute as it appears in source form, like + /// `"#[optimize(speed)]"`. + Other(String), +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +/// The contents of a `#[repr(...)]` attribute. +/// +/// Used in [`Attribute::Repr`]. +pub struct AttributeRepr { + /// The representation, e.g. `#[repr(C)]`, `#[repr(transparent)]` + pub kind: ReprKind, + + /// Alignment in bytes, if explicitly specified by `#[repr(align(...)]`. + pub align: Option, + /// Alignment in bytes, if explicitly specified by `#[repr(packed(...)]]`. + pub packed: Option, + + /// The integer type for an enum descriminant, if explicitly specified. + /// + /// e.g. `"i32"`, for `#[repr(C, i32)]` + pub int: Option, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +/// The kind of `#[repr]`. +/// +/// See [AttributeRepr::kind]`. +pub enum ReprKind { + /// `#[repr(Rust)]` + /// + /// Also the default. + Rust, + /// `#[repr(C)]` + C, + /// `#[repr(transparent)] + Transparent, + /// `#[repr(simd)]` + Simd, +} + /// A range of source code. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Span { @@ -1343,7 +1424,7 @@ pub struct Static { /// Is the static `unsafe`? /// - /// This is only true if it's in an `extern` block, and not explicity marked + /// This is only true if it's in an `extern` block, and not explicitly marked /// as `safe`. /// /// ```rust diff --git a/tests/rustdoc-json/attrs/automatically_derived.rs b/tests/rustdoc-json/attrs/automatically_derived.rs index 4e1ab3d145e5..9ba310d3655b 100644 --- a/tests/rustdoc-json/attrs/automatically_derived.rs +++ b/tests/rustdoc-json/attrs/automatically_derived.rs @@ -9,5 +9,5 @@ impl Default for Manual { } } -//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["#[automatically_derived]"]' +//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["automatically_derived"]' //@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Manual" && @.inner.impl.trait.path == "Default")].attrs' '[]' diff --git a/tests/rustdoc-json/attrs/cold.rs b/tests/rustdoc-json/attrs/cold.rs index e219345d669c..ec1926e894e4 100644 --- a/tests/rustdoc-json/attrs/cold.rs +++ b/tests/rustdoc-json/attrs/cold.rs @@ -1,3 +1,3 @@ -//@ is "$.index[?(@.name=='cold_fn')].attrs" '["#[attr = Cold]"]' +//@ is "$.index[?(@.name=='cold_fn')].attrs" '[{"other": "#[attr = Cold]"}]' #[cold] pub fn cold_fn() {} diff --git a/tests/rustdoc-json/attrs/export_name_2021.rs b/tests/rustdoc-json/attrs/export_name_2021.rs index 254e9f6ef5bf..451d9b9eb375 100644 --- a/tests/rustdoc-json/attrs/export_name_2021.rs +++ b/tests/rustdoc-json/attrs/export_name_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +//@ is "$.index[?(@.name=='example')].attrs" '[{"export_name": "altered"}]' #[export_name = "altered"] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/export_name_2024.rs b/tests/rustdoc-json/attrs/export_name_2024.rs index 8129c109306c..7e398db92ab3 100644 --- a/tests/rustdoc-json/attrs/export_name_2024.rs +++ b/tests/rustdoc-json/attrs/export_name_2024.rs @@ -2,8 +2,8 @@ #![no_std] // The representation of `#[unsafe(export_name = ..)]` in rustdoc in edition 2024 -// is still `#[export_name = ..]` without the `unsafe` attribute wrapper. +// doesn't mention the `unsafe`. -//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +//@ is "$.index[?(@.name=='example')].attrs" '[{"export_name": "altered"}]' #[unsafe(export_name = "altered")] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/inline.rs b/tests/rustdoc-json/attrs/inline.rs index b9ea6ab1d10c..2aed49a48a5c 100644 --- a/tests/rustdoc-json/attrs/inline.rs +++ b/tests/rustdoc-json/attrs/inline.rs @@ -1,11 +1,11 @@ -//@ is "$.index[?(@.name=='just_inline')].attrs" '["#[attr = Inline(Hint)]"]' +//@ is "$.index[?(@.name=='just_inline')].attrs" '[{"other": "#[attr = Inline(Hint)]"}]' #[inline] pub fn just_inline() {} -//@ is "$.index[?(@.name=='inline_always')].attrs" '["#[attr = Inline(Always)]"]' +//@ is "$.index[?(@.name=='inline_always')].attrs" '[{"other": "#[attr = Inline(Always)]"}]' #[inline(always)] pub fn inline_always() {} -//@ is "$.index[?(@.name=='inline_never')].attrs" '["#[attr = Inline(Never)]"]' +//@ is "$.index[?(@.name=='inline_never')].attrs" '[{"other": "#[attr = Inline(Never)]"}]' #[inline(never)] pub fn inline_never() {} diff --git a/tests/rustdoc-json/attrs/link_section_2021.rs b/tests/rustdoc-json/attrs/link_section_2021.rs index a1312f4210b4..acd8ecd0e30c 100644 --- a/tests/rustdoc-json/attrs/link_section_2021.rs +++ b/tests/rustdoc-json/attrs/link_section_2021.rs @@ -1,6 +1,7 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]' +//@ count "$.index[?(@.name=='example')].attrs[*]" 1 +//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '".text"' #[link_section = ".text"] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/link_section_2024.rs b/tests/rustdoc-json/attrs/link_section_2024.rs index edb028451a8e..8107493229b5 100644 --- a/tests/rustdoc-json/attrs/link_section_2024.rs +++ b/tests/rustdoc-json/attrs/link_section_2024.rs @@ -4,6 +4,7 @@ // Since the 2024 edition the link_section attribute must use the unsafe qualification. // However, the unsafe qualification is not shown by rustdoc. -//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]' +//@ count "$.index[?(@.name=='example')].attrs[*]" 1 +//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '".text"' #[unsafe(link_section = ".text")] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/must_use.rs b/tests/rustdoc-json/attrs/must_use.rs index 3ca6f5a75a5a..3f924c5169ca 100644 --- a/tests/rustdoc-json/attrs/must_use.rs +++ b/tests/rustdoc-json/attrs/must_use.rs @@ -1,9 +1,9 @@ #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[attr = MustUse]"]' +//@ is "$.index[?(@.name=='example')].attrs[*].must_use.reason" null #[must_use] pub fn example() -> impl Iterator {} -//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[attr = MustUse {reason: \"does nothing if you do not use it\"}]"]' +//@ is "$.index[?(@.name=='explicit_message')].attrs[*].must_use.reason" '"does nothing if you do not use it"' #[must_use = "does nothing if you do not use it"] pub fn explicit_message() -> impl Iterator {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2021.rs b/tests/rustdoc-json/attrs/no_mangle_2021.rs index 588be7256db5..703dcb56491c 100644 --- a/tests/rustdoc-json/attrs/no_mangle_2021.rs +++ b/tests/rustdoc-json/attrs/no_mangle_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["no_mangle"]' #[no_mangle] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2024.rs b/tests/rustdoc-json/attrs/no_mangle_2024.rs index 0d500e20e6c5..8af00eeda6bb 100644 --- a/tests/rustdoc-json/attrs/no_mangle_2024.rs +++ b/tests/rustdoc-json/attrs/no_mangle_2024.rs @@ -4,6 +4,6 @@ // The representation of `#[unsafe(no_mangle)]` in rustdoc in edition 2024 // is still `#[no_mangle]` without the `unsafe` attribute wrapper. -//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["no_mangle"]' #[unsafe(no_mangle)] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/non_exhaustive.rs b/tests/rustdoc-json/attrs/non_exhaustive.rs index b95f1a8171fd..e4e6c8fd53ba 100644 --- a/tests/rustdoc-json/attrs/non_exhaustive.rs +++ b/tests/rustdoc-json/attrs/non_exhaustive.rs @@ -1,18 +1,18 @@ #![no_std] -//@ is "$.index[?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]"]' +//@ is "$.index[?(@.name=='MyEnum')].attrs" '["non_exhaustive"]' #[non_exhaustive] pub enum MyEnum { First, } pub enum NonExhaustiveVariant { - //@ is "$.index[?(@.name=='Variant')].attrs" '["#[non_exhaustive]"]' + //@ is "$.index[?(@.name=='Variant')].attrs" '["non_exhaustive"]' #[non_exhaustive] Variant(i64), } -//@ is "$.index[?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]"]' +//@ is "$.index[?(@.name=='MyStruct')].attrs" '["non_exhaustive"]' #[non_exhaustive] pub struct MyStruct { pub x: i64, diff --git a/tests/rustdoc-json/attrs/optimize.rs b/tests/rustdoc-json/attrs/optimize.rs index 0bed0ad18c31..5988120ab2f7 100644 --- a/tests/rustdoc-json/attrs/optimize.rs +++ b/tests/rustdoc-json/attrs/optimize.rs @@ -1,13 +1,13 @@ #![feature(optimize_attribute)] -//@ is "$.index[?(@.name=='speed')].attrs" '["#[attr = Optimize(Speed)]"]' +//@ is "$.index[?(@.name=='speed')].attrs" '[{"other": "#[attr = Optimize(Speed)]"}]' #[optimize(speed)] pub fn speed() {} -//@ is "$.index[?(@.name=='size')].attrs" '["#[attr = Optimize(Size)]"]' +//@ is "$.index[?(@.name=='size')].attrs" '[{"other": "#[attr = Optimize(Size)]"}]' #[optimize(size)] pub fn size() {} -//@ is "$.index[?(@.name=='none')].attrs" '["#[attr = Optimize(DoNotOptimize)]"]' +//@ is "$.index[?(@.name=='none')].attrs" '[{"other": "#[attr = Optimize(DoNotOptimize)]"}]' #[optimize(none)] pub fn none() {} diff --git a/tests/rustdoc-json/attrs/repr_align.rs b/tests/rustdoc-json/attrs/repr_align.rs index c6debda7f1c9..f9d3417c4857 100644 --- a/tests/rustdoc-json/attrs/repr_align.rs +++ b/tests/rustdoc-json/attrs/repr_align.rs @@ -1,6 +1,7 @@ #![no_std] -//@ is "$.index[?(@.name=='Aligned')].attrs" '["#[repr(align(4))]"]' +//@ count "$.index[?(@.name=='Aligned')].attrs[*]" 1 +//@ is "$.index[?(@.name=='Aligned')].attrs[*].repr.align" 4 #[repr(align(4))] pub struct Aligned { a: i8, diff --git a/tests/rustdoc-json/attrs/repr_c.rs b/tests/rustdoc-json/attrs/repr_c.rs index e6219413f308..89dbc16cb2a9 100644 --- a/tests/rustdoc-json/attrs/repr_c.rs +++ b/tests/rustdoc-json/attrs/repr_c.rs @@ -1,16 +1,28 @@ #![no_std] -//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '["#[repr(C)]"]' +//@ count "$.index[?(@.name=='ReprCStruct')].attrs" 1 +//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.kind" '"c"' +//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.int" null +//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.packed" null +//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.align" null #[repr(C)] pub struct ReprCStruct(pub i64); -//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '["#[repr(C)]"]' +//@ count "$.index[?(@.name=='ReprCEnum')].attrs" 1 +//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.kind" '"c"' +//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.int" null +//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.packed" null +//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.align" null #[repr(C)] pub enum ReprCEnum { First, } -//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '["#[repr(C)]"]' +//@ count "$.index[?(@.name=='ReprCUnion')].attrs" 1 +//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.kind" '"c"' +//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.int" null +//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.packed" null +//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.align" null #[repr(C)] pub union ReprCUnion { pub left: i64, diff --git a/tests/rustdoc-json/attrs/repr_c_int_enum.rs b/tests/rustdoc-json/attrs/repr_c_int_enum.rs new file mode 100644 index 000000000000..e90bcf2b5c61 --- /dev/null +++ b/tests/rustdoc-json/attrs/repr_c_int_enum.rs @@ -0,0 +1,11 @@ +//@ count "$.index[?(@.name=='Foo')].attrs" 1 +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.kind" '"c"' +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"u8"' +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.packed" null +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.align" 16 +#[repr(C, u8)] +#[repr(align(16))] +pub enum Foo { + A(bool) = b'A', + B(char) = b'C', +} diff --git a/tests/rustdoc-json/attrs/repr_combination.rs b/tests/rustdoc-json/attrs/repr_combination.rs index 6fe29c5eac09..bd4a8563b6f2 100644 --- a/tests/rustdoc-json/attrs/repr_combination.rs +++ b/tests/rustdoc-json/attrs/repr_combination.rs @@ -1,35 +1,34 @@ #![no_std] // Combinations of `#[repr(..)]` attributes. -// Rustdoc JSON emits normalized output, regardless of the original source. -//@ is "$.index[?(@.name=='ReprCI8')].attrs" '["#[repr(C, i8)]"]' +//@ is "$.index[?(@.name=='ReprCI8')].attrs" '[{"repr":{"align":null,"int":"i8","kind":"c","packed":null}}]' #[repr(C, i8)] pub enum ReprCI8 { First, } -//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '["#[repr(C, i16)]"]' +//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '[{"repr":{"align":null,"int":"i16","kind":"c","packed":null}}]' #[repr(C)] #[repr(i16)] pub enum SeparateReprCI16 { First, } -//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '["#[repr(C, usize)]"]' +//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '[{"repr":{"align":null,"int":"usize","kind":"c","packed":null}}]' #[repr(usize, C)] pub enum ReversedReprCUsize { First, } -//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '["#[repr(C, packed(1))]"]' +//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":1}}]' #[repr(C, packed)] pub struct ReprCPacked { a: i8, b: i64, } -//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '["#[repr(C, packed(2))]"]' +//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":2}}]' #[repr(C)] #[repr(packed(2))] pub struct SeparateReprCPacked { @@ -37,21 +36,21 @@ pub struct SeparateReprCPacked { b: i64, } -//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '["#[repr(C, packed(2))]"]' +//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":2}}]' #[repr(packed(2), C)] pub struct ReversedReprCPacked { a: i8, b: i64, } -//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '["#[repr(C, align(16))]"]' +//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '[{"repr":{"align":16,"int":null,"kind":"c","packed":null}}]' #[repr(C, align(16))] pub struct ReprCAlign { a: i8, b: i64, } -//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '["#[repr(C, align(2))]"]' +//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '[{"repr":{"align":2,"int":null,"kind":"c","packed":null}}]' #[repr(C)] #[repr(align(2))] pub struct SeparateReprCAlign { @@ -59,25 +58,25 @@ pub struct SeparateReprCAlign { b: i64, } -//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '["#[repr(C, align(2))]"]' +//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '[{"repr":{"align":2,"int":null,"kind":"c","packed":null}}]' #[repr(align(2), C)] pub struct ReversedReprCAlign { a: i8, b: i64, } -//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]' +//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '[{"repr":{"align":16,"int":"isize","kind":"c","packed":null}}]' #[repr(C, align(16), isize)] pub enum AlignedExplicitRepr { First, } -//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]' +//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '[{"repr":{"align":16,"int":"isize","kind":"c","packed":null}}]' #[repr(isize, C, align(16))] pub enum ReorderedAlignedExplicitRepr { First, } -//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[repr(transparent)]"]' +//@ is "$.index[?(@.name=='Transparent')].attrs" '[{"repr":{"align":null,"int":null,"kind":"transparent","packed":null}}]' #[repr(transparent)] pub struct Transparent(i64); diff --git a/tests/rustdoc-json/attrs/repr_int_enum.rs b/tests/rustdoc-json/attrs/repr_int_enum.rs index 9b09f341d4fe..79e17f53ad90 100644 --- a/tests/rustdoc-json/attrs/repr_int_enum.rs +++ b/tests/rustdoc-json/attrs/repr_int_enum.rs @@ -1,18 +1,27 @@ #![no_std] -//@ is "$.index[?(@.name=='I8')].attrs" '["#[repr(i8)]"]' +//@ is "$.index[?(@.name=='I8')].attrs[*].repr.int" '"i8"' +//@ is "$.index[?(@.name=='I8')].attrs[*].repr.kind" '"rust"' +//@ is "$.index[?(@.name=='I8')].attrs[*].repr.align" null +//@ is "$.index[?(@.name=='I8')].attrs[*].repr.packed" null #[repr(i8)] pub enum I8 { First, } -//@ is "$.index[?(@.name=='I32')].attrs" '["#[repr(i32)]"]' +//@ is "$.index[?(@.name=='I32')].attrs[*].repr.int" '"i32"' +//@ is "$.index[?(@.name=='I32')].attrs[*].repr.kind" '"rust"' +//@ is "$.index[?(@.name=='I32')].attrs[*].repr.align" null +//@ is "$.index[?(@.name=='I32')].attrs[*].repr.packed" null #[repr(i32)] pub enum I32 { First, } -//@ is "$.index[?(@.name=='Usize')].attrs" '["#[repr(usize)]"]' +//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.int" '"usize"' +//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.kind" '"rust"' +//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.align" null +//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.packed" null #[repr(usize)] pub enum Usize { First, diff --git a/tests/rustdoc-json/attrs/repr_packed.rs b/tests/rustdoc-json/attrs/repr_packed.rs index 9f3fd86c4b03..ab573835b45c 100644 --- a/tests/rustdoc-json/attrs/repr_packed.rs +++ b/tests/rustdoc-json/attrs/repr_packed.rs @@ -1,16 +1,18 @@ #![no_std] // Note the normalization: -// `#[repr(packed)]` in source becomes `#[repr(packed(1))]` in rustdoc JSON. +// `#[repr(packed)]` in source becomes `{"repr": {"packed": 1, ...}}` in rustdoc JSON. // -//@ is "$.index[?(@.name=='Packed')].attrs" '["#[repr(packed(1))]"]' +//@ is "$.index[?(@.name=='Packed')].attrs[*].repr.packed" 1 +//@ is "$.index[?(@.name=='Packed')].attrs[*].repr.kind" '"rust"' #[repr(packed)] pub struct Packed { a: i8, b: i64, } -//@ is "$.index[?(@.name=='PackedAligned')].attrs" '["#[repr(packed(4))]"]' +//@ is "$.index[?(@.name=='PackedAligned')].attrs[*].repr.packed" 4 +//@ is "$.index[?(@.name=='PackedAligned')].attrs[*].repr.kind" '"rust"' #[repr(packed(4))] pub struct PackedAligned { a: i8, diff --git a/tests/rustdoc-json/attrs/target_feature.rs b/tests/rustdoc-json/attrs/target_feature.rs index 01bc4f54d322..efe3752c1660 100644 --- a/tests/rustdoc-json/attrs/target_feature.rs +++ b/tests/rustdoc-json/attrs/target_feature.rs @@ -1,38 +1,49 @@ -//@ is "$.index[?(@.name=='test1')].attrs" '["#[target_feature(enable=\"avx\")]"]' //@ is "$.index[?(@.name=='test1')].inner.function.header.is_unsafe" false +//@ count "$.index[?(@.name=='test1')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test1')].attrs[*].target_feature.enable" '["avx"]' #[target_feature(enable = "avx")] pub fn test1() {} -//@ is "$.index[?(@.name=='test2')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\")]"]' //@ is "$.index[?(@.name=='test2')].inner.function.header.is_unsafe" false +//@ count "$.index[?(@.name=='test2')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test2')].attrs[*].target_feature.enable" '["avx", "avx2"]' #[target_feature(enable = "avx,avx2")] pub fn test2() {} -//@ is "$.index[?(@.name=='test3')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\")]"]' //@ is "$.index[?(@.name=='test3')].inner.function.header.is_unsafe" false +//@ count "$.index[?(@.name=='test3')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test3')].attrs[*].target_feature.enable" '["avx", "avx2"]' #[target_feature(enable = "avx", enable = "avx2")] pub fn test3() {} -//@ is "$.index[?(@.name=='test4')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\", enable=\"avx512f\")]"]' //@ is "$.index[?(@.name=='test4')].inner.function.header.is_unsafe" false +//@ count "$.index[?(@.name=='test4')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test4')].attrs[*].target_feature.enable" '["avx", "avx2", "avx512f"]' #[target_feature(enable = "avx", enable = "avx2,avx512f")] pub fn test4() {} -//@ is "$.index[?(@.name=='test_unsafe_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]' +//@ count "$.index[?(@.name=='test5')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test5')].attrs[*].target_feature.enable" '["avx", "avx2"]' +#[target_feature(enable = "avx")] +#[target_feature(enable = "avx2")] +pub fn test5() {} + //@ is "$.index[?(@.name=='test_unsafe_fn')].inner.function.header.is_unsafe" true +//@ count "$.index[?(@.name=='test_unsafe_fn')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test_unsafe_fn')].attrs[*].target_feature.enable" '["avx"]' #[target_feature(enable = "avx")] pub unsafe fn test_unsafe_fn() {} pub struct Example; impl Example { - //@ is "$.index[?(@.name=='safe_assoc_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]' //@ is "$.index[?(@.name=='safe_assoc_fn')].inner.function.header.is_unsafe" false + //@ is "$.index[?(@.name=='safe_assoc_fn')].attrs[*].target_feature.enable" '["avx"]' #[target_feature(enable = "avx")] pub fn safe_assoc_fn() {} - //@ is "$.index[?(@.name=='unsafe_assoc_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]' //@ is "$.index[?(@.name=='unsafe_assoc_fn')].inner.function.header.is_unsafe" true + //@ is "$.index[?(@.name=='unsafe_assoc_fn')].attrs[*].target_feature.enable" '["avx"]' #[target_feature(enable = "avx")] pub unsafe fn unsafe_assoc_fn() {} } diff --git a/tests/rustdoc-json/enums/discriminant/struct.rs b/tests/rustdoc-json/enums/discriminant/struct.rs index ea669e6a0b30..fed0e545798a 100644 --- a/tests/rustdoc-json/enums/discriminant/struct.rs +++ b/tests/rustdoc-json/enums/discriminant/struct.rs @@ -1,5 +1,5 @@ #[repr(i32)] -//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(i32)]"]' +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"i32"' pub enum Foo { //@ is "$.index[?(@.name=='Struct')].inner.variant.discriminant" null //@ count "$.index[?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0 diff --git a/tests/rustdoc-json/enums/discriminant/tuple.rs b/tests/rustdoc-json/enums/discriminant/tuple.rs index 1b8e791eb230..54bba76a0634 100644 --- a/tests/rustdoc-json/enums/discriminant/tuple.rs +++ b/tests/rustdoc-json/enums/discriminant/tuple.rs @@ -1,5 +1,5 @@ #[repr(u32)] -//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(u32)]"]' +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"u32"' pub enum Foo { //@ is "$.index[?(@.name=='Tuple')].inner.variant.discriminant" null //@ count "$.index[?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0 diff --git a/tests/rustdoc-json/keyword_private.rs b/tests/rustdoc-json/keyword_private.rs index fea546c9fb60..3198fc2529ef 100644 --- a/tests/rustdoc-json/keyword_private.rs +++ b/tests/rustdoc-json/keyword_private.rs @@ -5,7 +5,7 @@ //@ !has "$.index[?(@.name=='match')]" //@ has "$.index[?(@.name=='foo')]" -//@ is "$.index[?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]"]' +//@ is "$.index[?(@.name=='foo')].attrs[*].other" '"#[doc(keyword = \"match\")]"' //@ is "$.index[?(@.name=='foo')].docs" '"this is a test!"' #[doc(keyword = "match")] /// this is a test! @@ -13,7 +13,7 @@ pub mod foo {} //@ !has "$.index[?(@.name=='break')]" //@ has "$.index[?(@.name=='bar')]" -//@ is "$.index[?(@.name=='bar')].attrs" '["#[doc(keyword = \"break\")]"]' +//@ is "$.index[?(@.name=='bar')].attrs[*].other" '"#[doc(keyword = \"break\")]"' //@ is "$.index[?(@.name=='bar')].docs" '"hello"' #[doc(keyword = "break")] /// hello diff --git a/tests/rustdoc-json/visibility/doc_hidden_documented.rs b/tests/rustdoc-json/visibility/doc_hidden_documented.rs index 6e9ef48680be..f05e4f9d92d5 100644 --- a/tests/rustdoc-json/visibility/doc_hidden_documented.rs +++ b/tests/rustdoc-json/visibility/doc_hidden_documented.rs @@ -1,15 +1,15 @@ //@ compile-flags: --document-hidden-items #![no_std] -//@ is "$.index[?(@.name=='func')].attrs" '["#[doc(hidden)]"]' +//@ is "$.index[?(@.name=='func')].attrs" '[{"other": "#[doc(hidden)]"}]' #[doc(hidden)] pub fn func() {} -//@ is "$.index[?(@.name=='Unit')].attrs" '["#[doc(hidden)]"]' +//@ is "$.index[?(@.name=='Unit')].attrs" '[{"other": "#[doc(hidden)]"}]' #[doc(hidden)] pub struct Unit; -//@ is "$.index[?(@.name=='hidden')].attrs" '["#[doc(hidden)]"]' +//@ is "$.index[?(@.name=='hidden')].attrs" '[{"other": "#[doc(hidden)]"}]' #[doc(hidden)] pub mod hidden { //@ is "$.index[?(@.name=='Inner')].attrs" '[]' From 4f1b3e3afc47f94f00de6294d180e90aa260b67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 15 Jul 2025 19:44:31 +0200 Subject: [PATCH 206/363] Clarify comments --- src/bootstrap/src/core/build_steps/tool.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index df89eb1da20c..4d2fa177765b 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -196,6 +196,7 @@ impl Step for ToolBuild { Kind::Build, self.mode, self.tool, + // A stage N tool is built with the stage N-1 compiler. self.build_compiler.stage + 1, &self.build_compiler.host, &self.target, @@ -366,7 +367,7 @@ pub(crate) fn get_tool_rustc_compiler( } /// Determines how to build a `ToolTarget`, i.e. which compiler should be used to compile it. -/// The compiler stage is automatically auto-bumped if we need to cross-compile a stage 1 tool. +/// The compiler stage is automatically bumped if we need to cross-compile a stage 1 tool. pub enum ToolTargetBuildMode { /// Build the tool using rustc that corresponds to the selected CLI stage. Build(TargetSelection), @@ -399,7 +400,7 @@ pub(crate) fn get_tool_target_compiler( builder.compiler(build_compiler_stage, builder.host_target) } else { // If we are cross-compiling a stage 1 tool, we cannot do that with a stage 0 compiler, - // so we auto-bump the tool's stage to 2. + // so we auto-bump the tool's stage to 2, which means we need a stage 1 compiler. builder.compiler(build_compiler_stage.max(1), builder.host_target) }; builder.std(compiler, target); From bbb114ef6198b1d2de4898f838b4ae3183c2db90 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 12 Jul 2025 13:16:34 -0500 Subject: [PATCH 207/363] ci cleanup: rustdoc-gui-test now installs browser-ui-test this removes the need for --unsafe-perm in the Dockerfile. --- src/build_helper/src/lib.rs | 1 + src/build_helper/src/npm.rs | 30 ++++++ .../host-x86_64/x86_64-gnu-miri/Dockerfile | 8 -- .../host-x86_64/x86_64-gnu-tools/Dockerfile | 11 --- .../x86_64-gnu-tools/browser-ui-test.version | 1 - src/tools/rustdoc-gui-test/src/main.rs | 93 +++---------------- 6 files changed, 44 insertions(+), 100 deletions(-) create mode 100644 src/build_helper/src/npm.rs delete mode 100644 src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version diff --git a/src/build_helper/src/lib.rs b/src/build_helper/src/lib.rs index 05de8fd2d42f..266eedc62458 100644 --- a/src/build_helper/src/lib.rs +++ b/src/build_helper/src/lib.rs @@ -5,6 +5,7 @@ pub mod drop_bomb; pub mod fs; pub mod git; pub mod metrics; +pub mod npm; pub mod stage0_parser; pub mod targets; pub mod util; diff --git a/src/build_helper/src/npm.rs b/src/build_helper/src/npm.rs new file mode 100644 index 000000000000..dedef40978dd --- /dev/null +++ b/src/build_helper/src/npm.rs @@ -0,0 +1,30 @@ +use std::error::Error; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::{fs, io}; + +/// Install an exact package version, and return the path of `node_modules`. +pub fn install_one( + out_dir: &Path, + npm_bin: &Path, + pkg_name: &str, + pkg_version: &str, +) -> Result { + let nm_path = out_dir.join("node_modules"); + let _ = fs::create_dir(&nm_path); + let mut child = Command::new(npm_bin) + .arg("install") + .arg("--audit=false") + .arg("--fund=false") + .arg(format!("{pkg_name}@{pkg_version}")) + .current_dir(out_dir) + .spawn()?; + let exit_status = child.wait()?; + if !exit_status.success() { + eprintln!("npm install did not exit successfully"); + return Err(io::Error::other(Box::::from(format!( + "npm install returned exit code {exit_status}" + )))); + } + Ok(nm_path) +} diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile index b937bc3e678d..ad2ee85c7bb5 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile @@ -46,12 +46,4 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu COPY scripts/shared.sh /scripts/ -# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries -# to create a new folder. For reference: -# https://github.com/puppeteer/puppeteer/issues/375 -# -# We also specify the version in case we need to update it to go around cache limitations. -# -# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case -# the local version of the package is different than the one used by the CI. ENV SCRIPT /tmp/check-miri.sh ../x.py diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index e770c58bd9cf..95357d229374 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -76,8 +76,6 @@ COPY scripts/nodejs.sh /scripts/ RUN sh /scripts/nodejs.sh /node ENV PATH="/node/bin:${PATH}" -COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/ - ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --save-toolstates=/tmp/toolstate/toolstates.json \ @@ -91,15 +89,6 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu COPY scripts/shared.sh /scripts/ -# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries -# to create a new folder. For reference: -# https://github.com/puppeteer/puppeteer/issues/375 -# -# We also specify the version in case we need to update it to go around cache limitations. -# -# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case -# the local version of the package is different than the one used by the CI. ENV SCRIPT /tmp/checktools.sh ../x.py && \ - npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \ python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version deleted file mode 100644 index b9f8e558df4d..000000000000 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ /dev/null @@ -1 +0,0 @@ -0.21.1 \ No newline at end of file diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index 6461f38f527b..bcec950a404f 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -1,63 +1,15 @@ +use std::env; use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::Arc; -use std::{env, fs}; +use build_helper::npm; use build_helper::util::try_run; use compiletest::directives::TestProps; use config::Config; mod config; -fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option { - let mut command = Command::new(&npm); - command.arg("list").arg("--parseable").arg("--long").arg("--depth=0"); - if global { - command.arg("--global"); - } - let lines = match command.output() { - Ok(output) => String::from_utf8_lossy(&output.stdout).into_owned(), - Err(e) => { - eprintln!( - "path to npm can be wrong, provided path: {npm:?}. Try to set npm path \ - in bootstrap.toml in [build.npm]", - ); - panic!("{:?}", e) - } - }; - lines - .lines() - .find_map(|l| l.rsplit(':').next()?.strip_prefix("browser-ui-test@")) - .map(|v| v.to_owned()) -} - -fn get_browser_ui_test_version(npm: &Path) -> Option { - get_browser_ui_test_version_inner(npm, false) - .or_else(|| get_browser_ui_test_version_inner(npm, true)) -} - -fn compare_browser_ui_test_version(installed_version: &str, src: &Path) { - match fs::read_to_string( - src.join("src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version"), - ) { - Ok(v) => { - if v.trim() != installed_version { - eprintln!( - "⚠️ Installed version of browser-ui-test (`{}`) is different than the \ - one used in the CI (`{}`)", - installed_version, v - ); - eprintln!( - "You can install this version using `npm update browser-ui-test` or by using \ - `npm install browser-ui-test@{}`", - v, - ); - } - } - Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e), - } -} - fn find_librs>(path: P) -> Option { for entry in walkdir::WalkDir::new(path) { let entry = entry.ok()?; @@ -71,27 +23,6 @@ fn find_librs>(path: P) -> Option { fn main() -> Result<(), ()> { let config = Arc::new(Config::from_args(env::args().collect())); - // The goal here is to check if the necessary packages are installed, and if not, we - // panic. - match get_browser_ui_test_version(&config.npm) { - Some(version) => { - // We also check the version currently used in CI and emit a warning if it's not the - // same one. - compare_browser_ui_test_version(&version, &config.rust_src); - } - None => { - eprintln!( - r#" -error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` dependency is missing. - -If you want to install the `browser-ui-test` dependency, run `npm install browser-ui-test` -"#, - ); - - panic!("Cannot run rustdoc-gui tests"); - } - } - let src_path = config.rust_src.join("tests/rustdoc-gui/src"); for entry in src_path.read_dir().expect("read_dir call failed") { if let Ok(entry) = entry { @@ -138,16 +69,12 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse } } - let mut command = Command::new(&config.nodejs); + // FIXME(binarycat): once we get package.json in version control, this should be updated to install via that instead + let local_node_modules = + npm::install_one(&config.out_dir, &config.npm, "browser-ui-test", "0.21.1") + .expect("unable to install browser-ui-test"); - if let Ok(current_dir) = env::current_dir() { - let local_node_modules = current_dir.join("node_modules"); - if local_node_modules.exists() { - // Link the local node_modules if exists. - // This is useful when we run rustdoc-gui-test from outside of the source root. - env::set_var("NODE_PATH", local_node_modules); - } - } + let mut command = Command::new(&config.nodejs); command .arg(config.rust_src.join("src/tools/rustdoc-gui/tester.js")) @@ -158,6 +85,12 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse .arg("--tests-folder") .arg(config.rust_src.join("tests/rustdoc-gui")); + if local_node_modules.exists() { + // Link the local node_modules if exists. + // This is useful when we run rustdoc-gui-test from outside of the source root. + command.env("NODE_PATH", local_node_modules); + } + for file in &config.goml_files { command.arg("--file").arg(file); } From 1120cb2fe54fae7a1a8ccd5beb941f5b207084c0 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 15 Jul 2025 14:14:22 -0500 Subject: [PATCH 208/363] Add LocalKey::update --- library/std/src/thread/local.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 7cd448733130..0ad014ccd3e2 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -469,6 +469,29 @@ impl LocalKey> { pub fn replace(&'static self, value: T) -> T { self.with(|cell| cell.replace(value)) } + + /// Updates the contained value using a function. + /// + /// # Examples + /// + /// ``` + /// #![feature(local_key_cell_update)] + /// use std::cell::Cell; + /// + /// thread_local! { + /// static X: Cell = const { Cell::new(5) }; + /// } + /// + /// X.update(|x| x + 1); + /// assert_eq!(X.get(), 6); + /// ``` + #[unstable(feature = "local_key_cell_update", issue = "143989")] + pub fn update(&'static self, f: impl FnOnce(T) -> T) + where + T: Copy, + { + self.with(|cell| cell.update(f)) + } } impl LocalKey> { From 85c89494d9efdc90f2ac08446c00b0b78287b7a2 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Thu, 10 Jul 2025 15:10:33 -0400 Subject: [PATCH 209/363] add support for global constructors (i.e. life before main) --- src/tools/miri/src/eval.rs | 91 +++++++++++++++++++++---------- src/tools/miri/src/helpers.rs | 9 ++- src/tools/miri/src/shims/ctor.rs | 94 ++++++++++++++++++++++++++++++++ src/tools/miri/src/shims/mod.rs | 1 + src/tools/miri/src/shims/tls.rs | 2 +- 5 files changed, 165 insertions(+), 32 deletions(-) create mode 100644 src/tools/miri/src/shims/ctor.rs diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 425a136dfa54..d986f2830aa2 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -11,14 +11,14 @@ use rustc_abi::ExternAbi; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; -use rustc_middle::ty::layout::LayoutCx; +use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutCx}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config::EntryFnType; use crate::concurrency::GenmcCtx; use crate::concurrency::thread::TlsAllocAction; use crate::diagnostics::report_leaks; -use crate::shims::tls; +use crate::shims::{ctor, tls}; use crate::*; #[derive(Copy, Clone, Debug)] @@ -216,9 +216,15 @@ impl Default for MiriConfig { } /// The state of the main thread. Implementation detail of `on_main_stack_empty`. -#[derive(Default, Debug)] +#[derive(Debug)] enum MainThreadState<'tcx> { - #[default] + GlobalCtors { + ctor_state: ctor::GlobalCtorState<'tcx>, + entry_id: DefId, + entry_type: MiriEntryFnType, + argc: ImmTy<'tcx>, + argv: ImmTy<'tcx>, + }, Running, TlsDtors(tls::TlsDtorsState<'tcx>), Yield { @@ -234,6 +240,15 @@ impl<'tcx> MainThreadState<'tcx> { ) -> InterpResult<'tcx, Poll<()>> { use MainThreadState::*; match self { + GlobalCtors { ctor_state, entry_id, entry_type, argc, argv } => { + match ctor_state.on_stack_empty(this)? { + Poll::Pending => {} // just keep going + Poll::Ready(()) => { + call_main(this, *entry_id, *entry_type, argc.clone(), argv.clone())?; + *self = Running; + } + } + } Running => { *self = TlsDtors(Default::default()); } @@ -309,26 +324,6 @@ pub fn create_ecx<'tcx>( MiriMachine::new(config, layout_cx, genmc_ctx), ); - // Some parts of initialization require a full `InterpCx`. - MiriMachine::late_init(&mut ecx, config, { - let mut state = MainThreadState::default(); - // Cannot capture anything GC-relevant here. - Box::new(move |m| state.on_main_stack_empty(m)) - })?; - - // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. - let sentinel = - 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." - ); - } - - // Setup first stack frame. - let entry_instance = ty::Instance::mono(tcx, entry_id); - // First argument is constructed later, because it's skipped for `miri_start.` // Second argument (argc): length of `config.args`. @@ -395,11 +390,51 @@ pub fn create_ecx<'tcx>( ImmTy::from_immediate(imm, layout) }; + // Some parts of initialization require a full `InterpCx`. + MiriMachine::late_init(&mut ecx, config, { + let mut state = MainThreadState::GlobalCtors { + entry_id, + entry_type, + argc, + argv, + ctor_state: ctor::GlobalCtorState::default(), + }; + + // Cannot capture anything GC-relevant here. + Box::new(move |m| state.on_main_stack_empty(m)) + })?; + + // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. + let sentinel = + 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." + ); + } + + interp_ok(ecx) +} + +// Call the entry function. +fn call_main<'tcx>( + ecx: &mut MiriInterpCx<'tcx>, + entry_id: DefId, + entry_type: MiriEntryFnType, + argc: ImmTy<'tcx>, + argv: ImmTy<'tcx>, +) -> InterpResult<'tcx, ()> { + let tcx = ecx.tcx(); + + // Setup first stack frame. + let entry_instance = ty::Instance::mono(tcx, entry_id); + // Return place (in static memory so that it does not count as leak). let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; ecx.machine.main_fn_ret_place = Some(ret_place.clone()); - // Call start function. + // Call start function. match entry_type { MiriEntryFnType::Rustc(EntryFnType::Main { .. }) => { let start_id = tcx.lang_items().start_fn().unwrap_or_else(|| { @@ -409,7 +444,7 @@ pub fn create_ecx<'tcx>( let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); let start_instance = ty::Instance::try_resolve( tcx, - typing_env, + ecx.typing_env(), start_id, tcx.mk_args(&[ty::GenericArg::from(main_ret_ty)]), ) @@ -427,7 +462,7 @@ pub fn create_ecx<'tcx>( ExternAbi::Rust, &[ ImmTy::from_scalar( - Scalar::from_pointer(main_ptr, &ecx), + Scalar::from_pointer(main_ptr, ecx), // FIXME use a proper fn ptr type ecx.machine.layouts.const_raw_ptr, ), @@ -450,7 +485,7 @@ pub fn create_ecx<'tcx>( } } - interp_ok(ecx) + interp_ok(()) } /// Evaluates the entry function specified by `entry_id`. diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 216b7b1e4bb3..35d3e7e647cc 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1235,8 +1235,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(()) } - /// Lookup an array of immediates stored as a linker section of name `name`. - fn lookup_link_section(&mut self, name: &str) -> InterpResult<'tcx, Vec>> { + /// Lookup an array of immediates from any linker sections matching the provided predicate. + fn lookup_link_section( + &mut self, + include_name: impl Fn(&str) -> bool, + ) -> InterpResult<'tcx, Vec>> { let this = self.eval_context_mut(); let tcx = this.tcx.tcx; @@ -1247,7 +1250,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let Some(link_section) = attrs.link_section else { return interp_ok(()); }; - if link_section.as_str() == name { + if include_name(link_section.as_str()) { let instance = ty::Instance::mono(tcx, def_id); let const_val = this.eval_global(instance).unwrap_or_else(|err| { panic!( diff --git a/src/tools/miri/src/shims/ctor.rs b/src/tools/miri/src/shims/ctor.rs new file mode 100644 index 000000000000..75f564989bc6 --- /dev/null +++ b/src/tools/miri/src/shims/ctor.rs @@ -0,0 +1,94 @@ +//! Implement global constructors. + +use std::task::Poll; + +use rustc_abi::ExternAbi; +use rustc_target::spec::BinaryFormat; + +use crate::*; + +#[derive(Debug, Default)] +pub struct GlobalCtorState<'tcx>(GlobalCtorStatePriv<'tcx>); + +#[derive(Debug, Default)] +enum GlobalCtorStatePriv<'tcx> { + #[default] + Init, + /// The list of constructor functions that we still have to call. + Ctors(Vec>), + Done, +} + +impl<'tcx> GlobalCtorState<'tcx> { + pub fn on_stack_empty( + &mut self, + this: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, Poll<()>> { + use GlobalCtorStatePriv::*; + let new_state = 'new_state: { + match &mut self.0 { + Init => { + let this = this.eval_context_mut(); + + // Lookup constructors from the relevant magic link section. + let ctors = match this.tcx.sess.target.binary_format { + // Read the CRT library section on Windows. + BinaryFormat::Coff => + this.lookup_link_section(|section| section == ".CRT$XCU")?, + + // Read the `__mod_init_func` section on macOS. + BinaryFormat::MachO => + this.lookup_link_section(|section| { + let mut parts = section.splitn(3, ','); + let (segment_name, section_name, section_type) = + (parts.next(), parts.next(), parts.next()); + + segment_name == Some("__DATA") + && section_name == Some("__mod_init_func") + // The `mod_init_funcs` directive ensures that the `S_MOD_INIT_FUNC_POINTERS` flag + // is set on the section, but it is not strictly required. + && matches!(section_type, None | Some("mod_init_funcs")) + })?, + + // Read the standard `.init_array` section on platforms that use ELF, or WASM, + // which supports the same linker directive. + // FIXME: Add support for `.init_array.N`. + BinaryFormat::Elf | BinaryFormat::Wasm => + this.lookup_link_section(|section| section == ".init_array")?, + + // Other platforms have no global ctor support. + _ => break 'new_state Done, + }; + + break 'new_state Ctors(ctors); + } + Ctors(ctors) => { + if let Some(ctor) = ctors.pop() { + let this = this.eval_context_mut(); + + let ctor = ctor.to_scalar().to_pointer(this)?; + let thread_callback = this.get_ptr_fn(ctor)?.as_instance()?; + + // The signature of this function is `unsafe extern "C" fn()`. + this.call_function( + thread_callback, + ExternAbi::C { unwind: false }, + &[], + None, + ReturnContinuation::Stop { cleanup: true }, + )?; + + return interp_ok(Poll::Pending); // we stay in this state (but `ctors` got shorter) + } + + // No more constructors to run. + break 'new_state Done; + } + Done => return interp_ok(Poll::Ready(())), + } + }; + + self.0 = new_state; + interp_ok(Poll::Pending) + } +} diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index b08ab101e947..0faf298bfaa3 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -11,6 +11,7 @@ mod wasi; mod windows; mod x86; +pub mod ctor; pub mod env; pub mod extern_static; pub mod foreign_items; diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index 7182637437a1..1200029692dc 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -302,7 +302,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Windows has a special magic linker section that is run on certain events. // We don't support most of that, but just enough to make thread-local dtors in `std` work. - interp_ok(this.lookup_link_section(".CRT$XLB")?) + interp_ok(this.lookup_link_section(|section| section == ".CRT$XLB")?) } fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx>) -> InterpResult<'tcx> { From d060859376994b32dad84e5bb7f507fbb1dcb89a Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Thu, 10 Jul 2025 16:37:54 -0400 Subject: [PATCH 210/363] add test for global constructors --- src/tools/miri/tests/pass/shims/ctor.rs | 43 +++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/tools/miri/tests/pass/shims/ctor.rs diff --git a/src/tools/miri/tests/pass/shims/ctor.rs b/src/tools/miri/tests/pass/shims/ctor.rs new file mode 100644 index 000000000000..c832e3f82a35 --- /dev/null +++ b/src/tools/miri/tests/pass/shims/ctor.rs @@ -0,0 +1,43 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; + +static COUNT: AtomicUsize = AtomicUsize::new(0); + +unsafe extern "C" fn ctor() { + COUNT.fetch_add(1, Ordering::Relaxed); +} + +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"), + link_section = "__DATA,__mod_init_func" + )] + #[used] + static $ident: unsafe extern "C" fn() = $ctor; + }; +} + +ctor! { CTOR1 = ctor } +ctor! { CTOR2 = ctor } +ctor! { CTOR3 = ctor } + +fn main() { + assert_eq!(COUNT.load(Ordering::Relaxed), 3, "ctors did not run"); +} From 8e400f97e59211732ba67518199432ae22685cb5 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 15 Jul 2025 19:07:37 +0200 Subject: [PATCH 211/363] Fix ice for feature-gated cfg attributes applied to the crate Signed-off-by: Jonathan Brouwer --- .../rustc_attr_parsing/src/attributes/cfg.rs | 53 +++++++++++-------- compiler/rustc_attr_parsing/src/context.rs | 27 ++++++++-- compiler/rustc_attr_parsing/src/lib.rs | 2 +- compiler/rustc_expand/src/config.rs | 22 +++++--- compiler/rustc_expand/src/expand.rs | 4 +- compiler/rustc_resolve/src/def_collector.rs | 4 +- 6 files changed, 74 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index a56855b3bd3d..6373cf6e08ad 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -9,7 +9,7 @@ use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; -use crate::context::{AcceptContext, Stage}; +use crate::context::{AcceptContext, ShouldEmit, Stage}; use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser}; use crate::{ CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg, @@ -90,7 +90,7 @@ fn parse_cfg_entry_version( list: &MetaItemListParser<'_>, meta_span: Span, ) -> Option { - try_gate_cfg(sym::version, meta_span, cx.sess(), Some(cx.features())); + try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option()); let Some(version) = list.single() else { cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: list.span }); return None; @@ -119,7 +119,9 @@ fn parse_cfg_entry_target( list: &MetaItemListParser<'_>, meta_span: Span, ) -> Option { - if !cx.features().cfg_target_compact() { + if let Some(features) = cx.features_option() + && !features.cfg_target_compact() + { feature_err( cx.sess(), sym::cfg_target_compact, @@ -186,12 +188,13 @@ pub fn eval_config_entry( cfg_entry: &CfgEntry, id: NodeId, features: Option<&Features>, + emit_lints: ShouldEmit, ) -> EvalConfigResult { match cfg_entry { CfgEntry::All(subs, ..) => { let mut all = None; for sub in subs { - let res = eval_config_entry(sess, sub, id, features); + let res = eval_config_entry(sess, sub, id, features, emit_lints); // We cannot short-circuit because `eval_config_entry` emits some lints if !res.as_bool() { all.get_or_insert(res); @@ -202,7 +205,7 @@ pub fn eval_config_entry( CfgEntry::Any(subs, span) => { let mut any = None; for sub in subs { - let res = eval_config_entry(sess, sub, id, features); + let res = eval_config_entry(sess, sub, id, features, emit_lints); // We cannot short-circuit because `eval_config_entry` emits some lints if res.as_bool() { any.get_or_insert(res); @@ -214,7 +217,7 @@ pub fn eval_config_entry( }) } CfgEntry::Not(sub, span) => { - if eval_config_entry(sess, sub, id, features).as_bool() { + if eval_config_entry(sess, sub, id, features, emit_lints).as_bool() { EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } } else { EvalConfigResult::True @@ -228,24 +231,28 @@ pub fn eval_config_entry( } } CfgEntry::NameValue { name, name_span, value, span } => { - match sess.psess.check_config.expecteds.get(name) { - Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => { - id.emit_span_lint( - sess, - UNEXPECTED_CFGS, - *span, - BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value), - ); + if let ShouldEmit::ErrorsAndLints = emit_lints { + match sess.psess.check_config.expecteds.get(name) { + Some(ExpectedValues::Some(values)) + if !values.contains(&value.map(|(v, _)| v)) => + { + id.emit_span_lint( + sess, + UNEXPECTED_CFGS, + *span, + BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value), + ); + } + None if sess.psess.check_config.exhaustive_names => { + id.emit_span_lint( + sess, + UNEXPECTED_CFGS, + *span, + BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value), + ); + } + _ => { /* not unexpected */ } } - None if sess.psess.check_config.exhaustive_names => { - id.emit_span_lint( - sess, - UNEXPECTED_CFGS, - *span, - BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value), - ); - } - _ => { /* not unexpected */ } } if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 567341d1517d..dc80d408b273 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -223,7 +223,7 @@ impl Stage for Early { sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>, ) -> ErrorGuaranteed { - if self.emit_errors { + if self.emit_errors.should_emit() { sess.dcx().emit_err(diag) } else { sess.dcx().create_err(diag).delay_as_bug() @@ -254,7 +254,7 @@ pub struct Early { /// Whether to emit errors or delay them as a bug /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted - pub emit_errors: bool, + pub emit_errors: ShouldEmit, } /// used when parsing attributes during ast lowering pub struct Late; @@ -555,6 +555,25 @@ pub enum OmitDoc { Skip, } +#[derive(Copy, Clone)] +pub enum ShouldEmit { + /// The operation will emit errors and lints. + /// This is usually what you need. + ErrorsAndLints, + /// The operation will emit *not* errors and lints. + /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::Emit`. + Nothing, +} + +impl ShouldEmit { + pub fn should_emit(&self) -> bool { + match self { + ShouldEmit::ErrorsAndLints => true, + ShouldEmit::Nothing => false, + } + } +} + /// Context created once, for example as part of the ast lowering /// context, through which all attributes can be lowered. pub struct AttributeParser<'sess, S: Stage = Late> { @@ -597,7 +616,7 @@ impl<'sess> AttributeParser<'sess, Early> { tools: Vec::new(), parse_only: Some(sym), sess, - stage: Early { emit_errors: false }, + stage: Early { emit_errors: ShouldEmit::Nothing }, }; let mut parsed = p.parse_attribute_list( attrs, @@ -620,7 +639,7 @@ impl<'sess> AttributeParser<'sess, Early> { target_span: Span, target_node_id: NodeId, features: Option<&'sess Features>, - emit_errors: bool, + emit_errors: ShouldEmit, parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T, template: &AttributeTemplate, ) -> T { diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 2102a26108bc..dc54cb6b840c 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -95,7 +95,7 @@ pub use attributes::cfg_old::*; pub use attributes::util::{ find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version, }; -pub use context::{AttributeParser, Early, Late, OmitDoc}; +pub use context::{AttributeParser, Early, Late, OmitDoc, ShouldEmit}; pub use lints::emit_attribute_lint; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 6922ddfd6bdd..83a8d601afea 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -12,7 +12,7 @@ use rustc_ast::{ }; use rustc_attr_parsing as attr; use rustc_attr_parsing::{ - AttributeParser, CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr, + AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg_attr, }; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_feature::{ @@ -167,7 +167,9 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec .flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)) .take_while(|attr| { !is_cfg(attr) - || strip_unconfigured.cfg_true(attr, strip_unconfigured.lint_node_id).as_bool() + || strip_unconfigured + .cfg_true(attr, strip_unconfigured.lint_node_id, ShouldEmit::Nothing) + .as_bool() }) .collect() } @@ -401,10 +403,18 @@ impl<'a> StripUnconfigured<'a> { /// Determines if a node with the given attributes should be included in this configuration. fn in_cfg(&self, attrs: &[Attribute]) -> bool { - attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr, self.lint_node_id).as_bool()) + attrs.iter().all(|attr| { + !is_cfg(attr) + || self.cfg_true(attr, self.lint_node_id, ShouldEmit::ErrorsAndLints).as_bool() + }) } - pub(crate) fn cfg_true(&self, attr: &Attribute, node: NodeId) -> EvalConfigResult { + pub(crate) fn cfg_true( + &self, + attr: &Attribute, + node: NodeId, + emit_errors: ShouldEmit, + ) -> EvalConfigResult { // We need to run this to do basic validation of the attribute, such as that lits are valid, etc // FIXME(jdonszelmann) this should not be necessary in the future match validate_attr::parse_meta(&self.sess.psess, attr) { @@ -428,7 +438,7 @@ impl<'a> StripUnconfigured<'a> { attr.span, node, self.features, - true, + emit_errors, parse_cfg_attr, &CFG_TEMPLATE, ) else { @@ -436,7 +446,7 @@ impl<'a> StripUnconfigured<'a> { return EvalConfigResult::True; }; - eval_config_entry(self.sess, &cfg, self.lint_node_id, self.features) + eval_config_entry(self.sess, &cfg, self.lint_node_id, self.features, emit_errors) } /// If attributes are not allowed on expressions, emit an error for `attr` diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index f99060e9a216..79ec79a2fdf4 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -13,7 +13,7 @@ use rustc_ast::{ MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, }; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::EvalConfigResult; +use rustc_attr_parsing::{EvalConfigResult, ShouldEmit}; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_errors::PResult; use rustc_feature::Features; @@ -2171,7 +2171,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { attr: ast::Attribute, pos: usize, ) -> EvalConfigResult { - let res = self.cfg().cfg_true(&attr, node.node_id()); + let res = self.cfg().cfg_true(&attr, node.node_id(), ShouldEmit::ErrorsAndLints); if res.as_bool() { // A trace attribute left in AST in place of the original `cfg` attribute. // It can later be used by lints or other diagnostics. diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 781e2ce97040..7d51fef28d3b 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -2,7 +2,7 @@ use std::mem; use rustc_ast::visit::FnKind; use rustc_ast::*; -use rustc_attr_parsing::{AttributeParser, Early, OmitDoc}; +use rustc_attr_parsing::{AttributeParser, Early, OmitDoc, ShouldEmit}; use rustc_expand::expand::AstFragment; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; @@ -132,7 +132,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &self.resolver.tcx.sess, self.resolver.tcx.features(), Vec::new(), - Early { emit_errors: false }, + Early { emit_errors: ShouldEmit::Nothing }, ); let attrs = parser.parse_attribute_list( &i.attrs, From bfa45ac78b4cb018ece7daa56116e50820d2fd92 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 15 Jul 2025 19:07:49 +0200 Subject: [PATCH 212/363] Add regression test Signed-off-by: Jonathan Brouwer --- tests/ui/check-cfg/cfg-crate-features.rs | 13 ++++++++ tests/ui/check-cfg/cfg-crate-features.stderr | 33 ++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 tests/ui/check-cfg/cfg-crate-features.rs create mode 100644 tests/ui/check-cfg/cfg-crate-features.stderr diff --git a/tests/ui/check-cfg/cfg-crate-features.rs b/tests/ui/check-cfg/cfg-crate-features.rs new file mode 100644 index 000000000000..16be8aaeeaa4 --- /dev/null +++ b/tests/ui/check-cfg/cfg-crate-features.rs @@ -0,0 +1,13 @@ +// https://github.com/rust-lang/rust/issues/143977 +// Check that features are available when an attribute is applied to a crate + +#![cfg(version("1.0"))] +//~^ ERROR `cfg(version)` is experimental and subject to change + +// Using invalid value `does_not_exist`, +// so we don't accidentally configure out the crate for any certain OS +#![cfg(not(target(os = "does_not_exist")))] +//~^ ERROR compact `cfg(target(..))` is experimental and subject to change +//~| WARN unexpected `cfg` condition value: `does_not_exist` + +fn main() {} diff --git a/tests/ui/check-cfg/cfg-crate-features.stderr b/tests/ui/check-cfg/cfg-crate-features.stderr new file mode 100644 index 000000000000..60a5404c0739 --- /dev/null +++ b/tests/ui/check-cfg/cfg-crate-features.stderr @@ -0,0 +1,33 @@ +error[E0658]: `cfg(version)` is experimental and subject to change + --> $DIR/cfg-crate-features.rs:4:8 + | +LL | #![cfg(version("1.0"))] + | ^^^^^^^^^^^^^^ + | + = note: see issue #64796 for more information + = help: add `#![feature(cfg_version)]` 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]: compact `cfg(target(..))` is experimental and subject to change + --> $DIR/cfg-crate-features.rs:9:12 + | +LL | #![cfg(not(target(os = "does_not_exist")))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #96901 for more information + = help: add `#![feature(cfg_target_compact)]` 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: unexpected `cfg` condition value: `does_not_exist` + --> $DIR/cfg-crate-features.rs:9:19 + | +LL | #![cfg(not(target(os = "does_not_exist")))] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, and `uefi` and 9 more + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. From c6e1b2177701df2ce9f61f28cbf28e8ced4ff64a Mon Sep 17 00:00:00 2001 From: Jacob Greenfield Date: Tue, 15 Jul 2025 20:47:09 -0400 Subject: [PATCH 213/363] Use hygenic macros for stable-mir --- .../rustc_public/src/rustc_internal/mod.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_public/src/rustc_internal/mod.rs b/compiler/rustc_public/src/rustc_internal/mod.rs index 5d7c8256d5bf..01354fc7bd42 100644 --- a/compiler/rustc_public/src/rustc_internal/mod.rs +++ b/compiler/rustc_public/src/rustc_internal/mod.rs @@ -144,10 +144,10 @@ where #[macro_export] macro_rules! run { ($args:expr, $callback_fn:ident) => { - run_driver!($args, || $callback_fn()) + $crate::run_driver!($args, || $callback_fn()) }; ($args:expr, $callback:expr) => { - run_driver!($args, $callback) + $crate::run_driver!($args, $callback) }; } @@ -158,10 +158,10 @@ macro_rules! run { #[macro_export] macro_rules! run_with_tcx { ($args:expr, $callback_fn:ident) => { - run_driver!($args, |tcx| $callback_fn(tcx), with_tcx) + $crate::run_driver!($args, |tcx| $callback_fn(tcx), with_tcx) }; ($args:expr, $callback:expr) => { - run_driver!($args, $callback, with_tcx) + $crate::run_driver!($args, $callback, with_tcx) }; } @@ -191,11 +191,11 @@ macro_rules! run_driver { use rustc_public::CompilerError; use std::ops::ControlFlow; - pub struct StableMir ControlFlow> + pub struct StableMir ControlFlow> where B: Send, C: Send, - F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, + F: FnOnce($($crate::optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, { callback: Option, result: Option>, @@ -205,7 +205,7 @@ macro_rules! run_driver { where B: Send, C: Send, - F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, + F: FnOnce($($crate::optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, { /// Creates a new `StableMir` instance, with given test_function and arguments. pub fn new(callback: F) -> Self { @@ -240,7 +240,7 @@ macro_rules! run_driver { where B: Send, C: Send, - F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, + F: FnOnce($($crate::optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, { /// Called after analysis. Return value instructs the compiler whether to /// continue the compilation afterwards (defaults to `Compilation::Continue`) @@ -251,7 +251,7 @@ macro_rules! run_driver { ) -> Compilation { if let Some(callback) = self.callback.take() { rustc_internal::run(tcx, || { - self.result = Some(callback($(optional!($with_tcx tcx))?)); + self.result = Some(callback($($crate::optional!($with_tcx tcx))?)); }) .unwrap(); if self.result.as_ref().is_some_and(|val| val.is_continue()) { From 10bc064d892be46c68b43a1ff8eb6b30abde5fdb Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 15 Jul 2025 18:32:00 -0700 Subject: [PATCH 214/363] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index eabb4cd923de..6833aa715d72 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit eabb4cd923deb73e714f7ad3f5234d68ca284dbe +Subproject commit 6833aa715d724437dc1247d0166afe314ab6854e From f1d84468c87a4e8ea96e603d21c460004bdeb24f Mon Sep 17 00:00:00 2001 From: "Martin Ombura Jr." <8682597+martinomburajr@users.noreply.github.com> Date: Tue, 15 Jul 2025 20:07:03 -0700 Subject: [PATCH 215/363] Update poison.rs Typo in word "below" --- library/std/src/sync/poison.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index 571f0d14248e..0c05f152ef84 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -10,7 +10,7 @@ //! (some invariant is not being upheld). //! //! The specifics of how this "poisoned" state affects other threads -//! depend on the primitive. See [#Overview] bellow. +//! depend on the primitive. See [#Overview] below. //! //! For the alternative implementations that do not employ poisoning, //! see `std::sync::nonpoisoning`. From 262d02e6fd1fd1b595f19ac33b4693e431c24832 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 16 Jul 2025 01:57:22 +0000 Subject: [PATCH 216/363] Ensure home directory exists This works around a missing mingw home directory in CI --- .github/workflows/ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e92afc14c20d..dc8ac539a3a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -182,6 +182,11 @@ jobs: - name: install MinGW run: src/ci/scripts/install-mingw.sh + # Workaround for spurious ci failures after mingw install + # see https://rust-lang.zulipchat.com/#narrow/channel/242791-t-infra/topic/Spurious.20bors.20CI.20failures/near/528915775 + - name: ensure home dir exists + run: mkdir -p ~ + - name: install ninja run: src/ci/scripts/install-ninja.sh From babe2c0d0f091f5ea9935176b478ea45b152e49e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 4 Jul 2025 22:21:31 +0300 Subject: [PATCH 217/363] resolve: Merge `NameBindingKind::Module` into `NameBindingKind::Res` --- compiler/rustc_hir/src/def.rs | 15 ++++++ .../src/rmeta/decoder/cstore_impl.rs | 7 +-- compiler/rustc_middle/src/ty/print/pretty.rs | 4 +- .../rustc_resolve/src/build_reduced_graph.rs | 50 ++++++------------- compiler/rustc_resolve/src/diagnostics.rs | 40 +++++---------- compiler/rustc_resolve/src/ident.rs | 6 +-- compiler/rustc_resolve/src/imports.rs | 3 -- .../rustc_resolve/src/late/diagnostics.rs | 6 +-- compiler/rustc_resolve/src/lib.rs | 29 +++-------- tests/ui/proc-macro/meta-macro-hygiene.stdout | 6 --- .../nonterminal-token-hygiene.stdout | 6 --- 11 files changed, 61 insertions(+), 111 deletions(-) diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index df010f870982..ca57c4f31641 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -295,6 +295,12 @@ impl DefKind { } } + /// This is a "module" in name resolution sense. + #[inline] + pub fn is_module_like(self) -> bool { + matches!(self, DefKind::Mod | DefKind::Enum | DefKind::Trait) + } + #[inline] pub fn is_fn_like(self) -> bool { matches!( @@ -720,6 +726,15 @@ impl Res { } } + /// If this is a "module" in name resolution sense, return its `DefId`. + #[inline] + pub fn module_like_def_id(&self) -> Option { + match self { + Res::Def(def_kind, def_id) if def_kind.is_module_like() => Some(*def_id), + _ => None, + } + } + /// A human readable name for the res kind ("function", "module", etc.). pub fn descr(&self) -> &'static str { match *self { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 19954459cb59..57a672c45f7b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -3,7 +3,7 @@ use std::mem; use std::sync::Arc; use rustc_attr_data_structures::Deprecation; -use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::arena::ArenaAllocatable; @@ -510,10 +510,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { } Entry::Vacant(entry) => { entry.insert(parent); - if matches!( - child.res, - Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, _) - ) { + if child.res.module_like_def_id().is_some() { bfs_queue.push_back(def_id); } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 7c48a4b0885e..8f0f9b21dc16 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3454,9 +3454,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N collect_fn(&child.ident, ns, def_id); } - if matches!(defkind, DefKind::Mod | DefKind::Enum | DefKind::Trait) - && seen_defs.insert(def_id) - { + if defkind.is_module_like() && seen_defs.insert(def_id) { queue.push(def_id); } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 6979d89a8e7b..a51cdbe76ee3 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -39,21 +39,6 @@ use crate::{ type Res = def::Res; -impl<'ra, Id: Into> ToNameBinding<'ra> - for (Module<'ra>, ty::Visibility, Span, LocalExpnId) -{ - fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { - arenas.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Module(self.0), - ambiguity: None, - warn_ambiguity: false, - vis: self.1.to_def_id(), - span: self.2, - expansion: self.3, - }) - } -} - impl<'ra, Id: Into> ToNameBinding<'ra> for (Res, ty::Visibility, Span, LocalExpnId) { fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { arenas.alloc_name_binding(NameBindingData { @@ -121,7 +106,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !def_id.is_local() { // Query `def_kind` is not used because query system overhead is too expensive here. let def_kind = self.cstore().def_kind_untracked(def_id); - if let DefKind::Mod | DefKind::Enum | DefKind::Trait = def_kind { + if def_kind.is_module_like() { let parent = self .tcx .opt_parent(def_id) @@ -223,12 +208,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let expansion = parent_scope.expansion; // Record primary definitions. match res { - Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, def_id) => { - let module = self.expect_module(def_id); - self.define(parent, ident, TypeNS, (module, vis, span, expansion)); - } Res::Def( - DefKind::Struct + DefKind::Mod + | DefKind::Enum + | DefKind::Trait + | DefKind::Struct | DefKind::Union | DefKind::Variant | DefKind::TyAlias @@ -766,7 +750,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ItemKind::Mod(_, ident, ref mod_kind) => { - let module = self.r.new_module( + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + + if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { + self.r.mods_with_parse_errors.insert(def_id); + } + self.parent_scope.module = self.r.new_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), @@ -774,14 +763,6 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { parent.no_implicit_prelude || ast::attr::contains_name(&item.attrs, sym::no_implicit_prelude), ); - self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - - if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { - self.r.mods_with_parse_errors.insert(def_id); - } - - // Descend into the module. - self.parent_scope.module = module; } // These items live in the value namespace. @@ -804,15 +785,15 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => { - let module = self.r.new_module( + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + + self.parent_scope.module = self.r.new_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), item.span, parent.no_implicit_prelude, ); - self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - self.parent_scope.module = module; } // These items live in both the type and value namespaces. @@ -920,8 +901,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } .map(|module| { let used = self.process_macro_use_imports(item, module); + let res = module.res().unwrap(); let vis = ty::Visibility::::Public; - let binding = (module, vis, sp, expansion).to_name_binding(self.r.arenas); + let binding = (res, vis, sp, expansion).to_name_binding(self.r.arenas); (used, Some(ModuleOrUniformRoot::Module(module)), binding) }) .unwrap_or((true, None, self.r.dummy_binding)); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 93d848787ef4..11e4a729ae23 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -232,12 +232,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - let old_kind = match (ns, old_binding.module()) { + let old_kind = match (ns, old_binding.res()) { (ValueNS, _) => "value", (MacroNS, _) => "macro", (TypeNS, _) if old_binding.is_extern_crate() => "extern crate", - (TypeNS, Some(module)) if module.is_normal() => "module", - (TypeNS, Some(module)) if module.is_trait() => "trait", + (TypeNS, Res::Def(DefKind::Mod, _)) => "module", + (TypeNS, Res::Def(DefKind::Trait, _)) => "trait", (TypeNS, _) => "type", }; @@ -1319,7 +1319,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // collect submodules to explore - if let Some(module) = name_binding.module() { + if let Some(def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); @@ -1339,14 +1339,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !is_extern_crate_that_also_appears_in_prelude || alias_import { // add the module to the lookup - if seen_modules.insert(module.def_id()) { + if seen_modules.insert(def_id) { if via_import { &mut worklist_via_import } else { &mut worklist }.push( ( - module, + this.expect_module(def_id), path_segments, child_accessible, child_doc_visible, - is_stable && this.is_stable(module.def_id(), name_binding.span), + is_stable && this.is_stable(def_id, name_binding.span), ), ); } @@ -2094,7 +2094,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true, // re-export )); } - NameBindingKind::Res(_) | NameBindingKind::Module(_) => {} + NameBindingKind::Res(_) => {} } let first = binding == first_binding; let def_span = self.tcx.sess.source_map().guess_head_span(binding.span); @@ -2306,25 +2306,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .ok() }; if let Some(binding) = binding { - let mut found = |what| { - msg = format!( - "expected {}, found {} `{}` in {}", - ns.descr(), - what, - ident, - parent - ) - }; - if binding.module().is_some() { - found("module") - } else { - match binding.res() { - // Avoid using TyCtxt::def_kind_descr in the resolver, because it - // indirectly *calls* the resolver, and would cause a query cycle. - Res::Def(kind, id) => found(kind.descr(id)), - _ => found(ns_to_try.descr()), - } - } + msg = format!( + "expected {}, found {} `{ident}` in {parent}", + ns.descr(), + binding.res().descr(), + ); }; } (msg, None) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 99297de40d58..04f9e35b6b46 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1637,11 +1637,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); - if let Some(next_module) = binding.module() { - if self.mods_with_parse_errors.contains(&next_module.def_id()) { + if let Some(def_id) = binding.res().module_like_def_id() { + if self.mods_with_parse_errors.contains(&def_id) { module_had_parse_errors = true; } - module = Some(ModuleOrUniformRoot::Module(next_module)); + module = Some(ModuleOrUniformRoot::Module(self.expect_module(def_id))); record_segment_res(self, res); } else if res == Res::ToolMod && !is_last && opt_ns.is_some() { if binding.is_import() { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 40c63a3edf3c..2fa20b254698 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -679,9 +679,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { NameBindingKind::Res(res) => { Some(self.def_id_to_node_id(res.def_id().expect_local())) } - NameBindingKind::Module(module) => { - Some(self.def_id_to_node_id(module.def_id().expect_local())) - } NameBindingKind::Import { import, .. } => import.id(), }; if let Some(binding_id) = binding_id { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b669796bb021..a4601cb44ebf 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2656,18 +2656,17 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if result.is_some() || !name_binding.vis.is_visible_locally() { return; } - if let Some(module) = name_binding.module() { + if let Some(module_def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); - let module_def_id = module.def_id(); let doc_visible = doc_visible && (module_def_id.is_local() || !r.tcx.is_doc_hidden(module_def_id)); if module_def_id == def_id { let path = Path { span: name_binding.span, segments: path_segments, tokens: None }; result = Some(( - module, + r.expect_module(module_def_id), ImportSuggestion { did: Some(def_id), descr: "module", @@ -2682,6 +2681,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } else { // add the module to the lookup if seen_modules.insert(module_def_id) { + let module = r.expect_module(module_def_id); worklist.push((module, path_segments, doc_visible)); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c2b3451d4a1d..eb2b92604836 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -674,7 +674,6 @@ impl<'ra> Module<'ra> { } } - // Public for rustdoc. fn def_id(self) -> DefId { self.opt_def_id().expect("`ModuleData::def_id` is called on a block module") } @@ -782,7 +781,6 @@ impl<'ra> ToNameBinding<'ra> for NameBinding<'ra> { #[derive(Clone, Copy, Debug)] enum NameBindingKind<'ra> { Res(Res), - Module(Module<'ra>), Import { binding: NameBinding<'ra>, import: Import<'ra> }, } @@ -875,18 +873,9 @@ struct AmbiguityError<'ra> { } impl<'ra> NameBindingData<'ra> { - fn module(&self) -> Option> { - match self.kind { - NameBindingKind::Module(module) => Some(module), - NameBindingKind::Import { binding, .. } => binding.module(), - _ => None, - } - } - fn res(&self) -> Res { match self.kind { NameBindingKind::Res(res) => res, - NameBindingKind::Module(module) => module.res().unwrap(), NameBindingKind::Import { binding, .. } => binding.res(), } } @@ -921,7 +910,7 @@ impl<'ra> NameBindingData<'ra> { DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _, )) => true, - NameBindingKind::Res(..) | NameBindingKind::Module(..) => false, + NameBindingKind::Res(..) => false, } } @@ -930,11 +919,7 @@ impl<'ra> NameBindingData<'ra> { NameBindingKind::Import { import, .. } => { matches!(import.kind, ImportKind::ExternCrate { .. }) } - NameBindingKind::Module(module) - if let ModuleKind::Def(DefKind::Mod, def_id, _) = module.kind => - { - def_id.is_crate_root() - } + NameBindingKind::Res(Res::Def(_, def_id)) => def_id.is_crate_root(), _ => false, } } @@ -1279,7 +1264,8 @@ impl<'ra> ResolverArenas<'ra> { if let Some(def_id) = def_id { module_map.insert(def_id, module); let vis = ty::Visibility::::Public; - let binding = (module, vis, module.span, LocalExpnId::ROOT).to_name_binding(self); + let res = module.res().unwrap(); + let binding = (res, vis, module.span, LocalExpnId::ROOT).to_name_binding(self); module_self_bindings.insert(module, binding); } module @@ -1838,7 +1824,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module.ensure_traits(self); let traits = module.traits.borrow(); for (trait_name, trait_binding) in traits.as_ref().unwrap().iter() { - if self.trait_may_have_item(trait_binding.module(), assoc_item) { + let trait_module = self.get_module(trait_binding.res().def_id()); + if self.trait_may_have_item(trait_module, assoc_item) { let def_id = trait_binding.res().def_id(); let import_ids = self.find_transitive_imports(&trait_binding.kind, *trait_name); found_traits.push(TraitCandidate { def_id, import_ids }); @@ -2174,9 +2161,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { self.crate_loader(|c| c.maybe_process_path_extern(ident.name))? }; - let crate_root = self.expect_module(crate_id.as_def_id()); + let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); let vis = ty::Visibility::::Public; - (crate_root, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas) + (res, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas) }) }); diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout index 1734b9afe92e..91d16eca1b0a 100644 --- a/tests/ui/proc-macro/meta-macro-hygiene.stdout +++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout @@ -49,12 +49,6 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index 42257312a872..63741326e341 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -72,12 +72,6 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #3, kind: Macro(Bang, "inner") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) From 01b546a19b36bebddc8fbb175837a1d90010d8bd Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 4 Jul 2025 23:53:34 +0300 Subject: [PATCH 218/363] resolve: Remove trait `ToNameBinding` --- .../rustc_resolve/src/build_reduced_graph.rs | 83 ++++++++++--------- compiler/rustc_resolve/src/ident.rs | 13 +-- compiler/rustc_resolve/src/imports.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 57 ++++++++----- compiler/rustc_resolve/src/macros.rs | 7 +- 5 files changed, 84 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index a51cdbe76ee3..4065dbca6751 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -33,39 +33,42 @@ use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::{ BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, - NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, ResolutionError, - Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError, errors, + NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Used, + VisResolutionError, errors, }; type Res = def::Res; -impl<'ra, Id: Into> ToNameBinding<'ra> for (Res, ty::Visibility, Span, LocalExpnId) { - fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { - arenas.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Res(self.0), - ambiguity: None, - warn_ambiguity: false, - vis: self.1.to_def_id(), - span: self.2, - expansion: self.3, - }) - } -} - 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(&mut self, parent: Module<'ra>, ident: Ident, ns: Namespace, def: T) - where - T: ToNameBinding<'ra>, - { - let binding = def.to_name_binding(self.arenas); + pub(crate) fn define_binding( + &mut self, + parent: Module<'ra>, + ident: Ident, + ns: Namespace, + binding: NameBinding<'ra>, + ) { let key = self.new_disambiguated_key(ident, ns); if let Err(old_binding) = self.try_define(parent, key, binding, false) { self.report_conflict(parent, ident, ns, old_binding, binding); } } + fn define( + &mut self, + parent: Module<'ra>, + ident: Ident, + ns: Namespace, + res: Res, + vis: ty::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) + } + /// Walks up the tree of definitions starting at `def_id`, /// stopping at the first encountered module. /// Parent block modules for arbitrary def-ids are not recorded for the local crate, @@ -223,7 +226,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _, ) | Res::PrimTy(..) - | Res::ToolMod => self.define(parent, ident, TypeNS, (res, vis, span, expansion)), + | Res::ToolMod => self.define(parent, ident, TypeNS, res, vis, span, expansion), Res::Def( DefKind::Fn | DefKind::AssocFn @@ -232,9 +235,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | DefKind::AssocConst | DefKind::Ctor(..), _, - ) => self.define(parent, ident, ValueNS, (res, vis, span, expansion)), + ) => self.define(parent, ident, ValueNS, res, vis, span, expansion), Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => { - self.define(parent, ident, MacroNS, (res, vis, span, expansion)) + self.define(parent, ident, MacroNS, res, vis, span, expansion) } Res::Def( DefKind::TyParam @@ -698,7 +701,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { 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(parent, ident, TypeNS, adt_res, adt_vis, adt_span, expansion); self.r.feed_visibility(feed, adt_vis); let def_id = feed.key(); @@ -750,7 +753,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ItemKind::Mod(_, ident, ref mod_kind) => { - self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { self.r.mods_with_parse_errors.insert(def_id); @@ -769,10 +772,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { 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(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(parent, ident, ValueNS, res, vis, sp, expansion); // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). @@ -781,11 +784,11 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // 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(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(parent, ident, TypeNS, res, vis, sp, expansion); self.parent_scope.module = self.r.new_module( Some(parent), @@ -837,7 +840,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { 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(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()); @@ -901,9 +904,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } .map(|module| { let used = self.process_macro_use_imports(item, module); - let res = module.res().unwrap(); - let vis = ty::Visibility::::Public; - let binding = (res, vis, sp, expansion).to_name_binding(self.r.arenas); + let binding = self.r.arenas.new_pub_res_binding(module.res().unwrap(), sp, expansion); (used, Some(ModuleOrUniformRoot::Module(module)), binding) }) .unwrap_or((true, None, self.r.dummy_binding)); @@ -960,7 +961,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ); } } - self.r.define(parent, ident, TypeNS, imported_binding); + self.r.define_binding(parent, ident, TypeNS, imported_binding); } /// Constructs the reduced graph for one foreign item. @@ -977,7 +978,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { 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(parent, ident, ns, self.res(def_id), vis, item.span, expansion); self.r.feed_visibility(feed, vis); } @@ -1217,7 +1218,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } else { ty::Visibility::Restricted(CRATE_DEF_ID) }; - let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas); + let binding = self.r.arenas.new_res_binding(res, vis.to_def_id(), span, expansion); self.r.set_binding_parent_module(binding, parent_scope.module); self.r.all_macro_rules.insert(ident.name); if is_macro_export { @@ -1236,7 +1237,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); self.r.import_use_map.insert(import, Used::Other); let import_binding = self.r.import(binding, import); - self.r.define(self.r.graph_root, ident, MacroNS, import_binding); + self.r.define_binding(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); @@ -1264,7 +1265,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { 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(module, ident, MacroNS, res, vis, span, expansion); self.r.feed_visibility(feed, vis); self.parent_scope.macro_rules } @@ -1400,7 +1401,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { 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(parent, ident, ns, self.res(def_id), vis, item.span, expansion); } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) { let impl_def_id = self.r.tcx.local_parent(local_def_id); let key = BindingKey::new(ident.normalize_to_macros_2_0(), ns); @@ -1485,7 +1486,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { 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(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. @@ -1501,7 +1502,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { 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(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/ident.rs b/compiler/rustc_resolve/src/ident.rs index 04f9e35b6b46..84d66c15f00c 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -3,11 +3,10 @@ use Namespace::*; use rustc_ast::{self as ast, NodeId}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS}; -use rustc_middle::{bug, ty}; +use rustc_middle::bug; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::parse::feature_err; -use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; use rustc_span::{Ident, Span, kw, sym}; use tracing::{debug, instrument}; @@ -20,11 +19,9 @@ use crate::{ AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, Determinacy, Finalize, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, - ScopeSet, Segment, ToNameBinding, Used, Weak, errors, + ScopeSet, Segment, Used, Weak, errors, }; -type Visibility = ty::Visibility; - #[derive(Copy, Clone)] pub enum UsePrelude { No, @@ -464,13 +461,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) { - let binding = ( + let binding = this.arenas.new_pub_res_binding( Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat), - Visibility::Public, derive.span, LocalExpnId::ROOT, - ) - .to_name_binding(this.arenas); + ); result = Ok((binding, Flags::empty())); break; } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 2fa20b254698..59896ee88f4c 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -872,7 +872,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // We need the `target`, `source` can be extracted. let imported_binding = this.import(binding, import); - this.define(parent, target, ns, imported_binding); + this.define_binding(parent, target, ns, imported_binding); PendingBinding::Ready(Some(imported_binding)) } Err(Determinacy::Determined) => { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index eb2b92604836..cf106a4892c7 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -768,16 +768,6 @@ impl std::hash::Hash for NameBindingData<'_> { } } -trait ToNameBinding<'ra> { - fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra>; -} - -impl<'ra> ToNameBinding<'ra> for NameBinding<'ra> { - fn to_name_binding(self, _: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { - self - } -} - #[derive(Clone, Copy, Debug)] enum NameBindingKind<'ra> { Res(Res), @@ -1240,6 +1230,32 @@ pub struct ResolverArenas<'ra> { } impl<'ra> ResolverArenas<'ra> { + fn new_res_binding( + &'ra self, + res: Res, + vis: ty::Visibility, + span: Span, + expansion: LocalExpnId, + ) -> NameBinding<'ra> { + self.alloc_name_binding(NameBindingData { + kind: NameBindingKind::Res(res), + ambiguity: None, + warn_ambiguity: false, + vis, + span, + expansion, + }) + } + + fn new_pub_res_binding( + &'ra self, + res: Res, + span: Span, + expn_id: LocalExpnId, + ) -> NameBinding<'ra> { + self.new_res_binding(res, Visibility::Public, span, expn_id) + } + fn new_module( &'ra self, parent: Option>, @@ -1263,9 +1279,8 @@ impl<'ra> ResolverArenas<'ra> { } if let Some(def_id) = def_id { module_map.insert(def_id, module); - let vis = ty::Visibility::::Public; let res = module.res().unwrap(); - let binding = (res, vis, module.span, LocalExpnId::ROOT).to_name_binding(self); + let binding = self.new_pub_res_binding(res, module.span, LocalExpnId::ROOT); module_self_bindings.insert(module, binding); } module @@ -1456,8 +1471,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let registered_tools = tcx.registered_tools(()); - - let pub_vis = ty::Visibility::::Public; let edition = tcx.sess.edition(); let mut resolver = Resolver { @@ -1506,12 +1519,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { macro_expanded_macro_export_errors: BTreeSet::new(), arenas, - dummy_binding: (Res::Err, pub_vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(arenas), + dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT), builtin_types_bindings: PrimTy::ALL .iter() .map(|prim_ty| { - let binding = (Res::PrimTy(*prim_ty), pub_vis, DUMMY_SP, LocalExpnId::ROOT) - .to_name_binding(arenas); + let res = Res::PrimTy(*prim_ty); + let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); (prim_ty.name(), binding) }) .collect(), @@ -1519,16 +1532,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .iter() .map(|builtin_attr| { let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(builtin_attr.name)); - let binding = - (res, pub_vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(arenas); + let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); (builtin_attr.name, binding) }) .collect(), registered_tool_bindings: registered_tools .iter() .map(|ident| { - let binding = (Res::ToolMod, pub_vis, ident.span, LocalExpnId::ROOT) - .to_name_binding(arenas); + let res = Res::ToolMod; + let binding = arenas.new_pub_res_binding(res, ident.span, LocalExpnId::ROOT); (*ident, binding) }) .collect(), @@ -2162,8 +2174,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.crate_loader(|c| c.maybe_process_path_extern(ident.name))? }; let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); - let vis = ty::Visibility::::Public; - (res, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas) + self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT) }) }); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index cbb24289f51f..c17d74659db3 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -20,7 +20,7 @@ use rustc_expand::expand::{ use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_middle::middle::stability; -use rustc_middle::ty::{RegisteredTools, TyCtxt, Visibility}; +use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_DIAGNOSTIC_ATTRIBUTES, @@ -41,7 +41,7 @@ use crate::imports::Import; use crate::{ BindingKey, DeriveData, Determinacy, Finalize, InvocationParent, MacroData, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError, - Resolver, ScopeSet, Segment, ToNameBinding, Used, + Resolver, ScopeSet, Segment, Used, }; type Res = def::Res; @@ -436,8 +436,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { .iter() .map(|(_, ident)| { let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); - let binding = (res, Visibility::::Public, ident.span, expn_id) - .to_name_binding(self.arenas); + let binding = self.arenas.new_pub_res_binding(res, ident.span, expn_id); (*ident, binding) }) .collect(); From 4fa23d96bc9334716b8f50511f5a920b46d349dd Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 15 Jul 2025 22:28:05 -0700 Subject: [PATCH 219/363] Improve comments inside `codegen_get_discr` --- compiler/rustc_codegen_ssa/src/mir/operand.rs | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 9910cb5469fc..6a3fdb6ede18 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -517,8 +517,52 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64); (is_niche, tagged_discr, 0) } else { - // The special cases don't apply, so we'll have to go with - // the general algorithm. + // With multiple niched variants we'll have to actually compute + // the variant index from the stored tag. + // + // However, there's still one small optimization we can often do for + // determining *whether* a tag value is a natural value or a niched + // variant. The general algorithm involves a subtraction that often + // wraps in practice, making it tricky to analyse. However, in cases + // where there are few enough possible values of the tag that it doesn't + // need to wrap around, we can instead just look for the contiguous + // tag values on the end of the range with a single comparison. + // + // For example, take the type `enum Demo { A, B, Untagged(bool) }`. + // The `bool` is {0, 1}, and the two other variants are given the + // tags {2, 3} respectively. That means the `tag_range` is + // `[0, 3]`, which doesn't wrap as unsigned (nor as signed), so + // we can test for the niched variants with just `>= 2`. + // + // That means we're looking either for the niche values *above* + // the natural values of the untagged variant: + // + // niche_start niche_end + // | | + // v v + // MIN -------------+---------------------------+---------- MAX + // ^ | is niche | + // | +---------------------------+ + // | | + // tag_range.start tag_range.end + // + // Or *below* the natural values: + // + // niche_start niche_end + // | | + // v v + // MIN ----+-----------------------+---------------------- MAX + // | is niche | ^ + // +-----------------------+ | + // | | + // tag_range.start tag_range.end + // + // With those two options and having the flexibility to choose + // between a signed or unsigned comparison on the tag, that + // covers most realistic scenarios. The tests have a (contrived) + // example of a 1-byte enum with over 128 niched variants which + // wraps both as signed as unsigned, though, and for something + // like that we're stuck with the general algorithm. let tag_range = tag_scalar.valid_range(&dl); let tag_size = tag_scalar.size(&dl); From 1a9a226058a31fab77229afc4b0e04c259c64112 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 5 Jul 2025 00:43:52 +0300 Subject: [PATCH 220/363] resolve: Import `ty::Visibility` everywhere --- .../rustc_resolve/src/build_reduced_graph.rs | 44 +++++++++---------- compiler/rustc_resolve/src/imports.rs | 9 ++-- compiler/rustc_resolve/src/late.rs | 8 ++-- compiler/rustc_resolve/src/lib.rs | 20 ++++----- 4 files changed, 39 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 4065dbca6751..5a1be618ceea 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -20,9 +20,9 @@ use rustc_hir::def::{self, *}; 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; -use rustc_middle::{bug, ty}; +use rustc_middle::ty::{Feed, Visibility}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::{Ident, Span, Symbol, kw, sym}; use tracing::debug; @@ -61,7 +61,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident: Ident, ns: Namespace, res: Res, - vis: ty::Visibility>, + vis: Visibility>, span: Span, expn_id: LocalExpnId, ) { @@ -281,10 +281,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { Res::Def(self.r.tcx.def_kind(def_id), def_id) } - fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility { + fn resolve_visibility(&mut self, vis: &ast::Visibility) -> Visibility { self.try_resolve_visibility(vis, true).unwrap_or_else(|err| { self.r.report_vis_error(err); - ty::Visibility::Public + Visibility::Public }) } @@ -292,10 +292,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { &mut self, vis: &'ast ast::Visibility, finalize: bool, - ) -> Result> { + ) -> Result> { let parent_scope = &self.parent_scope; match vis.kind { - ast::VisibilityKind::Public => Ok(ty::Visibility::Public), + ast::VisibilityKind::Public => Ok(Visibility::Public), ast::VisibilityKind::Inherited => { Ok(match self.parent_scope.module.kind { // Any inherited visibility resolved directly inside an enum or trait @@ -305,7 +305,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.tcx.visibility(def_id).expect_local() } // Otherwise, the visibility is restricted to the nearest parent `mod` item. - _ => ty::Visibility::Restricted( + _ => Visibility::Restricted( self.parent_scope.module.nearest_parent_mod().expect_local(), ), }) @@ -353,9 +353,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } if module.is_normal() { match res { - Res::Err => Ok(ty::Visibility::Public), + Res::Err => Ok(Visibility::Public), _ => { - let vis = ty::Visibility::Restricted(res.def_id()); + let vis = Visibility::Restricted(res.def_id()); if self.r.is_accessible_from(vis, parent_scope.module) { Ok(vis.expect_local()) } else { @@ -420,7 +420,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { item: &ast::Item, root_span: Span, root_id: NodeId, - vis: ty::Visibility, + vis: Visibility, ) { let current_module = self.parent_scope.module; let import = self.r.arenas.alloc_import(ImportData { @@ -468,7 +468,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { list_stem: bool, // The whole `use` item item: &Item, - vis: ty::Visibility, + vis: Visibility, root_span: Span, ) { debug!( @@ -677,7 +677,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { true, // The whole `use` item item, - ty::Visibility::Restricted( + Visibility::Restricted( self.parent_scope.module.nearest_parent_mod().expect_local(), ), root_span, @@ -693,7 +693,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ident: Ident, feed: Feed<'tcx, LocalDefId>, adt_res: Res, - adt_vis: ty::Visibility, + adt_vis: Visibility, adt_span: Span, ) { let parent_scope = &self.parent_scope; @@ -818,7 +818,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let mut ctor_vis = if vis.is_public() && ast::attr::contains_name(&item.attrs, sym::non_exhaustive) { - ty::Visibility::Restricted(CRATE_DEF_ID) + Visibility::Restricted(CRATE_DEF_ID) } else { vis }; @@ -831,7 +831,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // constructor visibility should still be determined correctly. let field_vis = self .try_resolve_visibility(&field.vis, false) - .unwrap_or(ty::Visibility::Public); + .unwrap_or(Visibility::Public); if ctor_vis.is_at_least(field_vis, self.r.tcx) { ctor_vis = field_vis; } @@ -880,7 +880,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { item: &Item, ident: Ident, local_def_id: LocalDefId, - vis: ty::Visibility, + vis: Visibility, parent: Module<'ra>, ) { let sp = item.span; @@ -1064,7 +1064,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { root_span: span, span, module_path: Vec::new(), - vis: ty::Visibility::Restricted(CRATE_DEF_ID), + vis: Visibility::Restricted(CRATE_DEF_ID), }) }; @@ -1214,9 +1214,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.macro_names.insert(ident); let is_macro_export = ast::attr::contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { - ty::Visibility::Public + Visibility::Public } else { - ty::Visibility::Restricted(CRATE_DEF_ID) + Visibility::Restricted(CRATE_DEF_ID) }; let binding = self.r.arenas.new_res_binding(res, vis.to_def_id(), span, expansion); self.r.set_binding_parent_module(binding, parent_scope.module); @@ -1258,7 +1258,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // Visibilities must not be resolved non-speculatively twice // and we already resolved this one as a `fn` item visibility. ItemKind::Fn(..) => { - self.try_resolve_visibility(&item.vis, false).unwrap_or(ty::Visibility::Public) + self.try_resolve_visibility(&item.vis, false).unwrap_or(Visibility::Public) } _ => self.resolve_visibility(&item.vis), }; @@ -1492,7 +1492,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // If the variant is marked as non_exhaustive then lower the visibility to within the crate. let ctor_vis = if vis.is_public() && ast::attr::contains_name(&variant.attrs, sym::non_exhaustive) { - ty::Visibility::Restricted(CRATE_DEF_ID) + Visibility::Restricted(CRATE_DEF_ID) } else { vis }; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 59896ee88f4c..9a031ee03e0a 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -11,7 +11,8 @@ use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_hir::def_id::DefId; use rustc_middle::metadata::{ModChild, Reexport}; -use rustc_middle::{span_bug, ty}; +use rustc_middle::span_bug; +use rustc_middle::ty::Visibility; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, @@ -88,7 +89,7 @@ pub(crate) enum ImportKind<'ra> { is_prelude: bool, // The visibility of the greatest re-export. // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. - max_vis: Cell>, + max_vis: Cell>, id: NodeId, }, ExternCrate { @@ -185,7 +186,7 @@ pub(crate) struct ImportData<'ra> { /// |`use ::foo` | `ModuleOrUniformRoot::CrateRootAndExternPrelude` | a special case in 2015 edition | /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - | pub imported_module: Cell>>, - pub vis: ty::Visibility, + pub vis: Visibility, } /// All imports are unique and allocated on a same arena, @@ -1280,7 +1281,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !binding.vis.is_at_least(import.vis, this.tcx) { reexport_error = Some((ns, binding)); - if let ty::Visibility::Restricted(binding_def_id) = binding.vis + if let Visibility::Restricted(binding_def_id) = binding.vis && binding_def_id.is_top_level_module() { crate_private_reexport = true; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 44a567f78100..3ef98100d094 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -28,7 +28,7 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, Par use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; -use rustc_middle::ty::DelegationFnSig; +use rustc_middle::ty::{DelegationFnSig, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint::{self, BuiltinLintDiag}; @@ -638,8 +638,8 @@ impl PathSource<'_, '_, '_> { enum MaybeExported<'a> { Ok(NodeId), Impl(Option), - ImplItem(Result), - NestedUse(&'a Visibility), + ImplItem(Result), + NestedUse(&'a ast::Visibility), } impl MaybeExported<'_> { @@ -3463,7 +3463,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { span, "error should be emitted when an unexpected trait item is used", ); - rustc_middle::ty::Visibility::Public + Visibility::Public }; this.r.feed_visibility(this.r.feed(id), vis); }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cf106a4892c7..5c72a6bcf708 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -65,7 +65,7 @@ use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{ self, DelegationFnSig, Feed, MainDefinition, RegisteredTools, ResolverGlobalCtxt, - ResolverOutputs, TyCtxt, TyCtxtFeed, + ResolverOutputs, TyCtxt, TyCtxtFeed, Visibility, }; use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; @@ -748,7 +748,7 @@ struct NameBindingData<'ra> { warn_ambiguity: bool, expansion: LocalExpnId, span: Span, - vis: ty::Visibility, + vis: Visibility, } /// All name bindings are unique and allocated on a same arena, @@ -1083,7 +1083,7 @@ pub struct Resolver<'ra, 'tcx> { /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap>, glob_error: Option, - visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>, + visibilities_for_hashing: Vec<(LocalDefId, Visibility)>, used_imports: FxHashSet, maybe_unused_trait_imports: FxIndexSet, @@ -1156,7 +1156,7 @@ pub struct Resolver<'ra, 'tcx> { /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. /// Also includes of list of each fields visibility - struct_constructors: LocalDefIdMap<(Res, ty::Visibility, Vec>)>, + struct_constructors: LocalDefIdMap<(Res, Visibility, Vec>)>, lint_buffer: LintBuffer, @@ -1233,7 +1233,7 @@ impl<'ra> ResolverArenas<'ra> { fn new_res_binding( &'ra self, res: Res, - vis: ty::Visibility, + vis: Visibility, span: Span, expansion: LocalExpnId, ) -> NameBinding<'ra> { @@ -1603,7 +1603,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let root_parent_scope = ParentScope::module(graph_root, &resolver); resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope); - resolver.feed_visibility(crate_feed, ty::Visibility::Public); + resolver.feed_visibility(crate_feed, Visibility::Public); resolver } @@ -1657,7 +1657,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Default::default() } - fn feed_visibility(&mut self, feed: Feed<'tcx, LocalDefId>, vis: ty::Visibility) { + fn feed_visibility(&mut self, feed: Feed<'tcx, LocalDefId>, vis: Visibility) { let feed = feed.upgrade(self.tcx); feed.visibility(vis.to_def_id()); self.visibilities_for_hashing.push((feed.def_id(), vis)); @@ -2109,11 +2109,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.pat_span_map.insert(node, span); } - fn is_accessible_from( - &self, - vis: ty::Visibility>, - module: Module<'ra>, - ) -> bool { + fn is_accessible_from(&self, vis: Visibility>, module: Module<'ra>) -> bool { vis.is_accessible_from(module.nearest_parent_mod(), self.tcx) } From 7f398fd5f6444bb57196519c2dbe9554c51d8318 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 5 Jul 2025 22:47:02 +0300 Subject: [PATCH 221/363] resolve: Optimize `fn traits_in_module` --- compiler/rustc_resolve/src/lib.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5c72a6bcf708..b0b29bc2eae2 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -579,7 +579,7 @@ struct ModuleData<'ra> { globs: RefCell>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. - traits: RefCell)]>>>, + traits: RefCell, Option>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -655,12 +655,12 @@ impl<'ra> Module<'ra> { let mut traits = self.traits.borrow_mut(); if traits.is_none() { let mut collected_traits = Vec::new(); - self.for_each_child(resolver, |_, name, ns, binding| { + self.for_each_child(resolver, |r, name, ns, binding| { if ns != TypeNS { return; } - if let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = binding.res() { - collected_traits.push((name, binding)) + if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() { + collected_traits.push((name, binding, r.as_mut().get_module(def_id))) } }); *traits = Some(collected_traits.into_boxed_slice()); @@ -1835,11 +1835,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { module.ensure_traits(self); let traits = module.traits.borrow(); - for (trait_name, trait_binding) in traits.as_ref().unwrap().iter() { - let trait_module = self.get_module(trait_binding.res().def_id()); + for &(trait_name, trait_binding, trait_module) in traits.as_ref().unwrap().iter() { if self.trait_may_have_item(trait_module, assoc_item) { let def_id = trait_binding.res().def_id(); - let import_ids = self.find_transitive_imports(&trait_binding.kind, *trait_name); + let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name); found_traits.push(TraitCandidate { def_id, import_ids }); } } From 42ec0280274acfa754ae88061ee6e77e7461fad1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 15 Jul 2025 17:16:53 +0200 Subject: [PATCH 222/363] type_id_eq: check that the hash fully matches the type --- .../src/interpret/intrinsics.rs | 99 ++++++++++--------- .../rustc_const_eval/src/interpret/memory.rs | 6 +- tests/ui/consts/const_transmute_type_id4.rs | 2 +- .../ui/consts/const_transmute_type_id4.stderr | 2 +- tests/ui/consts/const_transmute_type_id5.rs | 9 +- .../ui/consts/const_transmute_type_id5.stderr | 6 +- 6 files changed, 66 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 22d29eda913a..e24a355891db 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -4,8 +4,9 @@ use std::assert_matches::assert_matches; -use rustc_abi::{FieldIdx, Size}; +use rustc_abi::{FieldIdx, HasDataLayout, Size}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; +use rustc_middle::mir::interpret::{read_target_uint, write_target_uint}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; @@ -30,7 +31,7 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll } impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Generates a value of `TypeId` for `ty` in-place. - pub(crate) fn write_type_id( + fn write_type_id( &mut self, ty: Ty<'tcx>, dest: &PlaceTy<'tcx, M::Provenance>, @@ -48,8 +49,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Here we rely on `TypeId` being a newtype around an array of pointers, so we // first project to its only field and then the array elements. let alloc_id = tcx.reserve_and_set_type_id_alloc(ty); - let first = self.project_field(dest, FieldIdx::ZERO)?; - let mut elem_iter = self.project_array_fields(&first)?; + let arr = self.project_field(dest, FieldIdx::ZERO)?; + let mut elem_iter = self.project_array_fields(&arr)?; while let Some((_, elem)) = elem_iter.next(self)? { // Decorate this part of the hash with provenance; leave the integer part unchanged. let hash_fragment = self.read_scalar(&elem)?.to_target_usize(&tcx)?; @@ -61,6 +62,52 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(()) } + /// Read a value of type `TypeId`, returning the type it represents. + pub(crate) fn read_type_id( + &self, + op: &OpTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, Ty<'tcx>> { + // `TypeId` is a newtype around an array of pointers. All pointers must have the same + // provenance, and that provenance represents the type. + let ptr_size = self.pointer_size().bytes_usize(); + let arr = self.project_field(op, FieldIdx::ZERO)?; + + let mut ty_and_hash = None; + let mut elem_iter = self.project_array_fields(&arr)?; + while let Some((idx, elem)) = elem_iter.next(self)? { + let elem = self.read_pointer(&elem)?; + let (elem_ty, elem_hash) = self.get_ptr_type_id(elem)?; + // If this is the first element, remember the type and its hash. + // If this is not the first element, ensure it is consistent with the previous ones. + let full_hash = match ty_and_hash { + None => { + let hash = self.tcx.type_id_hash(elem_ty).as_u128(); + let mut hash_bytes = [0u8; 16]; + write_target_uint(self.data_layout().endian, &mut hash_bytes, hash).unwrap(); + ty_and_hash = Some((elem_ty, hash_bytes)); + hash_bytes + } + Some((ty, hash_bytes)) => { + if ty != elem_ty { + throw_ub_format!( + "invalid `TypeId` value: not all bytes carry the same type id metadata" + ); + } + hash_bytes + } + }; + // Ensure the elem_hash matches the corresponding part of the full hash. + let hash_frag = &full_hash[(idx as usize) * ptr_size..][..ptr_size]; + if read_target_uint(self.data_layout().endian, hash_frag).unwrap() != elem_hash.into() { + throw_ub_format!( + "invalid `TypeId` value: the hash does not match the type id metadata" + ); + } + } + + interp_ok(ty_and_hash.unwrap().0) + } + /// Returns `true` if emulation happened. /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own /// intrinsic handling. @@ -97,47 +144,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_type_id(tp_ty, dest)?; } sym::type_id_eq => { - // Both operands are `TypeId`, which is a newtype around an array of pointers. - // Project until we have the array elements. - let a_fields = self.project_field(&args[0], FieldIdx::ZERO)?; - let b_fields = self.project_field(&args[1], FieldIdx::ZERO)?; - - let mut a_fields = self.project_array_fields(&a_fields)?; - let mut b_fields = self.project_array_fields(&b_fields)?; - - let mut provenance_a = None; - let mut provenance_b = None; - let mut provenance_matches = true; - - while let Some((i, a)) = a_fields.next(self)? { - let (_, b) = b_fields.next(self)?.unwrap(); - - let a = self.deref_pointer(&a)?; - let (a, offset_a) = self.get_ptr_type_id(a.ptr())?; - - let b = self.deref_pointer(&b)?; - let (b, offset_b) = self.get_ptr_type_id(b.ptr())?; - - if *provenance_a.get_or_insert(a) != a { - throw_ub_format!( - "type_id_eq: the first TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's" - ) - } - if *provenance_b.get_or_insert(b) != b { - throw_ub_format!( - "type_id_eq: the second TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's" - ) - } - provenance_matches &= a == b; - - if offset_a != offset_b && provenance_matches { - throw_ub_format!( - "type_id_eq: one of the TypeId arguments is invalid, chunk {i} of the hash does not match the type it represents" - ) - } - } - - self.write_scalar(Scalar::from_bool(provenance_matches), dest)?; + let a_ty = self.read_type_id(&args[0])?; + let b_ty = self.read_type_id(&args[1])?; + self.write_scalar(Scalar::from_bool(a_ty == b_ty), dest)?; } sym::variant_count => { let tp_ty = instance.args.type_at(0); diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 6414821e21d0..e77467ab4126 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -951,12 +951,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn get_ptr_type_id( &self, ptr: Pointer>, - ) -> InterpResult<'tcx, (Ty<'tcx>, Size)> { + ) -> InterpResult<'tcx, (Ty<'tcx>, u64)> { let (alloc_id, offset, _meta) = self.ptr_get_alloc_id(ptr, 0)?; let GlobalAlloc::TypeId { ty } = self.tcx.global_alloc(alloc_id) else { - throw_ub_format!("type_id_eq: `TypeId` provenance is not a type id") + throw_ub_format!("invalid `TypeId` value: not all bytes carry type id metadata") }; - interp_ok((ty, offset)) + interp_ok((ty, offset.bytes())) } pub fn get_ptr_fn( diff --git a/tests/ui/consts/const_transmute_type_id4.rs b/tests/ui/consts/const_transmute_type_id4.rs index 22a607e9e0e2..0ea75f2a2f4d 100644 --- a/tests/ui/consts/const_transmute_type_id4.rs +++ b/tests/ui/consts/const_transmute_type_id4.rs @@ -10,7 +10,7 @@ const _: () = { std::ptr::write(ptr.offset(0), main as fn() as *const ()); } assert!(a == b); - //~^ ERROR: type_id_eq: `TypeId` provenance is not a type id + //~^ ERROR: invalid `TypeId` value }; fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id4.stderr b/tests/ui/consts/const_transmute_type_id4.stderr index b418a79d7f0f..b224227cf352 100644 --- a/tests/ui/consts/const_transmute_type_id4.stderr +++ b/tests/ui/consts/const_transmute_type_id4.stderr @@ -1,4 +1,4 @@ -error[E0080]: type_id_eq: `TypeId` provenance is not a type id +error[E0080]: invalid `TypeId` value: not all bytes carry type id metadata --> $DIR/const_transmute_type_id4.rs:12:13 | LL | assert!(a == b); diff --git a/tests/ui/consts/const_transmute_type_id5.rs b/tests/ui/consts/const_transmute_type_id5.rs index 0a9ba01e0dd7..ae0429f8dbb6 100644 --- a/tests/ui/consts/const_transmute_type_id5.rs +++ b/tests/ui/consts/const_transmute_type_id5.rs @@ -1,12 +1,11 @@ -//! Test that we require an equal TypeId to have the same integer -//! part, even if the provenance matches. +//! Test that we require an equal TypeId to have an integer part that properly +//! reflects the type id hash. #![feature(const_type_id, const_trait_impl, const_cmp)] use std::any::TypeId; const _: () = { - let a = TypeId::of::<()>(); let mut b = TypeId::of::<()>(); unsafe { let ptr = &mut b as *mut TypeId as *mut *const (); @@ -14,8 +13,8 @@ const _: () = { let val = std::ptr::read(ptr); std::ptr::write(ptr.offset(1), val); } - assert!(a == b); - //~^ ERROR: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents + assert!(b == b); + //~^ ERROR: invalid `TypeId` value }; fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id5.stderr b/tests/ui/consts/const_transmute_type_id5.stderr index 59823fcc1c9f..6205679ebb64 100644 --- a/tests/ui/consts/const_transmute_type_id5.stderr +++ b/tests/ui/consts/const_transmute_type_id5.stderr @@ -1,7 +1,7 @@ -error[E0080]: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents - --> $DIR/const_transmute_type_id5.rs:17:13 +error[E0080]: invalid `TypeId` value: the hash does not match the type id metadata + --> $DIR/const_transmute_type_id5.rs:16:13 | -LL | assert!(a == b); +LL | assert!(b == b); | ^^^^^^ evaluation of `_` failed inside this call | note: inside `::eq` From 0e423f441ade436bd732ececd3dd6c79885dd07c Mon Sep 17 00:00:00 2001 From: Edoardo Marangoni Date: Wed, 16 Jul 2025 09:24:30 +0200 Subject: [PATCH 223/363] Boostrap: add warning on `optimize = false` --- src/bootstrap/src/core/config/toml/rust.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index 0fae235bb93f..01fbd83317ec 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -541,6 +541,14 @@ impl Config { lld_enabled = lld_enabled_toml; std_features = std_features_toml; + if optimize_toml.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) { + eprintln!( + "WARNING: setting `optimize` to `false` is known to cause errors and \ + should be considered unsupported. Refer to `bootstrap.example.toml` \ + for more details." + ); + } + optimize = optimize_toml; self.rust_new_symbol_mangling = new_symbol_mangling; set(&mut self.rust_optimize_tests, optimize_tests); From 07a34c374b75730d7ba022135ac7929a2be6000e Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 15 Jul 2025 11:28:36 +0200 Subject: [PATCH 224/363] Make frame spans appear on a separate trace line This was done by making the tracing_chrome tracing layer check if "tracing_separate_line" was in the arguments of a span, and act accordingly. --- .../rustc_const_eval/src/interpret/stack.rs | 7 +- src/tools/miri/src/bin/log/tracing_chrome.rs | 72 +++++++++++++------ 2 files changed, 57 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index b6ba069526c0..2e99bb4209f2 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -12,6 +12,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_mir_dataflow::impls::always_storage_live_locals; use rustc_span::Span; +use tracing::field::Empty; use tracing::{info_span, instrument, trace}; use super::{ @@ -396,7 +397,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Finish things up. M::after_stack_push(self)?; self.frame_mut().loc = Left(mir::Location::START); - let span = info_span!("frame", "{}", instance); + // `tracing_separate_thread` is used to instruct the chrome_tracing [tracing::Layer] in Miri + // to put the "frame" span on a separate trace thread/line than other spans, to make the + // visualization in https://ui.perfetto.dev easier to interpret. It is set to a value of + // [tracing::field::Empty] so that other tracing layers (e.g. the logger) will ignore it. + let span = info_span!("frame", tracing_separate_thread = Empty, "{}", instance); self.frame_mut().tracing_span.enter(span); interp_ok(()) diff --git a/src/tools/miri/src/bin/log/tracing_chrome.rs b/src/tools/miri/src/bin/log/tracing_chrome.rs index 459acea6f0bf..5a96633c99e8 100644 --- a/src/tools/miri/src/bin/log/tracing_chrome.rs +++ b/src/tools/miri/src/bin/log/tracing_chrome.rs @@ -1,8 +1,18 @@ // SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: Copyright (c) 2020 Thoren Paulson -//! This file is taken unmodified from the following link, except for file attributes and -//! `extern crate` at the top. -//! https://github.com/thoren-d/tracing-chrome/blob/7e2625ab4aeeef2f0ef9bde9d6258dd181c04472/src/lib.rs +//! This file was initially taken from the following link: +//! +//! +//! The precise changes that were made to the original file can be found in git history +//! (`git log -- path/to/tracing_chrome.rs`), but in summary: +//! - the file attributes were changed and `extern crate` was added at the top +//! - if a tracing span has a field called "tracing_separate_thread", it will be given a separate +//! span ID even in [TraceStyle::Threaded] mode, to make it appear on a separate line when viewing +//! the trace in . This is the syntax to trigger this behavior: +//! ```rust +//! tracing::info_span!("my_span", tracing_separate_thread = tracing::field::Empty, /* ... */) +//! ``` +//! //! 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 //! not be possible to use the [ChromeLayer] in a context that expects a [Layer] from @@ -79,14 +89,26 @@ where } /// Decides how traces will be recorded. +/// Also see #[derive(Default)] pub enum TraceStyle { - /// Traces will be recorded as a group of threads. + /// Traces will be recorded as a group of threads, and all spans on the same thread will appear + /// on a single trace line in . /// In this style, spans should be entered and exited on the same thread. + /// + /// If a tracing span has a field called "tracing_separate_thread", it will be given a separate + /// span ID even in this mode, to make it appear on a separate line when viewing the trace in + /// . This is the syntax to trigger this behavior: + /// ```rust + /// tracing::info_span!("my_span", tracing_separate_thread = tracing::field::Empty, /* ... */) + /// ``` + /// [tracing::field::Empty] is used so that other tracing layers (e.g. the logger) will ignore + /// the "tracing_separate_thread" argument and not print out anything for it. #[default] Threaded, - /// Traces will recorded as a group of asynchronous operations. + /// Traces will recorded as a group of asynchronous operations. All spans will be given separate + /// span IDs and will appear on separate trace lines in . Async, } @@ -497,31 +519,39 @@ where } } - fn get_root_id(span: SpanRef) -> u64 { - span.scope() - .from_root() - .take(1) - .next() - .unwrap_or(span) - .id() - .into_u64() + fn get_root_id(&self, span: SpanRef) -> Option { + 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()) + } else { + None + } + }, + TraceStyle::Async => Some( + span.scope() + .from_root() + .take(1) + .next() + .unwrap_or(span) + .id() + .into_u64() + ), + } } fn enter_span(&self, span: SpanRef, ts: f64) { let callsite = self.get_callsite(EventOrSpan::Span(&span)); - let root_id = match self.trace_style { - TraceStyle::Async => Some(ChromeLayer::get_root_id(span)), - _ => None, - }; + let root_id = self.get_root_id(span); self.send_message(Message::Enter(ts, callsite, root_id)); } fn exit_span(&self, span: SpanRef, ts: f64) { let callsite = self.get_callsite(EventOrSpan::Span(&span)); - let root_id = match self.trace_style { - TraceStyle::Async => Some(ChromeLayer::get_root_id(span)), - _ => None, - }; + let root_id = self.get_root_id(span); self.send_message(Message::Exit(ts, callsite, root_id)); } From 06f0dca10600390f1e4d19fdefa3453d14238048 Mon Sep 17 00:00:00 2001 From: Nia Espera Date: Mon, 7 Jul 2025 18:37:47 +0200 Subject: [PATCH 225/363] hook up native-lib bits --- src/tools/miri/src/lib.rs | 1 + src/tools/miri/src/shims/native_lib/mod.rs | 123 +++++++++++++++--- .../miri/src/shims/native_lib/trace/parent.rs | 23 +++- .../native-lib/fail/tracing/partial_init.rs | 25 ++++ .../fail/tracing/partial_init.stderr | 39 ++++++ .../fail/tracing/unexposed_reachable_alloc.rs | 29 +++++ .../tracing/unexposed_reachable_alloc.stderr | 39 ++++++ ....stderr => ptr_read_access.notrace.stderr} | 0 ....stdout => ptr_read_access.notrace.stdout} | 0 .../tests/native-lib/pass/ptr_read_access.rs | 4 + .../pass/ptr_read_access.trace.stderr | 19 +++ .../pass/ptr_read_access.trace.stdout | 1 + ...stderr => ptr_write_access.notrace.stderr} | 0 .../tests/native-lib/pass/ptr_write_access.rs | 3 + .../pass/ptr_write_access.trace.stderr | 19 +++ .../miri/tests/native-lib/ptr_read_access.c | 6 + .../miri/tests/native-lib/ptr_write_access.c | 8 ++ 17 files changed, 314 insertions(+), 25 deletions(-) create mode 100644 src/tools/miri/tests/native-lib/fail/tracing/partial_init.rs create mode 100644 src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr create mode 100644 src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs create mode 100644 src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.stderr rename src/tools/miri/tests/native-lib/pass/{ptr_read_access.stderr => ptr_read_access.notrace.stderr} (100%) rename src/tools/miri/tests/native-lib/pass/{ptr_read_access.stdout => ptr_read_access.notrace.stdout} (100%) create mode 100644 src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr create mode 100644 src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stdout rename src/tools/miri/tests/native-lib/pass/{ptr_write_access.stderr => ptr_write_access.notrace.stderr} (100%) create mode 100644 src/tools/miri/tests/native-lib/pass/ptr_write_access.trace.stderr diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 374f63a16604..2010b4dae185 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -15,6 +15,7 @@ #![feature(unqualified_local_imports)] #![feature(derive_coerce_pointee)] #![feature(arbitrary_self_types)] +#![feature(iter_advance_by)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index a2a23c4813f0..fb7b1df41a4c 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -34,18 +34,25 @@ pub struct MemEvents { /// A single memory access. #[allow(dead_code)] #[cfg_attr(target_os = "linux", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum AccessEvent { - /// A read may have occurred on this memory range. - /// Some instructions *may* read memory without *always* doing that, - /// so this can be an over-approximation. - /// The range info, however, is reliable if the access did happen. + /// A read occurred on this memory range. Read(AccessRange), - /// A read may have occurred on this memory range. + /// A write may have occurred on this memory range. /// Some instructions *may* write memory without *always* doing that, /// so this can be an over-approximation. /// The range info, however, is reliable if the access did happen. - Write(AccessRange), + /// If the second field is true, the access definitely happened. + Write(AccessRange, bool), +} + +impl AccessEvent { + fn get_range(&self) -> AccessRange { + match self { + AccessEvent::Read(access_range) => access_range.clone(), + AccessEvent::Write(access_range, _) => access_range.clone(), + } + } } /// The memory touched by a given access. @@ -59,6 +66,12 @@ pub struct AccessRange { pub size: usize, } +impl AccessRange { + fn end(&self) -> usize { + self.addr.strict_add(self.size) + } +} + impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Call native host function and return the output as an immediate. @@ -196,6 +209,73 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } None } + + /// Applies the `events` to Miri's internal state. The event vector must be + /// ordered sequentially by when the accesses happened, and the sizes are + /// assumed to be exact. + fn tracing_apply_accesses(&mut self, events: MemEvents) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + for evt in events.acc_events { + let evt_rg = evt.get_range(); + // LLVM at least permits vectorising accesses to adjacent allocations, + // so we cannot assume 1 access = 1 allocation. :( + let mut rg = evt_rg.addr..evt_rg.end(); + while let Some(curr) = rg.next() { + let Some(alloc_id) = this.alloc_id_from_addr( + curr.to_u64(), + rg.len().try_into().unwrap(), + /* only_exposed_allocations */ true, + ) else { + throw_ub_format!("Foreign code did an out-of-bounds access!") + }; + let alloc = this.get_alloc_raw(alloc_id)?; + // The logical and physical address of the allocation coincide, so we can use + // this instead of `addr_from_alloc_id`. + let alloc_addr = alloc.get_bytes_unchecked_raw().addr(); + + // Determine the range inside the allocation that this access covers. This range is + // in terms of offsets from the start of `alloc`. The start of the overlap range + // will be `curr`; the end will be the minimum of the end of the allocation and the + // end of the access' range. + let overlap = curr.strict_sub(alloc_addr) + ..std::cmp::min(alloc.len(), rg.end.strict_sub(alloc_addr)); + // Skip forward however many bytes of the access are contained in the current + // allocation, subtracting 1 since the overlap range includes the current addr + // that was already popped off of the range. + rg.advance_by(overlap.len().strict_sub(1)).unwrap(); + + match evt { + AccessEvent::Read(_) => { + // FIXME: ProvenanceMap should have something like get_range(). + let p_map = alloc.provenance(); + for idx in overlap { + // If a provenance was read by the foreign code, expose it. + if let Some(prov) = p_map.get(Size::from_bytes(idx), this) { + this.expose_provenance(prov)?; + } + } + } + AccessEvent::Write(_, certain) => { + // Sometimes we aren't certain if a write happened, in which case we + // only initialise that data if the allocation is mutable. + if certain || alloc.mutability.is_mut() { + let (alloc, cx) = this.get_alloc_raw_mut(alloc_id)?; + alloc.process_native_write( + &cx.tcx, + Some(AllocRange { + start: Size::from_bytes(overlap.start), + size: Size::from_bytes(overlap.len()), + }), + ) + } + } + } + } + } + + interp_ok(()) + } } impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -221,6 +301,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } }; + // Do we have ptrace? + let tracing = trace::Supervisor::is_enabled(); + // Get the function arguments, and convert them to `libffi`-compatible form. let mut libffi_args = Vec::::with_capacity(args.len()); for arg in args.iter() { @@ -240,9 +323,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // The first time this happens, print a warning. if !this.machine.native_call_mem_warned.replace(true) { // Newly set, so first time we get here. - this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem { - tracing: self::trace::Supervisor::is_enabled(), - }); + this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem { tracing }); } this.expose_provenance(prov)?; @@ -269,15 +350,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // be read by FFI. The `black_box` is defensive programming as LLVM likes // to (incorrectly) optimize away ptr2int casts whose result is unused. std::hint::black_box(alloc.get_bytes_unchecked_raw().expose_provenance()); - // Expose all provenances in this allocation, since the native code can do $whatever. - for prov in alloc.provenance().provenances() { - this.expose_provenance(prov)?; + + if !tracing { + // Expose all provenances in this allocation, since the native code can do $whatever. + // Can be skipped when tracing; in that case we'll expose just the actually-read parts later. + for prov in alloc.provenance().provenances() { + this.expose_provenance(prov)?; + } } // Prepare for possible write from native code if mutable. if info.mutbl.is_mut() { let (alloc, cx) = this.get_alloc_raw_mut(alloc_id)?; - alloc.process_native_write(&cx.tcx, None); + // These writes could initialize everything and wreck havoc with the pointers. + // We can skip that when tracing; in that case we'll later do that only for the memory that got actually written. + if !tracing { + alloc.process_native_write(&cx.tcx, None); + } // Also expose *mutable* provenance for the interpreter-level allocation. std::hint::black_box(alloc.get_bytes_unchecked_raw_mut().expose_provenance()); } @@ -289,10 +378,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (ret, maybe_memevents) = this.call_native_with_args(link_name, dest, code_ptr, libffi_args)?; - if cfg!(target_os = "linux") - && let Some(events) = maybe_memevents - { - trace!("Registered FFI events:\n{events:#0x?}"); + if tracing { + this.tracing_apply_accesses(maybe_memevents.unwrap())?; } this.write_immediate(*ret, dest)?; diff --git a/src/tools/miri/src/shims/native_lib/trace/parent.rs b/src/tools/miri/src/shims/native_lib/trace/parent.rs index fc4047eec51d..83f6c7a13fcf 100644 --- a/src/tools/miri/src/shims/native_lib/trace/parent.rs +++ b/src/tools/miri/src/shims/native_lib/trace/parent.rs @@ -58,11 +58,11 @@ impl ArchIndependentRegs for libc::user_regs_struct { #[rustfmt::skip] impl ArchIndependentRegs for libc::user_regs_struct { #[inline] - fn ip(&self) -> usize { self.eip.try_into().unwrap() } + fn ip(&self) -> usize { self.eip.cast_unsigned().try_into().unwrap() } #[inline] - fn set_ip(&mut self, ip: usize) { self.eip = ip.try_into().unwrap() } + fn set_ip(&mut self, ip: usize) { self.eip = ip.cast_signed().try_into().unwrap() } #[inline] - fn set_sp(&mut self, sp: usize) { self.esp = sp.try_into().unwrap() } + fn set_sp(&mut self, sp: usize) { self.esp = sp.cast_signed().try_into().unwrap() } } /// A unified event representing something happening on the child process. Wraps @@ -386,7 +386,17 @@ fn capstone_find_events( acc_events.push(AccessEvent::Read(push.clone())); } if acc_ty.is_writable() { - acc_events.push(AccessEvent::Write(push)); + // FIXME: This could be made certain; either determine all cases where + // only reads happen, or have an intermediate mempr_* function to first + // map the page(s) as readonly and check if a segfault occurred. + + // Per https://docs.rs/iced-x86/latest/iced_x86/enum.OpAccess.html, + // we know that the possible access types are Read, CondRead, Write, + // CondWrite, ReadWrite, and ReadCondWrite. Since we got a segfault + // we know some kind of access happened so Cond{Read, Write}s are + // certain reads and writes; the only uncertainty is with an RW op + // as it might be a ReadCondWrite with the write condition unmet. + acc_events.push(AccessEvent::Write(push, !acc_ty.is_readable())); } return true; @@ -442,8 +452,7 @@ fn handle_segfault( // Get information on what caused the segfault. This contains the address // that triggered it. let siginfo = ptrace::getsiginfo(pid).unwrap(); - // All x86, ARM, etc. instructions only have at most one memory operand - // (thankfully!) + // All x86 instructions only have at most one memory operand (thankfully!) // SAFETY: si_addr is safe to call. let addr = unsafe { siginfo.si_addr().addr() }; let page_addr = addr.strict_sub(addr.strict_rem(page_size)); @@ -490,7 +499,7 @@ fn handle_segfault( ptrace::write( pid, (&raw const PAGE_ADDR).cast_mut().cast(), - libc::c_long::try_from(page_addr).unwrap(), + libc::c_long::try_from(page_addr.cast_signed()).unwrap(), ) .unwrap(); diff --git a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.rs b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.rs new file mode 100644 index 000000000000..e267f82e215b --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.rs @@ -0,0 +1,25 @@ +//@only-target: x86_64-unknown-linux-gnu i686-unknown-linux-gnu +//@compile-flags: -Zmiri-native-lib-enable-tracing + +extern "C" { + fn init_n(n: i32, ptr: *mut u8); +} + +fn main() { + partial_init(); +} + +// Initialise the first 2 elements of the slice from native code, and check +// that the 3rd is correctly deemed uninit. +fn partial_init() { + let mut slice = std::mem::MaybeUninit::<[u8; 3]>::uninit(); + let slice_ptr = slice.as_mut_ptr().cast::(); + unsafe { + // Initialize the first two elements. + init_n(2, slice_ptr); + assert!(*slice_ptr == 0); + assert!(*slice_ptr.offset(1) == 0); + // Reading the third is UB! + let _val = *slice_ptr.offset(2); //~ ERROR: Undefined Behavior: using uninitialized data + } +} diff --git a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr new file mode 100644 index 000000000000..84fd913b5e5b --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr @@ -0,0 +1,39 @@ +warning: sharing memory with a native function called via FFI + --> tests/native-lib/fail/tracing/partial_init.rs:LL:CC + | +LL | init_n(2, slice_ptr); + | ^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function + | + = help: when memory is shared with a native function call, Miri can only track initialisation and provenance on a best-effort basis + = help: in particular, Miri assumes that the native call initializes all memory it has written to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here + = note: BACKTRACE: + = note: inside `partial_init` at tests/native-lib/fail/tracing/partial_init.rs:LL:CC +note: inside `main` + --> tests/native-lib/fail/tracing/partial_init.rs:LL:CC + | +LL | partial_init(); + | ^^^^^^^^^^^^^^ + +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> tests/native-lib/fail/tracing/partial_init.rs:LL:CC + | +LL | let _val = *slice_ptr.offset(2); + | ^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `partial_init` at tests/native-lib/fail/tracing/partial_init.rs:LL:CC +note: inside `main` + --> tests/native-lib/fail/tracing/partial_init.rs:LL:CC + | +LL | partial_init(); + | ^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs b/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs new file mode 100644 index 000000000000..b78c29d98dbb --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs @@ -0,0 +1,29 @@ +//@only-target: x86_64-unknown-linux-gnu i686-unknown-linux-gnu +//@compile-flags: -Zmiri-permissive-provenance -Zmiri-native-lib-enable-tracing + +extern "C" { + fn do_one_deref(ptr: *const *const *const i32) -> usize; +} + +fn main() { + unexposed_reachable_alloc(); +} + +// Expose 2 pointers by virtue of doing a native read and assert that the 3rd in +// the chain remains properly unexposed. +fn unexposed_reachable_alloc() { + let inner = 42; + let intermediate_a = &raw const inner; + let intermediate_b = &raw const intermediate_a; + let exposed = &raw const intermediate_b; + // Discard the return value; it's just there so the access in C doesn't get optimised away. + unsafe { do_one_deref(exposed) }; + // Native read should have exposed the address of intermediate_b... + let valid: *const i32 = std::ptr::with_exposed_provenance(intermediate_b.addr()); + // but not of intermediate_a. + let invalid: *const i32 = std::ptr::with_exposed_provenance(intermediate_a.addr()); + unsafe { + let _ok = *valid; + let _not_ok = *invalid; //~ ERROR: Undefined Behavior: memory access failed: attempting to access + } +} diff --git a/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.stderr b/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.stderr new file mode 100644 index 000000000000..2d34dac1b3ff --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.stderr @@ -0,0 +1,39 @@ +warning: sharing memory with a native function called via FFI + --> tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC + | +LL | unsafe { do_one_deref(exposed) }; + | ^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function + | + = help: when memory is shared with a native function call, Miri can only track initialisation and provenance on a best-effort basis + = help: in particular, Miri assumes that the native call initializes all memory it has written to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here + = note: BACKTRACE: + = note: inside `unexposed_reachable_alloc` at tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC +note: inside `main` + --> tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC + | +LL | unexposed_reachable_alloc(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + --> tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC + | +LL | let _not_ok = *invalid; + | ^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `unexposed_reachable_alloc` at tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC +note: inside `main` + --> tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC + | +LL | unexposed_reachable_alloc(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.stderr b/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr similarity index 100% rename from src/tools/miri/tests/native-lib/pass/ptr_read_access.stderr rename to src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.stdout b/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stdout similarity index 100% rename from src/tools/miri/tests/native-lib/pass/ptr_read_access.stdout rename to src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stdout diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs index 4c8521353678..4f3c37f00c1d 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs @@ -1,3 +1,7 @@ +//@revisions: trace notrace +//@[trace] only-target: x86_64-unknown-linux-gnu i686-unknown-linux-gnu +//@[trace] compile-flags: -Zmiri-native-lib-enable-tracing + fn main() { test_access_pointer(); test_access_simple(); diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr new file mode 100644 index 000000000000..c2a4508b7fcc --- /dev/null +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr @@ -0,0 +1,19 @@ +warning: sharing memory with a native function called via FFI + --> tests/native-lib/pass/ptr_read_access.rs:LL:CC + | +LL | unsafe { print_pointer(&x) }; + | ^^^^^^^^^^^^^^^^^ sharing memory with a native function + | + = help: when memory is shared with a native function call, Miri can only track initialisation and provenance on a best-effort basis + = help: in particular, Miri assumes that the native call initializes all memory it has written to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here + = note: BACKTRACE: + = note: inside `test_access_pointer` at tests/native-lib/pass/ptr_read_access.rs:LL:CC +note: inside `main` + --> tests/native-lib/pass/ptr_read_access.rs:LL:CC + | +LL | test_access_pointer(); + | ^^^^^^^^^^^^^^^^^^^^^ + diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stdout b/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stdout new file mode 100644 index 000000000000..1a8799abfc93 --- /dev/null +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stdout @@ -0,0 +1 @@ +printing pointer dereference from C: 42 diff --git a/src/tools/miri/tests/native-lib/pass/ptr_write_access.stderr b/src/tools/miri/tests/native-lib/pass/ptr_write_access.notrace.stderr similarity index 100% rename from src/tools/miri/tests/native-lib/pass/ptr_write_access.stderr rename to src/tools/miri/tests/native-lib/pass/ptr_write_access.notrace.stderr diff --git a/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs index 86a9c97f4cec..57def78b0ab1 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs +++ b/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs @@ -1,3 +1,6 @@ +//@revisions: trace notrace +//@[trace] only-target: x86_64-unknown-linux-gnu i686-unknown-linux-gnu +//@[trace] compile-flags: -Zmiri-native-lib-enable-tracing //@compile-flags: -Zmiri-permissive-provenance #![feature(box_as_ptr)] diff --git a/src/tools/miri/tests/native-lib/pass/ptr_write_access.trace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_write_access.trace.stderr new file mode 100644 index 000000000000..dbf021b15bec --- /dev/null +++ b/src/tools/miri/tests/native-lib/pass/ptr_write_access.trace.stderr @@ -0,0 +1,19 @@ +warning: sharing memory with a native function called via FFI + --> tests/native-lib/pass/ptr_write_access.rs:LL:CC + | +LL | unsafe { increment_int(&mut x) }; + | ^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function + | + = help: when memory is shared with a native function call, Miri can only track initialisation and provenance on a best-effort basis + = help: in particular, Miri assumes that the native call initializes all memory it has written to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here + = note: BACKTRACE: + = note: inside `test_increment_int` at tests/native-lib/pass/ptr_write_access.rs:LL:CC +note: inside `main` + --> tests/native-lib/pass/ptr_write_access.rs:LL:CC + | +LL | test_increment_int(); + | ^^^^^^^^^^^^^^^^^^^^ + diff --git a/src/tools/miri/tests/native-lib/ptr_read_access.c b/src/tools/miri/tests/native-lib/ptr_read_access.c index b89126d3d7c8..021eb6adca4f 100644 --- a/src/tools/miri/tests/native-lib/ptr_read_access.c +++ b/src/tools/miri/tests/native-lib/ptr_read_access.c @@ -49,3 +49,9 @@ typedef struct Static { EXPORT int32_t access_static(const Static *s_ptr) { return s_ptr->recurse->recurse->value; } + +/* Test: unexposed_reachable_alloc */ + +EXPORT uintptr_t do_one_deref(const int32_t ***ptr) { + return (uintptr_t)*ptr; +} diff --git a/src/tools/miri/tests/native-lib/ptr_write_access.c b/src/tools/miri/tests/native-lib/ptr_write_access.c index fd8b005499c7..5260d0b36517 100644 --- a/src/tools/miri/tests/native-lib/ptr_write_access.c +++ b/src/tools/miri/tests/native-lib/ptr_write_access.c @@ -107,3 +107,11 @@ EXPORT void set_shared_mem(int32_t** ptr) { EXPORT void init_ptr_stored_in_shared_mem(int32_t val) { **shared_place = val; } + +/* Test: partial_init */ + +EXPORT void init_n(int32_t n, char* ptr) { + for (int i=0; i Date: Wed, 16 Jul 2025 03:53:20 -0400 Subject: [PATCH 226/363] update comment to reference legacy `.ctors` section Co-authored-by: Ralf Jung --- src/tools/miri/src/shims/ctor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/ctor.rs b/src/tools/miri/src/shims/ctor.rs index 75f564989bc6..367c2b1608b4 100644 --- a/src/tools/miri/src/shims/ctor.rs +++ b/src/tools/miri/src/shims/ctor.rs @@ -52,7 +52,7 @@ impl<'tcx> GlobalCtorState<'tcx> { // Read the standard `.init_array` section on platforms that use ELF, or WASM, // which supports the same linker directive. - // FIXME: Add support for `.init_array.N`. + // FIXME: Add support for `.init_array.N` and `.ctors`? BinaryFormat::Elf | BinaryFormat::Wasm => this.lookup_link_section(|section| section == ".init_array")?, From a7818abc141a072ff069ed6c43ebbe56eade9c23 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Jul 2025 11:01:44 +0200 Subject: [PATCH 227/363] minor tweaks and comments --- src/tools/miri/src/concurrency/thread.rs | 2 + src/tools/miri/src/eval.rs | 41 ++++++++++--------- .../src/shims/{ctor.rs => global_ctor.rs} | 8 +++- src/tools/miri/src/shims/mod.rs | 2 +- .../miri/tests/pass/alloc-access-tracking.rs | 4 +- src/tools/miri/tests/pass/shims/ctor.rs | 3 ++ 6 files changed, 35 insertions(+), 25 deletions(-) rename src/tools/miri/src/shims/{ctor.rs => global_ctor.rs} (87%) diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index abfee0ee8746..878afdf25173 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -677,6 +677,8 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn run_on_stack_empty(&mut self) -> InterpResult<'tcx, Poll<()>> { let this = self.eval_context_mut(); // Inform GenMC that a thread has finished all user code. GenMC needs to know this for scheduling. + // FIXME(GenMC): Thread-local destructors *are* user code, so this is odd. Also now that we + // support pre-main constructors, it can get called there as well. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { let thread_id = this.active_thread(); genmc_ctx.handle_thread_stack_empty(thread_id); diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index d986f2830aa2..be6404f64e8f 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -18,7 +18,7 @@ use rustc_session::config::EntryFnType; use crate::concurrency::GenmcCtx; use crate::concurrency::thread::TlsAllocAction; use crate::diagnostics::report_leaks; -use crate::shims::{ctor, tls}; +use crate::shims::{global_ctor, tls}; use crate::*; #[derive(Copy, Clone, Debug)] @@ -219,9 +219,11 @@ impl Default for MiriConfig { #[derive(Debug)] enum MainThreadState<'tcx> { GlobalCtors { - ctor_state: ctor::GlobalCtorState<'tcx>, + ctor_state: global_ctor::GlobalCtorState<'tcx>, + /// The main function to call. entry_id: DefId, entry_type: MiriEntryFnType, + /// Arguments passed to `main`. argc: ImmTy<'tcx>, argv: ImmTy<'tcx>, }, @@ -324,12 +326,19 @@ pub fn create_ecx<'tcx>( MiriMachine::new(config, layout_cx, genmc_ctx), ); - // First argument is constructed later, because it's skipped for `miri_start.` + // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. + let sentinel = + 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." + ); + } - // Second argument (argc): length of `config.args`. + // Compute argc and argv from `config.args`. let argc = ImmTy::from_int(i64::try_from(config.args.len()).unwrap(), ecx.machine.layouts.isize); - // Third argument (`argv`): created from `config.args`. let argv = { // Put each argument in memory, collect pointers. let mut argvs = Vec::>::with_capacity(config.args.len()); @@ -354,7 +363,7 @@ pub fn create_ecx<'tcx>( ecx.write_immediate(arg, &place)?; } ecx.mark_immutable(&argvs_place); - // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. + // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`, and for the GC to see them. { let argc_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; @@ -369,7 +378,7 @@ pub fn create_ecx<'tcx>( ecx.machine.argv = Some(argv_place.ptr()); } // Store command line as UTF-16 for Windows `GetCommandLineW`. - { + if tcx.sess.target.os == "windows" { // Construct a command string with all the arguments. let cmd_utf16: Vec = args_to_utf16_command_string(config.args.iter()); @@ -392,28 +401,20 @@ pub fn create_ecx<'tcx>( // Some parts of initialization require a full `InterpCx`. MiriMachine::late_init(&mut ecx, config, { - let mut state = MainThreadState::GlobalCtors { + let mut main_thread_state = MainThreadState::GlobalCtors { entry_id, entry_type, argc, argv, - ctor_state: ctor::GlobalCtorState::default(), + ctor_state: global_ctor::GlobalCtorState::default(), }; // Cannot capture anything GC-relevant here. - Box::new(move |m| state.on_main_stack_empty(m)) + // `argc` and `argv` *are* GC_relevant, but they also get stored in `machine.argc` and + // `machine.argv` so we are good. + Box::new(move |m| main_thread_state.on_main_stack_empty(m)) })?; - // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. - let sentinel = - 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." - ); - } - interp_ok(ecx) } diff --git a/src/tools/miri/src/shims/ctor.rs b/src/tools/miri/src/shims/global_ctor.rs similarity index 87% rename from src/tools/miri/src/shims/ctor.rs rename to src/tools/miri/src/shims/global_ctor.rs index 367c2b1608b4..c56251bbe63a 100644 --- a/src/tools/miri/src/shims/ctor.rs +++ b/src/tools/miri/src/shims/global_ctor.rs @@ -45,8 +45,12 @@ impl<'tcx> GlobalCtorState<'tcx> { segment_name == Some("__DATA") && section_name == Some("__mod_init_func") - // The `mod_init_funcs` directive ensures that the `S_MOD_INIT_FUNC_POINTERS` flag - // is set on the section, but it is not strictly required. + // The `mod_init_funcs` directive ensures that the + // `S_MOD_INIT_FUNC_POINTERS` flag is set on the section. LLVM + // adds this automatically so we currently do not require it. + // FIXME: is this guaranteed LLVM behavior? If not, we shouldn't + // implicitly add it here. Also see + // . && matches!(section_type, None | Some("mod_init_funcs")) })?, diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 0faf298bfaa3..75540f6f1500 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -11,10 +11,10 @@ mod wasi; mod windows; mod x86; -pub mod ctor; pub mod env; pub mod extern_static; pub mod foreign_items; +pub mod global_ctor; pub mod io_error; pub mod os_str; pub mod panic; diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs index 0e88951dc43f..9eba0ca171bc 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.rs +++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -//@compile-flags: -Zmiri-track-alloc-id=20 -Zmiri-track-alloc-accesses -Cpanic=abort -//@normalize-stderr-test: "id 20" -> "id $$ALLOC" +//@compile-flags: -Zmiri-track-alloc-id=19 -Zmiri-track-alloc-accesses -Cpanic=abort +//@normalize-stderr-test: "id 19" -> "id $$ALLOC" //@only-target: linux # alloc IDs differ between OSes (due to extern static allocations) extern "Rust" { diff --git a/src/tools/miri/tests/pass/shims/ctor.rs b/src/tools/miri/tests/pass/shims/ctor.rs index c832e3f82a35..b997d2386b82 100644 --- a/src/tools/miri/tests/pass/shims/ctor.rs +++ b/src/tools/miri/tests/pass/shims/ctor.rs @@ -6,6 +6,7 @@ unsafe extern "C" fn ctor() { COUNT.fetch_add(1, Ordering::Relaxed); } +#[rustfmt::skip] macro_rules! ctor { ($ident:ident = $ctor:ident) => { #[cfg_attr( @@ -27,6 +28,8 @@ macro_rules! ctor { #[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 . link_section = "__DATA,__mod_init_func" )] #[used] From 47b138b2b89f91278b7825569b1bdad24f1eee6a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Jul 2025 18:11:07 +0200 Subject: [PATCH 228/363] Make aliases search support partial matching --- src/librustdoc/html/render/search_index.rs | 2 +- src/librustdoc/html/static/js/rustdoc.d.ts | 5 + src/librustdoc/html/static/js/search.js | 150 +++++++++++---------- 3 files changed, 83 insertions(+), 74 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index aff8684ee3a0..ef0a8361fd90 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -116,7 +116,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.as_str().to_lowercase()).or_default().push(i); + aliases.entry(alias.to_string()).or_default().push(i); } } diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index ca2512e5ab68..9ce24d1c06f6 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -227,6 +227,11 @@ declare namespace rustdoc { path: string, ty: number, type: FunctionSearchType | null, + descIndex: number, + bitIndex: number, + implDisambiguator: String | null, + is_alias?: boolean, + original?: Row, } /** diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 15cad31f555a..2caf214ff73d 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -830,7 +830,7 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) { */ function makePrimitiveElement(name, extra) { return Object.assign({ - name: name, + name, id: null, fullPath: [name], pathWithoutLast: [], @@ -1483,6 +1483,7 @@ class DocSearch { */ this.assocTypeIdNameMap = new Map(); this.ALIASES = new Map(); + this.FOUND_ALIASES = new Set(); this.rootPath = rootPath; this.searchState = searchState; @@ -2030,6 +2031,8 @@ class DocSearch { // normalized names, type signature objects and fingerprints, and aliases. id = 0; + /** @type {Array<[string, { [key: string]: Array }, number]>} */ + const allAliases = []; for (const [crate, crateCorpus] of rawSearchIndex) { // a string representing the lengths of each description shard // a string representing the list of function types @@ -2178,10 +2181,10 @@ class DocSearch { paths[i] = { ty, name, path, exactPath, unboxFlag }; } - // convert `item*` into an object form, and construct word indices. + // Convert `item*` into an object form, and construct word indices. // - // before any analysis is performed lets gather the search terms to - // search against apart from the rest of the data. This is a quick + // Before any analysis is performed, let's gather the search terms to + // search against apart from the rest of the data. This is a quick // operation that is cached for the life of the page state so that // all other search operations have access to this cached data for // faster analysis operations @@ -2269,29 +2272,58 @@ class DocSearch { } if (aliases) { - const currentCrateAliases = new Map(); - this.ALIASES.set(crate, currentCrateAliases); - for (const alias_name in aliases) { - if (!Object.prototype.hasOwnProperty.call(aliases, alias_name)) { - continue; - } - - /** @type{number[]} */ - let currentNameAliases; - if (currentCrateAliases.has(alias_name)) { - currentNameAliases = currentCrateAliases.get(alias_name); - } else { - currentNameAliases = []; - currentCrateAliases.set(alias_name, currentNameAliases); - } - for (const local_alias of aliases[alias_name]) { - currentNameAliases.push(local_alias + currentIndex); - } - } + // We need to add the aliases in `searchIndex` after we finished filling it + // to not mess up indexes. + allAliases.push([crate, aliases, currentIndex]); } currentIndex += itemTypes.length; this.searchState.descShards.set(crate, descShardList); } + + for (const [crate, aliases, index] of allAliases) { + for (const [alias_name, alias_refs] of Object.entries(aliases)) { + if (!this.ALIASES.has(crate)) { + this.ALIASES.set(crate, new Map()); + } + const word = alias_name.toLowerCase(); + const crate_alias_map = this.ALIASES.get(crate); + if (!crate_alias_map.has(word)) { + crate_alias_map.set(word, []); + } + const aliases_map = crate_alias_map.get(word); + + const normalizedName = word.indexOf("_") === -1 ? word : word.replace(/_/g, ""); + for (const alias of alias_refs) { + const originalIndex = alias + index; + const original = searchIndex[originalIndex]; + /** @type {rustdoc.Row} */ + const row = { + crate, + name: alias_name, + normalizedName, + is_alias: true, + ty: original.ty, + type: original.type, + paramNames: [], + word, + id, + parent: undefined, + original, + path: "", + implDisambiguator: original.implDisambiguator, + // Needed to load the description of the original item. + // @ts-ignore + descShard: original.descShard, + descIndex: original.descIndex, + bitIndex: original.bitIndex, + }; + aliases_map.push(row); + this.nameTrie.insert(normalizedName, id, this.tailTable); + id += 1; + searchIndex.push(row); + } + } + } // Drop the (rather large) hash table used for reusing function items this.TYPES_POOL = new Map(); return searchIndex; @@ -2536,6 +2568,8 @@ class DocSearch { parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) + parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0); const maxEditDistance = Math.floor(queryLen / 3); + // We reinitialize the `FOUND_ALIASES` map. + this.FOUND_ALIASES.clear(); /** * @type {Map} @@ -2695,6 +2729,10 @@ class DocSearch { const buildHrefAndPath = item => { let displayPath; let href; + if (item.is_alias) { + this.FOUND_ALIASES.add(item.word); + item = item.original; + } const type = itemTypes[item.ty]; const name = item.name; let path = item.path; @@ -3198,8 +3236,7 @@ class DocSearch { result.item = this.searchIndex[result.id]; result.word = this.searchIndex[result.id].word; if (isReturnTypeQuery) { - // we are doing a return-type based search, - // deprioritize "clone-like" results, + // We are doing a return-type based search, deprioritize "clone-like" results, // ie. functions that also take the queried type as an argument. const resultItemType = result.item && result.item.type; if (!resultItemType) { @@ -4259,28 +4296,13 @@ class DocSearch { return false; } - // this does not yet have a type in `rustdoc.d.ts`. - // @ts-expect-error - function createAliasFromItem(item) { - return { - crate: item.crate, - name: item.name, - path: item.path, - descShard: item.descShard, - descIndex: item.descIndex, - exactPath: item.exactPath, - ty: item.ty, - parent: item.parent, - type: item.type, - is_alias: true, - bitIndex: item.bitIndex, - implDisambiguator: item.implDisambiguator, - }; - } - // @ts-expect-error const handleAliases = async(ret, query, filterCrates, currentCrate) => { const lowerQuery = query.toLowerCase(); + if (this.FOUND_ALIASES.has(lowerQuery)) { + return; + } + this.FOUND_ALIASES.add(lowerQuery); // We separate aliases and crate aliases because we want to have current crate // aliases to be before the others in the displayed results. // @ts-expect-error @@ -4292,7 +4314,7 @@ class DocSearch { && this.ALIASES.get(filterCrates).has(lowerQuery)) { const query_aliases = this.ALIASES.get(filterCrates).get(lowerQuery); for (const alias of query_aliases) { - aliases.push(createAliasFromItem(this.searchIndex[alias])); + aliases.push(alias); } } } else { @@ -4302,7 +4324,7 @@ class DocSearch { const pushTo = crate === currentCrate ? crateAliases : aliases; const query_aliases = crateAliasesIndex.get(lowerQuery); for (const alias of query_aliases) { - pushTo.push(createAliasFromItem(this.searchIndex[alias])); + pushTo.push(alias); } } } @@ -4310,9 +4332,9 @@ class DocSearch { // @ts-expect-error const sortFunc = (aaa, bbb) => { - if (aaa.path < bbb.path) { + if (aaa.original.path < bbb.original.path) { return 1; - } else if (aaa.path === bbb.path) { + } else if (aaa.original.path === bbb.original.path) { return 0; } return -1; @@ -4321,21 +4343,10 @@ class DocSearch { crateAliases.sort(sortFunc); aliases.sort(sortFunc); - // @ts-expect-error - const fetchDesc = alias => { - // @ts-expect-error - return this.searchIndexEmptyDesc.get(alias.crate).contains(alias.bitIndex) ? - "" : this.searchState.loadDesc(alias); - }; - const [crateDescs, descs] = await Promise.all([ - // @ts-expect-error - Promise.all(crateAliases.map(fetchDesc)), - Promise.all(aliases.map(fetchDesc)), - ]); - // @ts-expect-error const pushFunc = alias => { - alias.alias = query; + // Cloning `alias` to prevent its fields to be updated. + alias = {...alias}; const res = buildHrefAndPath(alias); alias.displayPath = pathSplitter(res[0]); alias.fullPath = alias.displayPath + alias.name; @@ -4347,16 +4358,8 @@ class DocSearch { } }; - aliases.forEach((alias, i) => { - // @ts-expect-error - alias.desc = descs[i]; - }); aliases.forEach(pushFunc); // @ts-expect-error - crateAliases.forEach((alias, i) => { - alias.desc = crateDescs[i]; - }); - // @ts-expect-error crateAliases.forEach(pushFunc); }; @@ -4802,7 +4805,7 @@ async function addTab(array, query, display) { output.className = "search-results " + extraClass; const lis = Promise.all(array.map(async item => { - const name = item.name; + const name = item.is_alias ? item.original.name : item.name; const type = itemTypes[item.ty]; const longType = longItemTypes[item.ty]; const typeName = longType.length !== 0 ? `${longType}` : "?"; @@ -4822,7 +4825,7 @@ async function addTab(array, query, display) { let alias = " "; if (item.is_alias) { alias = `
\ -${item.alias} - see \ +${item.name} - see \
`; } resultName.insertAdjacentHTML( @@ -5201,6 +5204,7 @@ function registerSearchEvents() { if (searchState.input.value.length === 0) { searchState.hideResults(); } else { + // @ts-ignore searchState.timeout = setTimeout(search, 500); } }; @@ -5842,8 +5846,8 @@ Lev1TParametricDescription.prototype.offsetIncrs3 = /*2 bits per value */ new In // be called ONLY when the whole file has been parsed and loaded. // @ts-expect-error -function initSearch(searchIndx) { - rawSearchIndex = searchIndx; +function initSearch(searchIndex) { + rawSearchIndex = searchIndex; if (typeof window !== "undefined") { // @ts-expect-error docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState); From b0bf51f9a9323ca5abf595c6d0653d60fe68ee24 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Jul 2025 21:07:55 +0200 Subject: [PATCH 229/363] Update rustdoc search tester to new alias output --- src/tools/rustdoc-js/tester.js | 71 ++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index f70fc917770c..0baa179e16b2 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -28,7 +28,14 @@ function readFile(filePath) { } function contentToDiffLine(key, value) { - return `"${key}": "${value}",`; + if (typeof value === "object" && !Array.isArray(value) && value !== null) { + const out = Object.entries(value) + .filter(([subKey, _]) => ["path", "name"].includes(subKey)) + .map(([subKey, subValue]) => `"${subKey}": ${JSON.stringify(subValue)}`) + .join(", "); + return `"${key}": ${out},`; + } + return `"${key}": ${JSON.stringify(value)},`; } function shouldIgnoreField(fieldName) { @@ -37,47 +44,61 @@ function shouldIgnoreField(fieldName) { fieldName === "proposeCorrectionTo"; } +function valueMapper(key, testOutput) { + const isAlias = testOutput["is_alias"]; + let value = testOutput[key]; + // To make our life easier, if there is a "parent" type, we add it to the path. + if (key === "path") { + if (testOutput["parent"] !== undefined) { + if (value.length > 0) { + value += "::" + testOutput["parent"]["name"]; + } else { + value = testOutput["parent"]["name"]; + } + } else if (testOutput["is_alias"]) { + value = valueMapper(key, testOutput["original"]); + } + } else if (isAlias && key === "alias") { + value = testOutput["name"]; + } else if (isAlias && ["name"].includes(key)) { + value = testOutput["original"][key]; + } + return value; +} + // This function is only called when no matching result was found and therefore will only display // the diff between the two items. -function betterLookingDiff(entry, data) { +function betterLookingDiff(expected, testOutput) { let output = " {\n"; - const spaces = " "; - for (const key in entry) { - if (!Object.prototype.hasOwnProperty.call(entry, key)) { + const spaces = " "; + for (const key in expected) { + if (!Object.prototype.hasOwnProperty.call(expected, key)) { continue; } - if (!data || !Object.prototype.hasOwnProperty.call(data, key)) { - output += "-" + spaces + contentToDiffLine(key, entry[key]) + "\n"; + if (!testOutput || !Object.prototype.hasOwnProperty.call(testOutput, key)) { + output += "-" + spaces + contentToDiffLine(key, expected[key]) + "\n"; continue; } - const value = data[key]; - if (value !== entry[key]) { - output += "-" + spaces + contentToDiffLine(key, entry[key]) + "\n"; + const value = valueMapper(key, testOutput); + if (value !== expected[key]) { + output += "-" + spaces + contentToDiffLine(key, expected[key]) + "\n"; output += "+" + spaces + contentToDiffLine(key, value) + "\n"; } else { - output += spaces + contentToDiffLine(key, value) + "\n"; + output += spaces + " " + contentToDiffLine(key, value) + "\n"; } } return output + " }"; } -function lookForEntry(entry, data) { - return data.findIndex(data_entry => { +function lookForEntry(expected, testOutput) { + return testOutput.findIndex(testOutputEntry => { let allGood = true; - for (const key in entry) { - if (!Object.prototype.hasOwnProperty.call(entry, key)) { + for (const key in expected) { + if (!Object.prototype.hasOwnProperty.call(expected, key)) { continue; } - let value = data_entry[key]; - // To make our life easier, if there is a "parent" type, we add it to the path. - if (key === "path" && data_entry["parent"] !== undefined) { - if (value.length > 0) { - value += "::" + data_entry["parent"]["name"]; - } else { - value = data_entry["parent"]["name"]; - } - } - if (value !== entry[key]) { + const value = valueMapper(key, testOutputEntry); + if (value !== expected[key]) { allGood = false; break; } From c079c96877fdd3977c8d5be830931ecb4f79018d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Jul 2025 21:08:18 +0200 Subject: [PATCH 230/363] Add test for aliases partial match --- tests/rustdoc-js-std/alias-lev.js | 11 +++++++++++ tests/rustdoc-js/non-english-identifier.js | 17 +++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 tests/rustdoc-js-std/alias-lev.js diff --git a/tests/rustdoc-js-std/alias-lev.js b/tests/rustdoc-js-std/alias-lev.js new file mode 100644 index 000000000000..17f3dc25d763 --- /dev/null +++ b/tests/rustdoc-js-std/alias-lev.js @@ -0,0 +1,11 @@ +// This test ensures that aliases are also allowed to be partially matched. + +// ignore-order + +const EXPECTED = { + // The full alias name is `getcwd`. + 'query': 'getcw', + 'others': [ + { 'path': 'std::env', 'name': 'current_dir', 'alias': 'getcwd' }, + ], +}; diff --git a/tests/rustdoc-js/non-english-identifier.js b/tests/rustdoc-js/non-english-identifier.js index f2180b4c7553..3d50bd3ee905 100644 --- a/tests/rustdoc-js/non-english-identifier.js +++ b/tests/rustdoc-js/non-english-identifier.js @@ -115,11 +115,10 @@ const EXPECTED = [ query: '加法', others: [ { - name: "add", + name: "加法", path: "non_english_identifier", - is_alias: true, - alias: "加法", - href: "../non_english_identifier/macro.add.html" + href: "../non_english_identifier/trait.加法.html", + desc: "Add" }, { name: "add", @@ -129,11 +128,13 @@ const EXPECTED = [ href: "../non_english_identifier/fn.add.html" }, { - name: "加法", + name: "add", path: "non_english_identifier", - href: "../non_english_identifier/trait.加法.html", - desc: "Add" - }], + is_alias: true, + alias: "加法", + href: "../non_english_identifier/macro.add.html" + }, + ], in_args: [{ name: "加上", path: "non_english_identifier::加法", From 8d64937dc25eb2b01596a3581ec2660d8e81b9b2 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 16 Jul 2025 10:56:32 +0000 Subject: [PATCH 231/363] trait_sel: `MetaSized` always holds temporarily As a temporary measure while a proper fix for `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs` is implemented, make `MetaSized` obligations always hold. In effect, temporarily reverting the `sized_hierarchy` feature. This is a small change that can be backported. --- .../rustc_trait_selection/src/traits/util.rs | 7 +++ ...st-size_of_val-align_of_val-extern-type.rs | 4 +- ...ize_of_val-align_of_val-extern-type.stderr | 38 +++----------- tests/ui/extern/extern-types-size_of_val.rs | 4 +- .../ui/extern/extern-types-size_of_val.stderr | 39 -------------- tests/ui/extern/extern-types-unsized.rs | 2 - tests/ui/extern/extern-types-unsized.stderr | 30 +---------- tests/ui/extern/unsized-extern-derefmove.rs | 4 -- .../ui/extern/unsized-extern-derefmove.stderr | 52 +------------------ .../layout/unconstrained-param-ice-137308.rs | 1 - .../unconstrained-param-ice-137308.stderr | 11 +--- tests/ui/nll/issue-50716.rs | 2 +- tests/ui/nll/issue-50716.stderr | 18 +------ ...omplete-inference-issue-143992.next.stderr | 17 ++++++ .../incomplete-inference-issue-143992.rs | 29 +++++++++++ .../sized-hierarchy/overflow.current.stderr | 45 ---------------- tests/ui/sized-hierarchy/overflow.rs | 6 ++- .../resolve-impl-before-constrain-check.rs | 1 - ...resolve-impl-before-constrain-check.stderr | 11 +--- 19 files changed, 77 insertions(+), 244 deletions(-) delete mode 100644 tests/ui/extern/extern-types-size_of_val.stderr create mode 100644 tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next.stderr create mode 100644 tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs delete mode 100644 tests/ui/sized-hierarchy/overflow.current.stderr diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 141454bfe375..00e31021eec0 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -378,6 +378,13 @@ pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc _ => return false, }; + // FIXME(sized_hierarchy): this temporarily reverts the `sized_hierarchy` feature + // while a proper fix for `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs` + // is pending a proper fix + if !tcx.features().sized_hierarchy() && matches!(sizedness, SizedTraitKind::MetaSized) { + return true; + } + if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) { debug!("fast path -- trivial sizedness"); return true; diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs index 2372d1c3e3d7..fd3ed8f18265 100644 --- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs @@ -8,8 +8,8 @@ extern "C" { } const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; -//~^ ERROR the size for values of type `Opaque` cannot be known +//~^ ERROR `extern type` does not have known layout const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) }; -//~^ ERROR the size for values of type `Opaque` cannot be known +//~^ ERROR `extern type` does not have known layout fn main() {} diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr index 825b9e941584..23f7aaf538ed 100644 --- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr @@ -1,39 +1,15 @@ -error[E0277]: the size for values of type `Opaque` cannot be known - --> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:43 +error[E0080]: `extern type` does not have known layout + --> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:31 | LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; - | ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Opaque` - | | - | required by a bound introduced by this call - | - = note: the trait bound `Opaque: MetaSized` is not satisfied -note: required by a bound in `std::intrinsics::size_of_val` - --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL -help: consider borrowing here - | -LL | const _SIZE: usize = unsafe { size_of_val(&(&4 as *const i32 as *const Opaque)) }; - | ++ + -LL | const _SIZE: usize = unsafe { size_of_val(&mut (&4 as *const i32 as *const Opaque)) }; - | ++++++ + + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_SIZE` failed here -error[E0277]: the size for values of type `Opaque` cannot be known - --> $DIR/const-size_of_val-align_of_val-extern-type.rs:12:45 +error[E0080]: `extern type` does not have known layout + --> $DIR/const-size_of_val-align_of_val-extern-type.rs:12:32 | LL | const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) }; - | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Opaque` - | | - | required by a bound introduced by this call - | - = note: the trait bound `Opaque: MetaSized` is not satisfied -note: required by a bound in `std::intrinsics::align_of_val` - --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL -help: consider borrowing here - | -LL | const _ALIGN: usize = unsafe { align_of_val(&(&4 as *const i32 as *const Opaque)) }; - | ++ + -LL | const _ALIGN: usize = unsafe { align_of_val(&mut (&4 as *const i32 as *const Opaque)) }; - | ++++++ + + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/extern/extern-types-size_of_val.rs b/tests/ui/extern/extern-types-size_of_val.rs index 3ff51b9b6b0d..875ae9a535a7 100644 --- a/tests/ui/extern/extern-types-size_of_val.rs +++ b/tests/ui/extern/extern-types-size_of_val.rs @@ -1,4 +1,4 @@ -//@ check-fail +//@ check-pass #![feature(extern_types)] use std::mem::{align_of_val, size_of_val}; @@ -11,7 +11,5 @@ fn main() { let x: &A = unsafe { &*(1usize as *const A) }; size_of_val(x); - //~^ ERROR the size for values of type `A` cannot be known align_of_val(x); - //~^ ERROR the size for values of type `A` cannot be known } diff --git a/tests/ui/extern/extern-types-size_of_val.stderr b/tests/ui/extern/extern-types-size_of_val.stderr deleted file mode 100644 index 8678c6c3d603..000000000000 --- a/tests/ui/extern/extern-types-size_of_val.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0277]: the size for values of type `A` cannot be known - --> $DIR/extern-types-size_of_val.rs:13:17 - | -LL | size_of_val(x); - | ----------- ^ the trait `MetaSized` is not implemented for `A` - | | - | required by a bound introduced by this call - | - = note: the trait bound `A: MetaSized` is not satisfied -note: required by a bound in `std::mem::size_of_val` - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -help: consider borrowing here - | -LL | size_of_val(&x); - | + -LL | size_of_val(&mut x); - | ++++ - -error[E0277]: the size for values of type `A` cannot be known - --> $DIR/extern-types-size_of_val.rs:15:18 - | -LL | align_of_val(x); - | ------------ ^ the trait `MetaSized` is not implemented for `A` - | | - | required by a bound introduced by this call - | - = note: the trait bound `A: MetaSized` is not satisfied -note: required by a bound in `std::mem::align_of_val` - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -help: consider borrowing here - | -LL | align_of_val(&x); - | + -LL | align_of_val(&mut x); - | ++++ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/extern/extern-types-unsized.rs b/tests/ui/extern/extern-types-unsized.rs index 46cdc24e0832..94a222a7e7e0 100644 --- a/tests/ui/extern/extern-types-unsized.rs +++ b/tests/ui/extern/extern-types-unsized.rs @@ -27,9 +27,7 @@ fn main() { assert_sized::>(); //~^ ERROR the size for values of type - //~| ERROR the size for values of type assert_sized::>>(); //~^ ERROR the size for values of type - //~| ERROR the size for values of type } diff --git a/tests/ui/extern/extern-types-unsized.stderr b/tests/ui/extern/extern-types-unsized.stderr index 43dd9800d6d3..a587d4dda55c 100644 --- a/tests/ui/extern/extern-types-unsized.stderr +++ b/tests/ui/extern/extern-types-unsized.stderr @@ -59,21 +59,8 @@ help: consider relaxing the implicit `Sized` restriction LL | fn assert_sized() {} | ++++++++ -error[E0277]: the size for values of type `A` cannot be known - --> $DIR/extern-types-unsized.rs:28:20 - | -LL | assert_sized::>(); - | ^^^^^^ doesn't have a known size - | - = help: the trait `MetaSized` is not implemented for `A` -note: required by a bound in `Bar` - --> $DIR/extern-types-unsized.rs:14:12 - | -LL | struct Bar { - | ^ required by this bound in `Bar` - error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/extern-types-unsized.rs:32:20 + --> $DIR/extern-types-unsized.rs:31:20 | LL | assert_sized::>>(); | ^^^^^^^^^^^ doesn't have a size known at compile-time @@ -94,19 +81,6 @@ help: consider relaxing the implicit `Sized` restriction LL | fn assert_sized() {} | ++++++++ -error[E0277]: the size for values of type `A` cannot be known - --> $DIR/extern-types-unsized.rs:32:20 - | -LL | assert_sized::>>(); - | ^^^^^^^^^^^ doesn't have a known size - | - = help: the trait `MetaSized` is not implemented for `A` -note: required by a bound in `Bar` - --> $DIR/extern-types-unsized.rs:14:12 - | -LL | struct Bar { - | ^ required by this bound in `Bar` - -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/extern/unsized-extern-derefmove.rs b/tests/ui/extern/unsized-extern-derefmove.rs index c02375266ab4..39597a12fe11 100644 --- a/tests/ui/extern/unsized-extern-derefmove.rs +++ b/tests/ui/extern/unsized-extern-derefmove.rs @@ -7,14 +7,10 @@ extern "C" { } unsafe fn make_device() -> Box { -//~^ ERROR the size for values of type `Device` cannot be known Box::from_raw(0 as *mut _) -//~^ ERROR the size for values of type `Device` cannot be known -//~| ERROR the size for values of type `Device` cannot be known } fn main() { let d: Device = unsafe { *make_device() }; //~^ ERROR the size for values of type `Device` cannot be known -//~| ERROR the size for values of type `Device` cannot be known } diff --git a/tests/ui/extern/unsized-extern-derefmove.stderr b/tests/ui/extern/unsized-extern-derefmove.stderr index a9efc2e66e3b..c43184d94e17 100644 --- a/tests/ui/extern/unsized-extern-derefmove.stderr +++ b/tests/ui/extern/unsized-extern-derefmove.stderr @@ -1,43 +1,5 @@ -error[E0277]: the size for values of type `Device` cannot be known - --> $DIR/unsized-extern-derefmove.rs:9:28 - | -LL | unsafe fn make_device() -> Box { - | ^^^^^^^^^^^ doesn't have a known size - | - = help: the trait `MetaSized` is not implemented for `Device` -note: required by a bound in `Box` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - -error[E0277]: the size for values of type `Device` cannot be known - --> $DIR/unsized-extern-derefmove.rs:11:19 - | -LL | Box::from_raw(0 as *mut _) - | ------------- ^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Device` - | | - | required by a bound introduced by this call - | - = note: the trait bound `Device: MetaSized` is not satisfied -note: required by a bound in `Box::::from_raw` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -help: consider borrowing here - | -LL | Box::from_raw(&(0 as *mut _)) - | ++ + -LL | Box::from_raw(&mut (0 as *mut _)) - | ++++++ + - -error[E0277]: the size for values of type `Device` cannot be known - --> $DIR/unsized-extern-derefmove.rs:11:5 - | -LL | Box::from_raw(0 as *mut _) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size - | - = help: the trait `MetaSized` is not implemented for `Device` -note: required by a bound in `Box` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - error[E0277]: the size for values of type `Device` cannot be known at compilation time - --> $DIR/unsized-extern-derefmove.rs:17:9 + --> $DIR/unsized-extern-derefmove.rs:14:9 | LL | let d: Device = unsafe { *make_device() }; | ^ doesn't have a size known at compile-time @@ -49,16 +11,6 @@ help: consider borrowing here LL | let d: &Device = unsafe { *make_device() }; | + -error[E0277]: the size for values of type `Device` cannot be known - --> $DIR/unsized-extern-derefmove.rs:17:31 - | -LL | let d: Device = unsafe { *make_device() }; - | ^^^^^^^^^^^^^ doesn't have a known size - | - = help: the trait `MetaSized` is not implemented for `Device` -note: required by a bound in `Box` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - -error: aborting due to 5 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/layout/unconstrained-param-ice-137308.rs b/tests/ui/layout/unconstrained-param-ice-137308.rs index 03b7e7599601..d05e6e1fd3f3 100644 --- a/tests/ui/layout/unconstrained-param-ice-137308.rs +++ b/tests/ui/layout/unconstrained-param-ice-137308.rs @@ -17,4 +17,3 @@ impl A for u8 { //~ ERROR: the type parameter `C` is not constrained #[rustc_layout(debug)] struct S([u8; ::B]); //~^ ERROR: the type has an unknown layout -//~| ERROR: type annotations needed diff --git a/tests/ui/layout/unconstrained-param-ice-137308.stderr b/tests/ui/layout/unconstrained-param-ice-137308.stderr index 82cd1217c490..615c131eb904 100644 --- a/tests/ui/layout/unconstrained-param-ice-137308.stderr +++ b/tests/ui/layout/unconstrained-param-ice-137308.stderr @@ -4,19 +4,12 @@ error[E0207]: the type parameter `C` is not constrained by the impl trait, self LL | impl A for u8 { | ^ unconstrained type parameter -error[E0282]: type annotations needed - --> $DIR/unconstrained-param-ice-137308.rs:18:16 - | -LL | struct S([u8; ::B]); - | ^^ cannot infer type for type parameter `C` - error: the type has an unknown layout --> $DIR/unconstrained-param-ice-137308.rs:18:1 | LL | struct S([u8; ::B]); | ^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0207, E0282. -For more information about an error, try `rustc --explain E0207`. +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/nll/issue-50716.rs b/tests/ui/nll/issue-50716.rs index 76c6fc5e7b92..96168ebeaa16 100644 --- a/tests/ui/nll/issue-50716.rs +++ b/tests/ui/nll/issue-50716.rs @@ -5,7 +5,7 @@ trait A { type X: ?Sized; } -fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) //~ ERROR +fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) where for<'b> &'b T: A, <&'static T as A>::X: Sized diff --git a/tests/ui/nll/issue-50716.stderr b/tests/ui/nll/issue-50716.stderr index edd7fd765dad..536f88085ded 100644 --- a/tests/ui/nll/issue-50716.stderr +++ b/tests/ui/nll/issue-50716.stderr @@ -1,18 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/issue-50716.rs:8:27 - | -LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) - | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch - | - = note: expected trait `<<&'a T as A>::X as MetaSized>` - found trait `<<&'static T as A>::X as MetaSized>` -note: the lifetime `'a` as defined here... - --> $DIR/issue-50716.rs:8:8 - | -LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) - | ^^ - = note: ...does not necessarily outlive the static lifetime - error: lifetime may not live long enough --> $DIR/issue-50716.rs:13:14 | @@ -22,6 +7,5 @@ LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) LL | let _x = *s; | ^^ proving this value is `Sized` requires that `'a` must outlive `'static` -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next.stderr b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next.stderr new file mode 100644 index 000000000000..cf56f42afc8a --- /dev/null +++ b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/incomplete-inference-issue-143992.rs:27:28 + | +LL | let _x = T::Assoc::new(()); + | ------------- ^^ expected `[u32; 1]`, found `()` + | | + | arguments to this function are incorrect + | +note: associated function defined here + --> $DIR/incomplete-inference-issue-143992.rs:18:8 + | +LL | fn new(r: R) -> R { + | ^^^ ---- + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs new file mode 100644 index 000000000000..3e3e1dc50e58 --- /dev/null +++ b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs @@ -0,0 +1,29 @@ +//@ compile-flags: --crate-type=lib +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[current] check-pass +//@[next] compile-flags: -Znext-solver +//@[next] check-fail + +// Test that we avoid incomplete inference when normalizing. Without this, +// `Trait`'s implicit `MetaSized` supertrait requires proving `T::Assoc<_>: MetaSized` +// before checking the `new` arguments, resulting in eagerly constraining the inference +// var to `u32`. This is undesirable and would breaking code. + +pub trait Trait { + type Assoc: OtherTrait; +} + +pub trait OtherTrait { + fn new(r: R) -> R { + r + } +} + +pub fn function() +where + T::Assoc<[u32; 1]>: Clone, +{ + let _x = T::Assoc::new(()); +//[next]~^ ERROR mismatched types +} diff --git a/tests/ui/sized-hierarchy/overflow.current.stderr b/tests/ui/sized-hierarchy/overflow.current.stderr deleted file mode 100644 index e90548aa78c6..000000000000 --- a/tests/ui/sized-hierarchy/overflow.current.stderr +++ /dev/null @@ -1,45 +0,0 @@ -error[E0275]: overflow evaluating the requirement `Element: MetaSized` - --> $DIR/overflow.rs:16:16 - | -LL | struct Element(> as ParseTokens>::Output); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: required for `Box` to implement `ParseTokens` - --> $DIR/overflow.rs:12:31 - | -LL | impl ParseTokens for Box { - | - ^^^^^^^^^^^ ^^^^^^ - | | - | unsatisfied trait bound introduced here - = note: 1 redundant requirement hidden - = note: required for `Box>` to implement `ParseTokens` - -error[E0275]: overflow evaluating the requirement `Box: ParseTokens` - --> $DIR/overflow.rs:18:22 - | -LL | impl ParseTokens for Element { - | ^^^^^^^ - | -note: required for `Box>` to implement `ParseTokens` - --> $DIR/overflow.rs:12:31 - | -LL | impl ParseTokens for Box { - | ----------- ^^^^^^^^^^^ ^^^^^^ - | | - | unsatisfied trait bound introduced here -note: required because it appears within the type `Element` - --> $DIR/overflow.rs:16:8 - | -LL | struct Element(> as ParseTokens>::Output); - | ^^^^^^^ -note: required by a bound in `ParseTokens` - --> $DIR/overflow.rs:9:1 - | -LL | / trait ParseTokens { -LL | | type Output; -LL | | } - | |_^ required by this bound in `ParseTokens` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/sized-hierarchy/overflow.rs b/tests/ui/sized-hierarchy/overflow.rs index e1af4885e539..f8e5dd5d4029 100644 --- a/tests/ui/sized-hierarchy/overflow.rs +++ b/tests/ui/sized-hierarchy/overflow.rs @@ -1,9 +1,13 @@ //@ compile-flags: --crate-type=lib //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) +//@[current] check-pass //@[next] check-pass //@[next] compile-flags: -Znext-solver +// FIXME(sized_hierarchy): this is expected to fail in the old solver when there +// isn't a temporary revert of the `sized_hierarchy` feature + use std::marker::PhantomData; trait ParseTokens { @@ -14,8 +18,6 @@ impl ParseTokens for Box { } struct Element(> as ParseTokens>::Output); -//[current]~^ ERROR overflow evaluating impl ParseTokens for Element { -//[current]~^ ERROR overflow evaluating type Output = (); } diff --git a/tests/ui/traits/resolve-impl-before-constrain-check.rs b/tests/ui/traits/resolve-impl-before-constrain-check.rs index 50d1a8745513..87f9c241e402 100644 --- a/tests/ui/traits/resolve-impl-before-constrain-check.rs +++ b/tests/ui/traits/resolve-impl-before-constrain-check.rs @@ -15,7 +15,6 @@ use foo::*; fn test() -> impl Sized { <() as Callable>::call() -//~^ ERROR: type annotations needed } fn main() {} diff --git a/tests/ui/traits/resolve-impl-before-constrain-check.stderr b/tests/ui/traits/resolve-impl-before-constrain-check.stderr index 13fbfdb855cb..e8e569ba625e 100644 --- a/tests/ui/traits/resolve-impl-before-constrain-check.stderr +++ b/tests/ui/traits/resolve-impl-before-constrain-check.stderr @@ -4,13 +4,6 @@ error[E0207]: the type parameter `V` is not constrained by the impl trait, self LL | impl Callable for () { | ^ unconstrained type parameter -error[E0282]: type annotations needed - --> $DIR/resolve-impl-before-constrain-check.rs:17:6 - | -LL | <() as Callable>::call() - | ^^ cannot infer type for type parameter `V` +error: aborting due to 1 previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0207, E0282. -For more information about an error, try `rustc --explain E0207`. +For more information about this error, try `rustc --explain E0207`. From 83fbcabd92dd62198a1275d0d5cf7925150d1d6a Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 16 Jul 2025 08:44:15 -0400 Subject: [PATCH 232/363] Fix warnings in tests --- tests/run/asm.rs | 1 + tests/run/float.rs | 16 +++++++--------- tests/run/int.rs | 2 -- tests/run/volatile.rs | 3 ++- tests/run/volatile2.rs | 6 ++---- 5 files changed, 12 insertions(+), 16 deletions(-) diff --git a/tests/run/asm.rs b/tests/run/asm.rs index 2dbf43be664d..9b15a28d8298 100644 --- a/tests/run/asm.rs +++ b/tests/run/asm.rs @@ -16,6 +16,7 @@ add_asm: ret" ); +#[cfg(target_arch = "x86_64")] extern "C" { fn add_asm(a: i64, b: i64) -> i64; } diff --git a/tests/run/float.rs b/tests/run/float.rs index 424fa1cf4ad5..df555f383fe0 100644 --- a/tests/run/float.rs +++ b/tests/run/float.rs @@ -3,8 +3,6 @@ // Run-time: // status: 0 -#![feature(const_black_box)] - fn main() { use std::hint::black_box; @@ -15,14 +13,14 @@ fn main() { }}; } - check!(i32, (black_box(0.0f32) as i32)); + check!(i32, black_box(0.0f32) as i32); - check!(u64, (black_box(f32::NAN) as u64)); - check!(u128, (black_box(f32::NAN) as u128)); + check!(u64, black_box(f32::NAN) as u64); + check!(u128, black_box(f32::NAN) as u128); - check!(i64, (black_box(f64::NAN) as i64)); - check!(u64, (black_box(f64::NAN) as u64)); + check!(i64, black_box(f64::NAN) as i64); + check!(u64, black_box(f64::NAN) as u64); - check!(i16, (black_box(f32::MIN) as i16)); - check!(i16, (black_box(f32::MAX) as i16)); + check!(i16, black_box(f32::MIN) as i16); + check!(i16, black_box(f32::MAX) as i16); } diff --git a/tests/run/int.rs b/tests/run/int.rs index 47b5dea46f8d..e20ecc23679d 100644 --- a/tests/run/int.rs +++ b/tests/run/int.rs @@ -3,8 +3,6 @@ // Run-time: // status: 0 -#![feature(const_black_box)] - fn main() { use std::hint::black_box; diff --git a/tests/run/volatile.rs b/tests/run/volatile.rs index 8b0433125936..94a7bdc5c066 100644 --- a/tests/run/volatile.rs +++ b/tests/run/volatile.rs @@ -5,13 +5,14 @@ use std::mem::MaybeUninit; +#[allow(dead_code)] #[derive(Debug)] struct Struct { pointer: *const (), func: unsafe fn(*const ()), } -fn func(ptr: *const ()) { +fn func(_ptr: *const ()) { } fn main() { diff --git a/tests/run/volatile2.rs b/tests/run/volatile2.rs index a177b817ab35..bdcb82598789 100644 --- a/tests/run/volatile2.rs +++ b/tests/run/volatile2.rs @@ -6,8 +6,6 @@ mod libc { #[link(name = "c")] extern "C" { - pub fn puts(s: *const u8) -> i32; - pub fn sigaction(signum: i32, act: *const sigaction, oldact: *mut sigaction) -> i32; pub fn mmap(addr: *mut (), len: usize, prot: i32, flags: i32, fd: i32, offset: i64) -> *mut (); pub fn mprotect(addr: *mut (), len: usize, prot: i32) -> i32; @@ -61,7 +59,7 @@ fn main() { panic!("error: mmap failed"); } - let p_count = (&mut COUNT) as *mut u32; + let p_count = (&raw mut COUNT) as *mut u32; p_count.write_volatile(0); // Trigger segfaults @@ -94,7 +92,7 @@ fn main() { } unsafe extern "C" fn segv_handler(_: i32, _: *mut (), _: *mut ()) { - let p_count = (&mut COUNT) as *mut u32; + let p_count = (&raw mut COUNT) as *mut u32; p_count.write_volatile(p_count.read_volatile() + 1); let count = p_count.read_volatile(); From 8f854d9cb2d108a2d4f980ccb4d5909e214e6ef0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Jul 2025 15:11:11 +0200 Subject: [PATCH 233/363] const heap: fix ICE on forgotten make_global --- .../src/const_eval/eval_queries.rs | 11 ++- .../rustc_const_eval/src/interpret/intern.rs | 74 +++++++++---------- .../rustc_const_eval/src/interpret/mod.rs | 2 +- .../src/interpret/validity.rs | 10 ++- tests/crashes/const_mut_ref_check_bypass.rs | 11 --- .../heap/ptr_not_made_global_mut.rs | 9 +-- .../heap/ptr_not_made_global_mut.stderr | 8 +- 7 files changed, 58 insertions(+), 67 deletions(-) delete mode 100644 tests/crashes/const_mut_ref_check_bypass.rs diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 32209ff43679..ce72d59b8b0e 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -18,7 +18,7 @@ use tracing::{debug, instrument, trace}; use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine}; use crate::const_eval::CheckAlignment; use crate::interpret::{ - CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpErrorKind, + CtfeValidationMode, GlobalId, Immediate, InternError, InternKind, InterpCx, InterpErrorKind, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, ReturnContinuation, create_static_alloc, intern_const_alloc_recursive, interp_ok, throw_exhaust, }; @@ -98,20 +98,25 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( match intern_result { Ok(()) => {} - Err(InternResult::FoundDanglingPointer) => { + Err(InternError::DanglingPointer) => { throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error( ecx.tcx .dcx() .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }), ))); } - Err(InternResult::FoundBadMutablePointer) => { + Err(InternError::BadMutablePointer) => { throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error( ecx.tcx .dcx() .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }), ))); } + Err(InternError::ConstAllocNotGlobal) => { + throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error( + ecx.tcx.dcx().emit_err(errors::ConstHeapPtrInFinal { span: ecx.tcx.span }), + ))); + } } interp_ok(R::make_result(ret, ecx)) diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index b8fcdc9b7ef0..f25bb222bcfc 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -26,12 +26,9 @@ use rustc_middle::ty::layout::TyAndLayout; use rustc_span::def_id::LocalDefId; use tracing::{instrument, trace}; -use super::{ - AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub, interp_ok, -}; -use crate::const_eval; +use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, interp_ok}; use crate::const_eval::DummyMachine; -use crate::errors::{ConstHeapPtrInFinal, NestedStaticInThreadLocal}; +use crate::{const_eval, errors}; pub trait CompileTimeMachine<'tcx, T> = Machine< 'tcx, @@ -63,7 +60,7 @@ pub enum DisallowInternReason { /// /// This prevents us from interning `const_allocate` pointers that have not been made /// global through `const_make_global`. -pub trait CanIntern { +pub trait CanIntern: Copy { fn disallows_intern(&self) -> Option; } @@ -96,24 +93,22 @@ fn intern_shallow<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>( alloc_id: AllocId, mutability: Mutability, disambiguator: Option<&mut DisambiguatorState>, -) -> Result + 'tcx, ()> { +) -> Result + 'tcx, InternError> { trace!("intern_shallow {:?}", alloc_id); // remove allocation // FIXME(#120456) - is `swap_remove` correct? let Some((kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else { - return Err(()); + return Err(InternError::DanglingPointer); }; match kind { MemoryKind::Machine(x) if let Some(reason) = x.disallows_intern() => match reason { - // Attempting to intern a `const_allocate`d pointer that was not made global via - // `const_make_global`. This is an error, but if we return `Err` now, things - // become inconsistent because we already removed the allocation from `alloc_map`. - // So instead we just emit an error and then continue interning as usual. - // We *could* do this check before removing the allocation from `alloc_map`, but then - // it would be much harder to ensure that we only error once for each allocation. DisallowInternReason::ConstHeap => { - ecx.tcx.dcx().emit_err(ConstHeapPtrInFinal { span: ecx.tcx.span }); + // Attempting to intern a `const_allocate`d pointer that was not made global via + // `const_make_global`. We want to error here, but we have to first put the + // allocation back into the `alloc_map` to keep things in a consistent state. + ecx.memory.alloc_map.insert(alloc_id, (kind, alloc)); + return Err(InternError::ConstAllocNotGlobal); } }, MemoryKind::Machine(_) | MemoryKind::Stack | MemoryKind::CallerLocation => {} @@ -170,7 +165,7 @@ fn intern_as_new_static<'tcx>( tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); if tcx.is_thread_local_static(static_id.into()) { - tcx.dcx().emit_err(NestedStaticInThreadLocal { span: tcx.def_span(static_id) }); + tcx.dcx().emit_err(errors::NestedStaticInThreadLocal { span: tcx.def_span(static_id) }); } // These do not inherit the codegen attrs of the parent static allocation, since @@ -196,9 +191,10 @@ pub enum InternKind { } #[derive(Debug)] -pub enum InternResult { - FoundBadMutablePointer, - FoundDanglingPointer, +pub enum InternError { + BadMutablePointer, + DanglingPointer, + ConstAllocNotGlobal, } /// Intern `ret` and everything it references. @@ -212,7 +208,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval ecx: &mut InterpCx<'tcx, M>, intern_kind: InternKind, ret: &MPlaceTy<'tcx>, -) -> Result<(), InternResult> { +) -> Result<(), InternError> { let mut disambiguator = DisambiguatorState::new(); // We are interning recursively, and for mutability we are distinguishing the "root" allocation @@ -269,6 +265,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval // We want to first report "dangling" and then "mutable", so we need to delay reporting these // errors. let mut result = Ok(()); + let mut found_bad_mutable_ptr = false; // Keep interning as long as there are things to intern. // We show errors if there are dangling pointers, or mutable pointers in immutable contexts @@ -323,18 +320,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval // when there is memory there that someone might expect to be mutable, but we make it immutable. let dangling = !is_already_global && !ecx.memory.alloc_map.contains_key(&alloc_id); if !dangling { - // Found a mutable pointer inside a const where inner allocations should be - // immutable. - if !ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { - span_bug!( - ecx.tcx.span, - "the static const safety checks accepted a mutable pointer they should not have accepted" - ); - } - // Prefer dangling pointer errors over mutable pointer errors - if result.is_ok() { - result = Err(InternResult::FoundBadMutablePointer); - } + found_bad_mutable_ptr = true; } } if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { @@ -355,12 +341,25 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval just_interned.insert(alloc_id); match intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguator)) { Ok(nested) => todo.extend(nested), - Err(()) => { - ecx.tcx.dcx().delayed_bug("found dangling pointer during const interning"); - result = Err(InternResult::FoundDanglingPointer); + Err(err) => { + ecx.tcx.dcx().delayed_bug("error during const interning"); + result = Err(err); } } } + if found_bad_mutable_ptr && result.is_ok() { + // We found a mutable pointer inside a const where inner allocations should be immutable, + // and there was no other error. This should usually never happen! However, this can happen + // in unleash-miri mode, so report it as a normal error then. + if ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { + result = Err(InternError::BadMutablePointer); + } else { + span_bug!( + ecx.tcx.span, + "the static const safety checks accepted a mutable pointer they should not have accepted" + ); + } + } result } @@ -375,10 +374,7 @@ pub fn intern_const_alloc_for_constprop<'tcx, T: CanIntern, M: CompileTimeMachin return interp_ok(()); } // Move allocation to `tcx`. - if let Some(_) = intern_shallow(ecx, alloc_id, Mutability::Not, None) - .map_err(|()| err_ub!(DeadLocal))? - .next() - { + if let Some(_) = intern_shallow(ecx, alloc_id, Mutability::Not, None).unwrap().next() { // We are not doing recursive interning, so we don't currently support provenance. // (If this assertion ever triggers, we should just implement a // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 2fc372dd0197..2f365ec77b33 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -26,7 +26,7 @@ pub use self::call::FnArg; pub use self::eval_context::{InterpCx, format_interp_error}; use self::eval_context::{from_known_layout, mir_assign_valid_types}; pub use self::intern::{ - HasStaticRootDefId, InternKind, InternResult, intern_const_alloc_for_constprop, + HasStaticRootDefId, InternError, InternKind, intern_const_alloc_for_constprop, intern_const_alloc_recursive, }; pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine}; diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index fc44490c96d3..62f591ceaa91 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -558,7 +558,15 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { { // Everything should be already interned. let Some(global_alloc) = self.ecx.tcx.try_get_global_alloc(alloc_id) else { - assert!(self.ecx.memory.alloc_map.get(alloc_id).is_none()); + if self.ecx.memory.alloc_map.contains_key(&alloc_id) { + // This can happen when interning didn't complete due to, e.g. + // missing `make_global`. This must mean other errors are already + // being reported. + self.ecx.tcx.dcx().delayed_bug( + "interning did not complete, there should be an error", + ); + return interp_ok(()); + } // We can't have *any* references to non-existing allocations in const-eval // as the rest of rustc isn't happy with them... so we throw an error, even // though for zero-sized references this isn't really UB. diff --git a/tests/crashes/const_mut_ref_check_bypass.rs b/tests/crashes/const_mut_ref_check_bypass.rs deleted file mode 100644 index 6234536c72be..000000000000 --- a/tests/crashes/const_mut_ref_check_bypass.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Version of `tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs` without the flag that -// suppresses the ICE. -//@ known-bug: #129233 -#![feature(core_intrinsics)] -#![feature(const_heap)] -#![feature(const_mut_refs)] -use std::intrinsics; - -const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; - -fn main() {} diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.rs b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.rs index 201fa7150229..e44a3f7a23c2 100644 --- a/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.rs +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.rs @@ -1,12 +1,11 @@ -// We unleash Miri here since this test demonstrates code that bypasses the checks against interning -// mutable pointers, which currently ICEs. Unleashing Miri silences the ICE. -//@ compile-flags: -Zunleash-the-miri-inside-of-you +// Ensure that we reject interning `const_allocate`d allocations in the final value of constants +// if they have not been made global through `const_make_global`. This covers the case where the +// pointer is even still mutable, which used to ICE. #![feature(core_intrinsics)] #![feature(const_heap)] use std::intrinsics; const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; -//~^ error: mutable pointer in final value of constant -//~| error: encountered `const_allocate` pointer in final value that was not made global +//~^ error: encountered `const_allocate` pointer in final value that was not made global fn main() {} diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr index eae79d24797a..2445ce633d6f 100644 --- a/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr @@ -6,11 +6,5 @@ LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 | = note: use `const_make_global` to make allocated pointers immutable before returning -error: encountered mutable pointer in final value of constant - --> $DIR/ptr_not_made_global_mut.rs:8:1 - | -LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error From 0bf0860a0ef285fe3e4eb3b176006c14d8ca9d8d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Jul 2025 15:19:17 +0200 Subject: [PATCH 234/363] simplfy memory kind handling during interning --- .../src/const_eval/dummy_machine.rs | 1 - .../src/const_eval/machine.rs | 2 - .../rustc_const_eval/src/interpret/intern.rs | 49 ++++--------------- .../rustc_const_eval/src/interpret/machine.rs | 1 + 4 files changed, 11 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index b6e2682af367..438aed41b8be 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -49,7 +49,6 @@ impl HasStaticRootDefId for DummyMachine { impl<'tcx> interpret::Machine<'tcx> for DummyMachine { interpret::compile_time_machine!(<'tcx>); - type MemoryKind = !; const PANIC_ON_ALLOC_FAIL: bool = true; // We want to just eval random consts in the program, so `eval_mir_const` can fail. diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 0a6bdef2225e..70ad57b2b11b 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -320,8 +320,6 @@ impl<'tcx> CompileTimeMachine<'tcx> { impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { compile_time_machine!(<'tcx>); - type MemoryKind = MemoryKind; - const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error #[inline(always)] diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index f25bb222bcfc..bb59b9f54186 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -30,14 +30,14 @@ use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceT use crate::const_eval::DummyMachine; use crate::{const_eval, errors}; -pub trait CompileTimeMachine<'tcx, T> = Machine< +pub trait CompileTimeMachine<'tcx> = Machine< 'tcx, - MemoryKind = T, + MemoryKind = const_eval::MemoryKind, Provenance = CtfeProvenance, ExtraFnVal = !, FrameExtra = (), AllocExtra = (), - MemoryMap = FxIndexMap, Allocation)>, + MemoryMap = FxIndexMap, Allocation)>, > + HasStaticRootDefId; pub trait HasStaticRootDefId { @@ -52,35 +52,6 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> { } } -pub enum DisallowInternReason { - ConstHeap, -} - -/// A trait for controlling whether memory allocated in the interpreter can be interned. -/// -/// This prevents us from interning `const_allocate` pointers that have not been made -/// global through `const_make_global`. -pub trait CanIntern: Copy { - fn disallows_intern(&self) -> Option; -} - -impl CanIntern for const_eval::MemoryKind { - fn disallows_intern(&self) -> Option { - match self { - const_eval::MemoryKind::Heap { was_made_global: false } => { - Some(DisallowInternReason::ConstHeap) - } - const_eval::MemoryKind::Heap { was_made_global: true } => None, - } - } -} - -impl CanIntern for ! { - fn disallows_intern(&self) -> Option { - *self - } -} - /// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory. /// /// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the @@ -88,7 +59,7 @@ impl CanIntern for ! { /// already mutable (as a sanity check). /// /// Returns an iterator over all relocations referred to by this allocation. -fn intern_shallow<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>( +fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>( ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, mutability: Mutability, @@ -102,16 +73,16 @@ fn intern_shallow<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>( }; match kind { - MemoryKind::Machine(x) if let Some(reason) = x.disallows_intern() => match reason { - DisallowInternReason::ConstHeap => { + MemoryKind::Machine(const_eval::MemoryKind::Heap { was_made_global }) => { + if !was_made_global { // Attempting to intern a `const_allocate`d pointer that was not made global via // `const_make_global`. We want to error here, but we have to first put the // allocation back into the `alloc_map` to keep things in a consistent state. ecx.memory.alloc_map.insert(alloc_id, (kind, alloc)); return Err(InternError::ConstAllocNotGlobal); } - }, - MemoryKind::Machine(_) | MemoryKind::Stack | MemoryKind::CallerLocation => {} + } + MemoryKind::Stack | MemoryKind::CallerLocation => {} } // Set allocation mutability as appropriate. This is used by LLVM to put things into @@ -204,7 +175,7 @@ pub enum InternError { /// /// For `InternKind::Static` the root allocation will not be interned, but must be handled by the caller. #[instrument(level = "debug", skip(ecx))] -pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval::MemoryKind>>( +pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( ecx: &mut InterpCx<'tcx, M>, intern_kind: InternKind, ret: &MPlaceTy<'tcx>, @@ -365,7 +336,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval /// Intern `ret`. This function assumes that `ret` references no other allocation. #[instrument(level = "debug", skip(ecx))] -pub fn intern_const_alloc_for_constprop<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>( +pub fn intern_const_alloc_for_constprop<'tcx, M: CompileTimeMachine<'tcx>>( ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, ) -> InterpResult<'tcx, ()> { diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index d150ed69250e..e981f3973ae6 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -649,6 +649,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { type ExtraFnVal = !; + type MemoryKind = $crate::const_eval::MemoryKind; type MemoryMap = rustc_data_structures::fx::FxIndexMap, Allocation)>; const GLOBAL_KIND: Option = None; // no copying of globals from `tcx` to machine memory From ecd958f4802bfead8a35a1fcdbb1c17467ad727c Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 16 Jul 2025 09:33:08 -0400 Subject: [PATCH 235/363] Fix LTO errors --- .github/workflows/release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b0c552751e3e..b7e2583aad39 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,7 +78,8 @@ jobs: - name: Run tests run: | # FIXME(antoyo): we cannot enable LTO for stdarch tests currently because of some failing LTO tests using proc-macros. - printf '[profile.release]\nlto = "fat"\n' >> build/build_sysroot/sysroot_src/library/sysroot/Cargo.toml + # FIXME(antoyo): this should probably not be needed since we embed the LTO bitcode. + printf '[profile.release]\nlto = "fat"\n' >> build/build_sysroot/sysroot_src/library/Cargo.toml EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot --keep-lto-tests ${{ matrix.commands }} - name: Run y.sh cargo build From 4e054fc4c4809a3c1df60ea99077f4d662b79750 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sun, 13 Jul 2025 11:51:22 +0200 Subject: [PATCH 236/363] Port `#[coverage]` to the new attribute system --- .../src/attributes.rs | 19 ++ .../src/encode_cross_crate.rs | 1 + .../src/attributes/codegen_attrs.rs | 41 ++- compiler/rustc_attr_parsing/src/context.rs | 26 +- .../src/session_diagnostics.rs | 49 +++- .../rustc_mir_transform/src/coverage/query.rs | 32 +-- compiler/rustc_parse/src/validate_attr.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 8 +- tests/ui/attributes/malformed-attrs.stderr | 26 +- .../ui/coverage-attr/bad-attr-ice.feat.stderr | 7 +- .../coverage-attr/bad-attr-ice.nofeat.stderr | 29 ++- tests/ui/coverage-attr/bad-syntax.stderr | 246 +++++++++--------- tests/ui/coverage-attr/name-value.rs | 7 - tests/ui/coverage-attr/name-value.stderr | 179 ++++--------- tests/ui/coverage-attr/subword.stderr | 33 ++- tests/ui/coverage-attr/word-only.rs | 7 - tests/ui/coverage-attr/word-only.stderr | 185 ++++--------- 17 files changed, 434 insertions(+), 462 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 3dedeb1b3726..24f52d6f5002 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -110,6 +110,22 @@ pub enum DeprecatedSince { Err, } +#[derive( + Copy, + Debug, + Eq, + PartialEq, + Encodable, + Decodable, + Clone, + HashStable_Generic, + PrintAttribute +)] +pub enum CoverageStatus { + On, + Off, +} + impl Deprecation { /// Whether an item marked with #[deprecated(since = "X")] is currently /// deprecated (i.e., whether X is not greater than the current rustc @@ -274,6 +290,9 @@ pub enum AttributeKind { /// Represents `#[const_trait]`. ConstTrait(Span), + /// Represents `#[coverage]`. + Coverage(Span, CoverageStatus), + ///Represents `#[rustc_deny_explicit_impl]`. DenyExplicitImpl(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 3e2dc0a15b2f..8105e4fb1255 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -28,6 +28,7 @@ impl AttributeKind { ConstStability { .. } => Yes, ConstStabilityIndirect => No, ConstTrait(..) => No, + Coverage(..) => No, DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, DoNotImplementViaObject(..) => No, diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 34d9b0483482..3e542771d58c 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, OptimizeAttr, UsedBy}; +use rustc_attr_data_structures::{AttributeKind, CoverageStatus, OptimizeAttr, UsedBy}; use rustc_feature::{AttributeTemplate, template}; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; @@ -52,6 +52,45 @@ impl NoArgsAttributeParser for ColdParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold; } +pub(crate) struct CoverageParser; + +impl SingleAttributeParser for CoverageParser { + const PATH: &[Symbol] = &[sym::coverage]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let Some(args) = args.list() else { + cx.expected_specific_argument_and_list(cx.attr_span, vec!["on", "off"]); + return None; + }; + + let Some(arg) = args.single() else { + cx.expected_single_argument(args.span); + return None; + }; + + let fail_incorrect_argument = |span| cx.expected_specific_argument(span, vec!["on", "off"]); + + let Some(arg) = arg.meta_item() else { + fail_incorrect_argument(args.span); + return None; + }; + + let status = match arg.path().word_sym() { + Some(sym::off) => CoverageStatus::Off, + Some(sym::on) => CoverageStatus::On, + None | Some(_) => { + fail_incorrect_argument(arg.span()); + return None; + } + }; + + Some(AttributeKind::Coverage(cx.attr_span, status)) + } +} + pub(crate) struct ExportNameParser; impl SingleAttributeParser for ExportNameParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 567341d1517d..043a0524269a 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -15,8 +15,9 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; use crate::attributes::codegen_attrs::{ - ColdParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser, - OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser, + ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, + OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, + UsedParser, }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; @@ -136,6 +137,7 @@ attribute_parsers!( // tidy-alphabetical-end // tidy-alphabetical-start + Single, Single, Single, Single, @@ -449,6 +451,25 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { reason: AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings: false, + list: false, + }, + }) + } + + pub(crate) fn expected_specific_argument_and_list( + &self, + span: Span, + possibilities: Vec<&'static str>, + ) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedSpecificArgument { + possibilities, + strings: false, + list: true, }, }) } @@ -466,6 +487,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { reason: AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings: true, + list: false, }, }) } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 97bf3d1c5495..67dac8da3842 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -525,7 +525,9 @@ pub(crate) struct LinkOrdinalOutOfRange { pub(crate) enum AttributeParseErrorReason { ExpectedNoArgs, - ExpectedStringLiteral { byte_string: Option }, + ExpectedStringLiteral { + byte_string: Option, + }, ExpectedIntegerLiteral, ExpectedAtLeastOneArgument, ExpectedSingleArgument, @@ -533,7 +535,12 @@ pub(crate) enum AttributeParseErrorReason { UnexpectedLiteral, ExpectedNameValue(Option), DuplicateKey(Symbol), - ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool }, + ExpectedSpecificArgument { + possibilities: Vec<&'static str>, + strings: bool, + /// Should we tell the user to write a list when they didn't? + list: bool, + }, } pub(crate) struct AttributeParseError { @@ -607,7 +614,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { format!("expected this to be of the form `{name} = \"...\"`"), ); } - AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings } => { + AttributeParseErrorReason::ExpectedSpecificArgument { + possibilities, + strings, + list: false, + } => { let quote = if strings { '"' } else { '`' }; match possibilities.as_slice() { &[] => {} @@ -633,6 +644,38 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { } } } + AttributeParseErrorReason::ExpectedSpecificArgument { + possibilities, + strings, + list: true, + } => { + let quote = if strings { '"' } else { '`' }; + match possibilities.as_slice() { + &[] => {} + &[x] => { + diag.span_label( + self.span, + format!( + "this attribute is only valid with {quote}{x}{quote} as an argument" + ), + ); + } + [first, second] => { + diag.span_label(self.span, format!("this attribute is only valid with either {quote}{first}{quote} or {quote}{second}{quote} as an argument")); + } + [first @ .., second_to_last, last] => { + let mut res = String::new(); + for i in first { + res.push_str(&format!("{quote}{i}{quote}, ")); + } + res.push_str(&format!( + "{quote}{second_to_last}{quote} or {quote}{last}{quote}" + )); + + diag.span_label(self.span, format!("this attribute is only valid with one of the following arguments: {res}")); + } + } + } } let suggestions = self.template.suggestions(false, &name); diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index ccf76dc71087..986c001de5e8 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -1,3 +1,4 @@ +use rustc_attr_data_structures::{AttributeKind, CoverageStatus, 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}; @@ -5,7 +6,6 @@ use rustc_middle::mir::{Body, Statement, StatementKind}; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::util::Providers; use rustc_span::def_id::LocalDefId; -use rustc_span::sym; use tracing::trace; use crate::coverage::counters::node_flow::make_node_counters; @@ -58,26 +58,20 @@ 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(attr) = tcx.get_attr(def_id, sym::coverage) { - match attr.meta_item_list().as_deref() { - Some([item]) if item.has_name(sym::off) => return false, - Some([item]) if item.has_name(sym::on) => return true, - Some(_) | None => { - // Other possibilities should have been rejected by `rustc_parse::validate_attr`. - // Use `span_delayed_bug` to avoid an ICE in failing builds (#127880). - tcx.dcx().span_delayed_bug(attr.span(), "unexpected value of coverage attribute"); - } + if let Some(coverage_status) = + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Coverage(_, status) => status) + { + *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 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, - } } /// Query implementation for `coverage_ids_info`. diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 783d79d978ab..a476f0db37e0 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -318,6 +318,7 @@ pub fn check_builtin_meta_item( | sym::rustc_layout_scalar_valid_range_end | sym::no_implicit_prelude | sym::automatically_derived + | sym::coverage ) { return; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2009ddc1e2d5..810472eb2ded 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -285,6 +285,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::StdInternalSymbol(attr_span)) => { self.check_rustc_std_internal_symbol(attr_span, span, target) } + &Attribute::Parsed(AttributeKind::Coverage(attr_span, _)) => { + self.check_coverage(attr_span, span, target) + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -294,7 +297,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::diagnostic, sym::on_unimplemented, ..] => { self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target) } - [sym::coverage, ..] => self.check_coverage(attr, span, target), [sym::no_sanitize, ..] => { self.check_no_sanitize(attr, span, target) } @@ -585,7 +587,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Checks that `#[coverage(..)]` is applied to a function/closure/method, /// or to an impl block or module. - fn check_coverage(&self, attr: &Attribute, target_span: Span, target: Target) { + fn check_coverage(&self, attr_span: Span, target_span: Span, target: Target) { let mut not_fn_impl_mod = None; let mut no_body = None; @@ -608,7 +610,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } self.dcx().emit_err(errors::CoverageAttributeNotAllowed { - attr_span: attr.span(), + attr_span, not_fn_impl_mod, no_body, help: (), diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 56f2be353e76..0d0c338d3026 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -37,19 +37,6 @@ error: malformed `crate_name` attribute input LL | #[crate_name] | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]` -error: malformed `coverage` attribute input - --> $DIR/malformed-attrs.rs:90:1 - | -LL | #[coverage] - | ^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL | #[coverage(off)] - | +++++ -LL | #[coverage(on)] - | ++++ - error: malformed `no_sanitize` attribute input --> $DIR/malformed-attrs.rs:92:1 | @@ -460,6 +447,19 @@ error[E0539]: malformed `link_section` attribute input LL | #[link_section] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]` +error[E0539]: malformed `coverage` attribute input + --> $DIR/malformed-attrs.rs:90:1 + | +LL | #[coverage] + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | +help: try changing it to one of the following valid forms of the attribute + | +LL | #[coverage(off)] + | +++++ +LL | #[coverage(on)] + | ++++ + error[E0565]: malformed `no_implicit_prelude` attribute input --> $DIR/malformed-attrs.rs:97:1 | diff --git a/tests/ui/coverage-attr/bad-attr-ice.feat.stderr b/tests/ui/coverage-attr/bad-attr-ice.feat.stderr index dc84394fe3c0..5a003af42da5 100644 --- a/tests/ui/coverage-attr/bad-attr-ice.feat.stderr +++ b/tests/ui/coverage-attr/bad-attr-ice.feat.stderr @@ -1,10 +1,10 @@ -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/bad-attr-ice.rs:11:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ @@ -13,3 +13,4 @@ LL | #[coverage(on)] error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr b/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr index 49b8974bfdfb..4501e5e9dc82 100644 --- a/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr +++ b/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr @@ -1,16 +1,3 @@ -error: malformed `coverage` attribute input - --> $DIR/bad-attr-ice.rs:11:1 - | -LL | #[coverage] - | ^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL | #[coverage(off)] - | +++++ -LL | #[coverage(on)] - | ++++ - error[E0658]: the `#[coverage]` attribute is an experimental feature --> $DIR/bad-attr-ice.rs:11:1 | @@ -21,6 +8,20 @@ LL | #[coverage] = help: add `#![feature(coverage_attribute)]` 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[E0539]: malformed `coverage` attribute input + --> $DIR/bad-attr-ice.rs:11:1 + | +LL | #[coverage] + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | +help: try changing it to one of the following valid forms of the attribute + | +LL | #[coverage(off)] + | +++++ +LL | #[coverage(on)] + | ++++ + error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0539, E0658. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr index fa500b542097..927f61da08db 100644 --- a/tests/ui/coverage-attr/bad-syntax.stderr +++ b/tests/ui/coverage-attr/bad-syntax.stderr @@ -1,119 +1,3 @@ -error: malformed `coverage` attribute input - --> $DIR/bad-syntax.rs:17:1 - | -LL | #[coverage] - | ^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL | #[coverage(off)] - | +++++ -LL | #[coverage(on)] - | ++++ - -error: malformed `coverage` attribute input - --> $DIR/bad-syntax.rs:20:1 - | -LL | #[coverage = true] - | ^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[coverage = true] -LL + #[coverage(off)] - | -LL - #[coverage = true] -LL + #[coverage(on)] - | - -error: malformed `coverage` attribute input - --> $DIR/bad-syntax.rs:23:1 - | -LL | #[coverage()] - | ^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL | #[coverage(off)] - | +++ -LL | #[coverage(on)] - | ++ - -error: malformed `coverage` attribute input - --> $DIR/bad-syntax.rs:26:1 - | -LL | #[coverage(off, off)] - | ^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[coverage(off, off)] -LL + #[coverage(off)] - | -LL - #[coverage(off, off)] -LL + #[coverage(on)] - | - -error: malformed `coverage` attribute input - --> $DIR/bad-syntax.rs:29:1 - | -LL | #[coverage(off, on)] - | ^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[coverage(off, on)] -LL + #[coverage(off)] - | -LL - #[coverage(off, on)] -LL + #[coverage(on)] - | - -error: malformed `coverage` attribute input - --> $DIR/bad-syntax.rs:32:1 - | -LL | #[coverage(bogus)] - | ^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[coverage(bogus)] -LL + #[coverage(off)] - | -LL - #[coverage(bogus)] -LL + #[coverage(on)] - | - -error: malformed `coverage` attribute input - --> $DIR/bad-syntax.rs:35:1 - | -LL | #[coverage(bogus, off)] - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[coverage(bogus, off)] -LL + #[coverage(off)] - | -LL - #[coverage(bogus, off)] -LL + #[coverage(on)] - | - -error: malformed `coverage` attribute input - --> $DIR/bad-syntax.rs:38:1 - | -LL | #[coverage(off, bogus)] - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[coverage(off, bogus)] -LL + #[coverage(off)] - | -LL - #[coverage(off, bogus)] -LL + #[coverage(on)] - | - error: expected identifier, found `,` --> $DIR/bad-syntax.rs:44:12 | @@ -150,5 +34,135 @@ note: attribute also specified here LL | #[coverage(on)] | ^^^^^^^^^^^^^^^ +error[E0539]: malformed `coverage` attribute input + --> $DIR/bad-syntax.rs:17:1 + | +LL | #[coverage] + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | +help: try changing it to one of the following valid forms of the attribute + | +LL | #[coverage(off)] + | +++++ +LL | #[coverage(on)] + | ++++ + +error[E0539]: malformed `coverage` attribute input + --> $DIR/bad-syntax.rs:20:1 + | +LL | #[coverage = true] + | ^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[coverage = true] +LL + #[coverage(off)] + | +LL - #[coverage = true] +LL + #[coverage(on)] + | + +error[E0805]: malformed `coverage` attribute input + --> $DIR/bad-syntax.rs:23:1 + | +LL | #[coverage()] + | ^^^^^^^^^^--^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL | #[coverage(off)] + | +++ +LL | #[coverage(on)] + | ++ + +error[E0805]: malformed `coverage` attribute input + --> $DIR/bad-syntax.rs:26:1 + | +LL | #[coverage(off, off)] + | ^^^^^^^^^^----------^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[coverage(off, off)] +LL + #[coverage(off)] + | +LL - #[coverage(off, off)] +LL + #[coverage(on)] + | + +error[E0805]: malformed `coverage` attribute input + --> $DIR/bad-syntax.rs:29:1 + | +LL | #[coverage(off, on)] + | ^^^^^^^^^^---------^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[coverage(off, on)] +LL + #[coverage(off)] + | +LL - #[coverage(off, on)] +LL + #[coverage(on)] + | + +error[E0539]: malformed `coverage` attribute input + --> $DIR/bad-syntax.rs:32:1 + | +LL | #[coverage(bogus)] + | ^^^^^^^^^^^-----^^ + | | + | valid arguments are `on` or `off` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[coverage(bogus)] +LL + #[coverage(off)] + | +LL - #[coverage(bogus)] +LL + #[coverage(on)] + | + +error[E0805]: malformed `coverage` attribute input + --> $DIR/bad-syntax.rs:35:1 + | +LL | #[coverage(bogus, off)] + | ^^^^^^^^^^------------^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[coverage(bogus, off)] +LL + #[coverage(off)] + | +LL - #[coverage(bogus, off)] +LL + #[coverage(on)] + | + +error[E0805]: malformed `coverage` attribute input + --> $DIR/bad-syntax.rs:38:1 + | +LL | #[coverage(off, bogus)] + | ^^^^^^^^^^------------^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[coverage(off, bogus)] +LL + #[coverage(off)] + | +LL - #[coverage(off, bogus)] +LL + #[coverage(on)] + | + error: aborting due to 11 previous errors +Some errors have detailed explanations: E0539, E0805. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/coverage-attr/name-value.rs b/tests/ui/coverage-attr/name-value.rs index ffd9afe2ce18..8171dbbf6927 100644 --- a/tests/ui/coverage-attr/name-value.rs +++ b/tests/ui/coverage-attr/name-value.rs @@ -20,7 +20,6 @@ mod my_mod_inner { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input -//~| ERROR [E0788] struct MyStruct; #[coverage = "off"] @@ -28,22 +27,18 @@ struct MyStruct; impl MyStruct { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] const X: u32 = 7; } #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input -//~| ERROR [E0788] trait MyTrait { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] const X: u32; #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] type T; } @@ -52,12 +47,10 @@ trait MyTrait { impl MyTrait for MyStruct { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] const X: u32 = 8; #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] type T = (); } diff --git a/tests/ui/coverage-attr/name-value.stderr b/tests/ui/coverage-attr/name-value.stderr index f24db78415e3..a838ec5df8ea 100644 --- a/tests/ui/coverage-attr/name-value.stderr +++ b/tests/ui/coverage-attr/name-value.stderr @@ -1,10 +1,10 @@ -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:12:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -13,28 +13,28 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:17:5 | LL | #![coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #![coverage = "off"] -LL + #![coverage(off)] +LL + #[coverage(off)] | LL - #![coverage = "off"] -LL + #![coverage(on)] +LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:21:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -43,13 +43,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:26:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:25:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -58,13 +58,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:29:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:28:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -73,13 +73,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:35:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:33:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -88,13 +88,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:39:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:36:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -103,13 +103,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:44:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:40:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -118,13 +118,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:50:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:45:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -133,13 +133,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:53:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:48:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -148,13 +148,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:58:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:52:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -163,13 +163,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:64:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:57:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -178,87 +178,6 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:21:1 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | struct MyStruct; - | ---------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module +error: aborting due to 12 previous errors -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:35:1 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | / trait MyTrait { -LL | | #[coverage = "off"] -... | -LL | | type T; -LL | | } - | |_- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:39:5 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | const X: u32; - | ------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:44:5 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | type T; - | ------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:29:5 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | const X: u32 = 7; - | ----------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:53:5 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | const X: u32 = 8; - | ----------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:58:5 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | type T = (); - | ------------ not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error: aborting due to 19 previous errors - -For more information about this error, try `rustc --explain E0788`. +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/coverage-attr/subword.stderr b/tests/ui/coverage-attr/subword.stderr index a5d1a492181b..32a09a10c849 100644 --- a/tests/ui/coverage-attr/subword.stderr +++ b/tests/ui/coverage-attr/subword.stderr @@ -1,10 +1,12 @@ -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/subword.rs:8:1 | LL | #[coverage(yes(milord))] - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^-----------^^ + | | + | valid arguments are `on` or `off` | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage(yes(milord))] LL + #[coverage(off)] @@ -13,13 +15,15 @@ LL - #[coverage(yes(milord))] LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/subword.rs:11:1 | LL | #[coverage(no(milord))] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^----------^^ + | | + | valid arguments are `on` or `off` | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage(no(milord))] LL + #[coverage(off)] @@ -28,13 +32,15 @@ LL - #[coverage(no(milord))] LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/subword.rs:14:1 | LL | #[coverage(yes = "milord")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^--------------^^ + | | + | valid arguments are `on` or `off` | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage(yes = "milord")] LL + #[coverage(off)] @@ -43,13 +49,15 @@ LL - #[coverage(yes = "milord")] LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/subword.rs:17:1 | LL | #[coverage(no = "milord")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^-------------^^ + | | + | valid arguments are `on` or `off` | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage(no = "milord")] LL + #[coverage(off)] @@ -60,3 +68,4 @@ LL + #[coverage(on)] error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/coverage-attr/word-only.rs b/tests/ui/coverage-attr/word-only.rs index d0f743938f3a..81bd558b8b00 100644 --- a/tests/ui/coverage-attr/word-only.rs +++ b/tests/ui/coverage-attr/word-only.rs @@ -20,7 +20,6 @@ mod my_mod_inner { #[coverage] //~^ ERROR malformed `coverage` attribute input -//~| ERROR [E0788] struct MyStruct; #[coverage] @@ -28,22 +27,18 @@ struct MyStruct; impl MyStruct { #[coverage] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] const X: u32 = 7; } #[coverage] //~^ ERROR malformed `coverage` attribute input -//~| ERROR [E0788] trait MyTrait { #[coverage] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] const X: u32; #[coverage] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] type T; } @@ -52,12 +47,10 @@ trait MyTrait { impl MyTrait for MyStruct { #[coverage] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] const X: u32 = 8; #[coverage] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] type T = (); } diff --git a/tests/ui/coverage-attr/word-only.stderr b/tests/ui/coverage-attr/word-only.stderr index 2773db9c8578..dd161360a5c4 100644 --- a/tests/ui/coverage-attr/word-only.stderr +++ b/tests/ui/coverage-attr/word-only.stderr @@ -1,240 +1,161 @@ -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:12:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:17:5 | LL | #![coverage] - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute + | +LL - #![coverage] +LL + #[coverage(off)] + | +LL - #![coverage] +LL + #[coverage(on)] | -LL | #![coverage(off)] - | +++++ -LL | #![coverage(on)] - | ++++ -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:21:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:26:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:25:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:29:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:28:5 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:35:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:33:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:39:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:36:5 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:44:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:40:5 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:50:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:45:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:53:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:48:5 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:58:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:52:5 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:64:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:57:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:21:1 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | struct MyStruct; - | ---------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module +error: aborting due to 12 previous errors -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:35:1 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | / trait MyTrait { -LL | | #[coverage] -... | -LL | | type T; -LL | | } - | |_- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:39:5 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | const X: u32; - | ------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:44:5 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | type T; - | ------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:29:5 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | const X: u32 = 7; - | ----------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:53:5 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | const X: u32 = 8; - | ----------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:58:5 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | type T = (); - | ------------ not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error: aborting due to 19 previous errors - -For more information about this error, try `rustc --explain E0788`. +For more information about this error, try `rustc --explain E0539`. From af39c0c57cb23678daaeb75ea729edd71aba14b8 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 10 Jul 2025 14:17:10 +0800 Subject: [PATCH 237/363] Emit warning when there is no space between `-o` and confusing arg Signed-off-by: xizheyin --- compiler/rustc_driver_impl/src/lib.rs | 46 +++++++++ compiler/rustc_session/src/config.rs | 5 + tests/run-make/option-output-no-space/main.rs | 1 + .../run-make/option-output-no-space/rmake.rs | 95 +++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 tests/run-make/option-output-no-space/main.rs create mode 100644 tests/run-make/option-output-no-space/rmake.rs diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 184903854555..f3ed60421056 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1237,9 +1237,55 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option bool { + let s1 = s1.replace('-', "_"); + let s2 = s2.replace('-', "_"); + s1 == s2 + } + + if let Some(name) = matches.opt_str("o") + && let Some(suspect) = args.iter().find(|arg| arg.starts_with("-o") && *arg != "-o") + { + let filename = suspect.strip_prefix("-").unwrap_or(suspect); + let optgroups = config::rustc_optgroups(); + let fake_args = ["optimize", "o0", "o1", "o2", "o3", "ofast", "og", "os", "oz"]; + + // Check if provided filename might be confusing in conjunction with `-o` flag, + // i.e. consider `-o{filename}` such as `-optimize` with `filename` being `ptimize`. + // There are high-value confusables, for example: + // - Long name of flags, e.g. `--out-dir` vs `-out-dir` + // - C compiler flag, e.g. `optimize`, `o0`, `o1`, `o2`, `o3`, `ofast`. + // - Codegen flags, e.g. `pt-level` of `-opt-level`. + if optgroups.iter().any(|option| eq_ignore_separators(option.long_name(), filename)) + || config::CG_OPTIONS.iter().any(|option| eq_ignore_separators(option.name(), filename)) + || fake_args.iter().any(|arg| eq_ignore_separators(arg, filename)) + { + early_dcx.early_warn( + "option `-o` has no space between flag name and value, which can be confusing", + ); + early_dcx.early_note(format!( + "output filename `-o {name}` is applied instead of a flag named `o{name}`" + )); + early_dcx.early_help(format!( + "insert a space between `-o` and `{name}` if this is intentional: `-o {name}`" + )); + } + } +} + fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> { let mut parser = unwrap_or_emit_fatal(match &sess.io.input { Input::File(file) => new_parser_from_file(&sess.psess, file, None), diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 4627c2978fc0..7f2f5f1c5a47 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1653,6 +1653,11 @@ impl RustcOptGroup { OptionKind::FlagMulti => options.optflagmulti(short_name, long_name, desc), }; } + + /// This is for diagnostics-only. + pub fn long_name(&self) -> &str { + self.long_name + } } pub fn make_opt( diff --git a/tests/run-make/option-output-no-space/main.rs b/tests/run-make/option-output-no-space/main.rs new file mode 100644 index 000000000000..f328e4d9d04c --- /dev/null +++ b/tests/run-make/option-output-no-space/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make/option-output-no-space/rmake.rs b/tests/run-make/option-output-no-space/rmake.rs new file mode 100644 index 000000000000..2c42f15aa89a --- /dev/null +++ b/tests/run-make/option-output-no-space/rmake.rs @@ -0,0 +1,95 @@ +// This test is to check if the warning is emitted when no space +// between `-o` and arg is applied, see issue #142812 + +//@ ignore-cross-compile +use run_make_support::rustc; + +fn main() { + // test fake args + rustc() + .input("main.rs") + .arg("-optimize") + .run() + .assert_stderr_contains( + "warning: option `-o` has no space between flag name and value, which can be confusing", + ) + .assert_stderr_contains( + "note: output filename `-o ptimize` is applied instead of a flag named `optimize`", + ); + rustc() + .input("main.rs") + .arg("-o0") + .run() + .assert_stderr_contains( + "warning: option `-o` has no space between flag name and value, which can be confusing", + ) + .assert_stderr_contains( + "note: output filename `-o 0` is applied instead of a flag named `o0`", + ); + rustc().input("main.rs").arg("-o1").run(); + // test real args by iter optgroups + rustc() + .input("main.rs") + .arg("-out-dir") + .run() + .assert_stderr_contains( + "warning: option `-o` has no space between flag name and value, which can be confusing", + ) + .assert_stderr_contains( + "note: output filename `-o ut-dir` is applied instead of a flag named `out-dir`", + ) + .assert_stderr_contains( + "help: insert a space between `-o` and `ut-dir` if this is intentional: `-o ut-dir`", + ); + // test real args by iter CG_OPTIONS + rustc() + .input("main.rs") + .arg("-opt_level") + .run() + .assert_stderr_contains( + "warning: option `-o` has no space between flag name and value, which can be confusing", + ) + .assert_stderr_contains( + "note: output filename `-o pt_level` is applied instead of a flag named `opt_level`", + ) + .assert_stderr_contains( + "help: insert a space between `-o` and `pt_level` if this is intentional: `-o pt_level`" + ); + // separater in-sensitive + rustc() + .input("main.rs") + .arg("-opt-level") + .run() + .assert_stderr_contains( + "warning: option `-o` has no space between flag name and value, which can be confusing", + ) + .assert_stderr_contains( + "note: output filename `-o pt-level` is applied instead of a flag named `opt-level`", + ) + .assert_stderr_contains( + "help: insert a space between `-o` and `pt-level` if this is intentional: `-o pt-level`" + ); + rustc() + .input("main.rs") + .arg("-overflow-checks") + .run() + .assert_stderr_contains( + "warning: option `-o` has no space between flag name and value, which can be confusing", + ) + .assert_stderr_contains( + "note: output filename `-o verflow-checks` \ + is applied instead of a flag named `overflow-checks`", + ) + .assert_stderr_contains( + "help: insert a space between `-o` and `verflow-checks` \ + if this is intentional: `-o verflow-checks`", + ); + + // No warning for Z_OPTIONS + rustc().input("main.rs").arg("-oom").run().assert_stderr_equals(""); + + // test no warning when there is space between `-o` and arg + rustc().input("main.rs").arg("-o").arg("ptimize").run().assert_stderr_equals(""); + rustc().input("main.rs").arg("--out-dir").arg("xxx").run().assert_stderr_equals(""); + rustc().input("main.rs").arg("-o").arg("out-dir").run().assert_stderr_equals(""); +} From 9ef3be2f8662a6f65c02f7551bae0f7476da8211 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 16 Jul 2025 21:29:16 +0200 Subject: [PATCH 238/363] go over invariants again :3 Co-authored-by: Boxy --- .../rustc-dev-guide/src/solve/invariants.md | 95 +++++++++++-------- 1 file changed, 55 insertions(+), 40 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/solve/invariants.md b/src/doc/rustc-dev-guide/src/solve/invariants.md index fd12b1957574..2f5a134f4dfe 100644 --- a/src/doc/rustc-dev-guide/src/solve/invariants.md +++ b/src/doc/rustc-dev-guide/src/solve/invariants.md @@ -11,10 +11,8 @@ It is important to know about the things you can assume while working on - and w type system, so here's an incomplete and unofficial list of invariants of the core type system: -- ✅: this invariant mostly holds, with some weird exceptions, you can rely on it outside -of these cases -- ❌: this invariant does not hold, either due to bugs or by design, you must not rely on -it for soundness or have to be incredibly careful when doing so +- ✅: this invariant mostly holds, with some weird exceptions or current bugs +- ❌: this invariant does not hold, and is unlikely to do so in the future; do not rely on it for soundness or have to be incredibly careful when doing so ### `wf(X)` implies `wf(normalize(X))` ✅ @@ -23,6 +21,8 @@ well-formed after normalizing said aliases. We rely on this as otherwise we would have to re-check for well-formedness for these types. +This currently does not hold due to a type system unsoundness: [#84533](https://github.com/rust-lang/rust/issues/84533). + ### Structural equality modulo regions implies semantic equality ✅ If you have a some type and equate it to itself after replacing any regions with unique @@ -36,7 +36,7 @@ If this invariant is broken MIR typeck ends up failing with an ICE. TODO: this invariant is formulated in a weird way and needs to be elaborated. Pretty much: I would like this check to only fail if there's a solver bug: -https://github.com/rust-lang/rust/blob/2ffeb4636b4ae376f716dc4378a7efb37632dc2d/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs#L391-L407 +https://github.com/rust-lang/rust/blob/2ffeb4636b4ae376f716dc4378a7efb37632dc2d/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs#L391-L407 We should readd this check and see where it breaks :3 If we prove some goal/equate types/whatever, apply the resulting inference constraints, and then redo the original action, the result should be the same. @@ -73,30 +73,6 @@ Many of the currently known unsound issues end up relying on this invariant bein It is however very difficult to imagine a sound type system without this invariant, so the issue is that the invariant is broken, not that we incorrectly rely on it. -### Generic goals and their instantiations have the same result ✅ - -Pretty much: If we successfully typecheck a generic function concrete instantiations -of that function should also typeck. We should not get errors post-monomorphization. -We can however get overflow errors at that point. - -TODO: example for overflow error post-monomorphization - -This invariant is relied on to allow the normalization of generic aliases. Breaking -it can easily result in unsoundness, e.g. [#57893](https://github.com/rust-lang/rust/issues/57893) - -### Trait goals in empty environments are proven by a unique impl ✅ - -If a trait goal holds with an empty environment, there should be a unique `impl`, -either user-defined or builtin, which is used to prove that goal. This is -necessary to select a unique method. - -We do however break this invariant in few cases, some of which are due to bugs, -some by design: -- *marker traits* are allowed to overlap as they do not have associated items -- *specialization* allows specializing impls to overlap with their parent -- the builtin trait object trait implementation can overlap with a user-defined impl: -[#57893] - ### The type system is complete ❌ The type system is not complete, it often adds unnecessary inference constraints, and errors @@ -108,6 +84,37 @@ even though the goal could hold. - preferring `ParamEnv` candidates over `Impl` candidates during candidate selection in the trait solver +### Goals keep their result from HIR typeck afterwards ✅ + +Having a goal which succeeds during HIR typeck but fails when being reevaluated during MIR borrowck causes ICE, e.g. [#140211](https://github.com/rust-lang/rust/issues/140211). + +Having a goal which succeeds during HIR typeck but fails after being instantiated is unsound, e.g. [#140212](https://github.com/rust-lang/rust/issues/140212). + +It is interesting that we allow some incompleteness in the trait solver while still maintaining this limitation. It would be nice if there was a clear way to separate the "allowed incompleteness" from behavior which would break this invariant. + +#### Normalization must not change results + +This invariant is relied on to allow the normalization of generic aliases. Breaking +it can easily result in unsoundness, e.g. [#57893](https://github.com/rust-lang/rust/issues/57893) + +#### Goals may still overflow after instantiation + +As they start to hit the recursion limit. We also have diverging aliases which are scuffed. It's unclear how these should be handled :3 + +### Trait goals in empty environments are proven by a unique impl ✅ + +If a trait goal holds with an empty environment, there should be a unique `impl`, +either user-defined or builtin, which is used to prove that goal. This is +necessary to select unique methods and associated items. + +We do however break this invariant in few cases, some of which are due to bugs, +some by design: +- *marker traits* are allowed to overlap as they do not have associated items +- *specialization* allows specializing impls to overlap with their parent +- the builtin trait object trait implementation can overlap with a user-defined impl: +[#57893](https://github.com/rust-lang/rust/issues/57893) + + #### The type system is complete during the implicit negative overlap check in coherence ✅ For more on overlap checking: [coherence] @@ -121,18 +128,19 @@ We have to be careful as it is quite easy to break: - generalization of aliases - generalization during subtyping binders (luckily not exploitable in coherence) -### Trait solving must be (free) lifetime agnostic ✅ +### Trait solving must not depend on lifetimes being different ✅ -Trait solving during codegen should have the same result as during typeck. As we erase -all free regions during codegen we must not rely on them during typeck. A noteworthy example -is special behavior for `'static`. +If a goal holds with lifetimes being different, it must also hold with these lifetimes being the same. We otherwise get post-monomorphization errors during codegen or unsoundness due to invalid vtables. + +We could also just get inconsistent behavior when first proving a goal with different lifetimes which are later constrained to be equal. + +### Trait solving in bodies must not depend on lifetimes being equal ✅ We also have to be careful with relying on equality of regions in the trait solver. This is fine for codegen, as we treat all erased regions as equal. We can however lose equality information from HIR to MIR typeck. -The new solver "uniquifies regions" during canonicalization, canonicalizing `u32: Trait<'x, 'x>` -as `exists<'0, '1> u32: Trait<'0, '1>`, to make it harder to rely on this property. +This currently does not hold with the new solver: [trait-system-refactor-initiative#27](https://github.com/rust-lang/trait-system-refactor-initiative/issues/27). ### Removing ambiguity makes strictly more things compile ❌ @@ -146,9 +154,16 @@ changes, breaking existing projects. Two types being equal in the type system must mean that they have the same `TypeId` after instantiating their generic parameters with concrete -arguments. This currently does not hold: [#97156]. +arguments. We can otherwise use their different `TypeId`s to impact trait selection. -[#57893]: https://github.com/rust-lang/rust/issues/57893 -[#97156]: https://github.com/rust-lang/rust/issues/97156 -[#114936]: https://github.com/rust-lang/rust/issues/114936 -[coherence]: ../coherence.md +We lookup types using structural equality during codegen, but this shouldn't necessarily be unsound +- may result in redundant method codegen or backend type check errors? +- we also rely on it in CTFE assertions + +### Semantically different types have different `TypeId`s ✅ + +Semantically different `'static` types need different `TypeId`s to avoid transmutes, +for example `for<'a> fn(&'a str)` vs `fn(&'static str)` must have a different `TypeId`. + + +[coherence]: ../coherence.md From f100767dce1fcc0287047053cc29659ac5321a6b Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 1 Jul 2025 20:02:31 +0200 Subject: [PATCH 239/363] fix `-Zsanitizer=kcfi` on `#[naked]` functions And more broadly only codegen `InstanceKind::Item` using the naked function codegen code. Other instance kinds should follow the normal path. --- .../rustc_codegen_cranelift/src/driver/aot.rs | 8 +++- compiler/rustc_codegen_ssa/src/mono_item.rs | 13 ++--- .../codegen/sanitizer/kcfi/naked-function.rs | 47 +++++++++++++++++++ tests/ui/asm/naked-function-shim.rs | 31 ++++++++++++ 4 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 tests/codegen/sanitizer/kcfi/naked-function.rs create mode 100644 tests/ui/asm/naked-function-shim.rs diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 442151fe32de..727f2760c0f9 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -530,8 +530,12 @@ fn codegen_cgu_content( for (mono_item, item_data) in mono_items { match mono_item { MonoItem::Fn(instance) => { - if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) - { + // Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be + // codegened like a normal function. + let is_item_instance = matches!(instance.def, InstanceKind::Item(_)); + + let flags = tcx.codegen_fn_attrs(instance.def_id()).flags; + if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) { rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm( &mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm }, instance, diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 7b4268abe4b1..fa0ef04b2e67 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -1,5 +1,6 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; +use rustc_middle::ty::InstanceKind; use rustc_middle::ty::layout::HasTyCtxt; use tracing::debug; @@ -41,12 +42,12 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { base::codegen_global_asm(cx, item_id); } MonoItem::Fn(instance) => { - if cx - .tcx() - .codegen_fn_attrs(instance.def_id()) - .flags - .contains(CodegenFnAttrFlags::NAKED) - { + // Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be + // codegened like a normal function. + let is_item_instance = matches!(instance.def, InstanceKind::Item(_)); + + let flags = cx.tcx().codegen_fn_attrs(instance.def_id()).flags; + if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) { naked_asm::codegen_naked_asm::(cx, instance, item_data); } else { base::codegen_instance::(cx, instance); diff --git a/tests/codegen/sanitizer/kcfi/naked-function.rs b/tests/codegen/sanitizer/kcfi/naked-function.rs new file mode 100644 index 000000000000..92431fc7d633 --- /dev/null +++ b/tests/codegen/sanitizer/kcfi/naked-function.rs @@ -0,0 +1,47 @@ +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [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 +//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Cno-prepopulate-passes -Copt-level=0 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +struct Thing; +trait MyTrait { + #[unsafe(naked)] + extern "C" fn my_naked_function() { + // the real function is defined + // CHECK: .globl + // CHECK-SAME: my_naked_function + naked_asm!("ret") + } +} +impl MyTrait for Thing {} + +// CHECK-LABEL: main +#[unsafe(no_mangle)] +pub fn main() { + // Trick the compiler into generating an indirect call. + const F: extern "C" fn() = Thing::my_naked_function; + + // main calls the shim function + // CHECK: call + // CHECK-SAME: my_naked_function + // CHECK-SAME: reify.shim.fnptr + (F)(); +} + +// the shim calls the real function +// CHECK: define +// CHECK-SAME: my_naked_function +// CHECK-SAME: reify.shim.fnptr + +// CHECK: declare !kcfi_type +// CHECK-SAME: my_naked_function diff --git a/tests/ui/asm/naked-function-shim.rs b/tests/ui/asm/naked-function-shim.rs new file mode 100644 index 000000000000..4694d0cd963e --- /dev/null +++ b/tests/ui/asm/naked-function-shim.rs @@ -0,0 +1,31 @@ +// The indirect call will generate a shim that then calls the actual function. Test that +// this is handled correctly. See also https://github.com/rust-lang/rust/issues/143266. + +//@ build-pass +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [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 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +trait MyTrait { + #[unsafe(naked)] + extern "C" fn foo(&self) { + naked_asm!("ret") + } +} + +impl MyTrait for i32 {} + +fn main() { + let x: extern "C" fn(&_) = ::foo; + x(&1); +} From ec0ff720d1a89cb51edd90116c6e70051affa95f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 2 Jul 2025 10:46:15 +0200 Subject: [PATCH 240/363] add `codegen_instance_attrs` query and use it for naked functions --- .../rustc_codegen_cranelift/src/driver/aot.rs | 8 ++------ .../rustc_codegen_ssa/src/codegen_attrs.rs | 1 + .../rustc_codegen_ssa/src/mir/debuginfo.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 5 ++--- compiler/rustc_codegen_ssa/src/mono_item.rs | 9 ++------- .../src/middle/codegen_fn_attrs.rs | 20 +++++++++++++++++++ .../codegen/sanitizer/kcfi/naked-function.rs | 12 +++++------ 7 files changed, 34 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 727f2760c0f9..8ec3599b63d8 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -530,12 +530,8 @@ fn codegen_cgu_content( for (mono_item, item_data) in mono_items { match mono_item { MonoItem::Fn(instance) => { - // Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be - // codegened like a normal function. - let is_item_instance = matches!(instance.def, InstanceKind::Item(_)); - - let flags = tcx.codegen_fn_attrs(instance.def_id()).flags; - if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) { + let flags = tcx.codegen_instance_attrs(instance.def).flags; + if flags.contains(CodegenFnAttrFlags::NAKED) { rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm( &mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm }, instance, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 85d01d4f9389..a1dd64736fc2 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -114,6 +114,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.export_name = Some(*name); } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, + AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name), AttributeKind::LinkSection { name, .. } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 025f5fb54f42..b8f635ab7816 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -356,7 +356,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Operand(operand) => { // Don't spill operands onto the stack in naked functions. // See: https://github.com/rust-lang/rust/issues/42779 - let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id()); + let attrs = bx.tcx().codegen_instance_attrs(self.instance.def); if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { return; } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index fa69820d5d2e..50d0f9107445 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -390,9 +390,8 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mut num_untupled = None; - let codegen_fn_attrs = bx.tcx().codegen_fn_attrs(fx.instance.def_id()); - let naked = codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED); - if naked { + let codegen_fn_attrs = bx.tcx().codegen_instance_attrs(fx.instance.def); + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { return vec![]; } diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index fa0ef04b2e67..2c3a6de750e2 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -1,6 +1,5 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; -use rustc_middle::ty::InstanceKind; use rustc_middle::ty::layout::HasTyCtxt; use tracing::debug; @@ -42,12 +41,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { base::codegen_global_asm(cx, item_id); } MonoItem::Fn(instance) => { - // Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be - // codegened like a normal function. - let is_item_instance = matches!(instance.def, InstanceKind::Item(_)); - - let flags = cx.tcx().codegen_fn_attrs(instance.def_id()).flags; - if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) { + let flags = cx.tcx().codegen_instance_attrs(instance.def).flags; + if flags.contains(CodegenFnAttrFlags::NAKED) { naked_asm::codegen_naked_asm::(cx, instance, item_data); } else { base::codegen_instance::(cx, instance); diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 2f16d385efb3..92670e7e018f 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use rustc_abi::Align; use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs; use rustc_attr_data_structures::{InlineAttr, InstructionSetAttr, OptimizeAttr}; @@ -6,6 +8,24 @@ use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; use crate::mir::mono::Linkage; +use crate::ty::{InstanceKind, TyCtxt}; + +impl<'tcx> TyCtxt<'tcx> { + pub fn codegen_instance_attrs( + self, + instance_kind: InstanceKind<'_>, + ) -> Cow<'tcx, CodegenFnAttrs> { + let mut attrs = Cow::Borrowed(self.codegen_fn_attrs(instance_kind.def_id())); + + // Drop the `#[naked]` attribute on non-item `InstanceKind`s, like the shims that + // are generated for indirect function calls. + if !matches!(instance_kind, InstanceKind::Item(_)) { + attrs.to_mut().flags.remove(CodegenFnAttrFlags::NAKED); + } + + attrs + } +} #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)] pub struct CodegenFnAttrs { diff --git a/tests/codegen/sanitizer/kcfi/naked-function.rs b/tests/codegen/sanitizer/kcfi/naked-function.rs index 92431fc7d633..2c8cdc919b85 100644 --- a/tests/codegen/sanitizer/kcfi/naked-function.rs +++ b/tests/codegen/sanitizer/kcfi/naked-function.rs @@ -25,6 +25,11 @@ trait MyTrait { } impl MyTrait for Thing {} +// the shim calls the real function +// CHECK-LABEL: define +// CHECK-SAME: my_naked_function +// CHECK-SAME: reify.shim.fnptr + // CHECK-LABEL: main #[unsafe(no_mangle)] pub fn main() { @@ -32,16 +37,11 @@ pub fn main() { const F: extern "C" fn() = Thing::my_naked_function; // main calls the shim function - // CHECK: call + // CHECK: call void // CHECK-SAME: my_naked_function // CHECK-SAME: reify.shim.fnptr (F)(); } -// the shim calls the real function -// CHECK: define -// CHECK-SAME: my_naked_function -// CHECK-SAME: reify.shim.fnptr - // CHECK: declare !kcfi_type // CHECK-SAME: my_naked_function From 9c8ab891876b37aac458a7461d904fe593856745 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 2 Jul 2025 11:12:54 +0200 Subject: [PATCH 241/363] use `codegen_instance_attrs` where an instance is (easily) available --- compiler/rustc_codegen_cranelift/src/driver/jit.rs | 2 +- compiler/rustc_codegen_cranelift/src/driver/mod.rs | 2 +- compiler/rustc_codegen_gcc/src/attributes.rs | 2 +- compiler/rustc_codegen_gcc/src/callee.rs | 2 +- compiler/rustc_codegen_gcc/src/mono_item.rs | 2 +- compiler/rustc_codegen_llvm/src/attributes.rs | 2 +- compiler/rustc_codegen_llvm/src/callee.rs | 2 +- compiler/rustc_codegen_llvm/src/mono_item.rs | 4 ++-- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 1 - compiler/rustc_codegen_ssa/src/mir/naked_asm.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 12 ++++++++++-- compiler/rustc_codegen_ssa/src/mono_item.rs | 2 +- compiler/rustc_const_eval/src/interpret/memory.rs | 2 +- .../rustc_middle/src/middle/codegen_fn_attrs.rs | 4 +++- compiler/rustc_middle/src/mir/mono.rs | 13 ++++++------- compiler/rustc_middle/src/query/mod.rs | 9 +++++++++ compiler/rustc_symbol_mangling/src/lib.rs | 2 +- src/tools/miri/src/machine.rs | 4 ++-- 18 files changed, 43 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index b1f185b551c3..b3497503bf06 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -127,7 +127,7 @@ fn codegen_and_compile_fn<'tcx>( module: &mut dyn Module, instance: Instance<'tcx>, ) { - if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) { + if tcx.codegen_instance_attrs(instance.def).flags.contains(CodegenFnAttrFlags::NAKED) { tcx.dcx() .span_fatal(tcx.def_span(instance.def_id()), "Naked asm is not supported in JIT mode"); } diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs index ffd47cace380..8f83c30b598d 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs @@ -35,7 +35,7 @@ fn predefine_mono_items<'tcx>( is_compiler_builtins, ); let is_naked = tcx - .codegen_fn_attrs(instance.def_id()) + .codegen_instance_attrs(instance.def) .flags .contains(CodegenFnAttrFlags::NAKED); module diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index bf0927dc590b..7a1ae6ca9c8b 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -87,7 +87,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>( #[cfg_attr(not(feature = "master"), allow(unused_variables))] func: Function<'gcc>, instance: ty::Instance<'tcx>, ) { - let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def); #[cfg(feature = "master")] { diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs index 189ac7cd7792..e7ca95af594c 100644 --- a/compiler/rustc_codegen_gcc/src/callee.rs +++ b/compiler/rustc_codegen_gcc/src/callee.rs @@ -105,7 +105,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) let is_hidden = if is_generic { // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() - || tcx.codegen_fn_attrs(instance_def_id).inline + || tcx.codegen_instance_attrs(instance.def).inline == rustc_attr_data_structures::InlineAttr::Never) { // When not sharing generics, all instances are in the same diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs index 539e3ac85076..51f35cbdee47 100644 --- a/compiler/rustc_codegen_gcc/src/mono_item.rs +++ b/compiler/rustc_codegen_gcc/src/mono_item.rs @@ -53,7 +53,7 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); self.linkage.set(base::linkage_to_gcc(linkage)); let decl = self.declare_fn(symbol_name, fn_abi); - //let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); + //let attrs = self.tcx.codegen_instance_attrs(instance.def); attributes::from_fn_attrs(self, decl, instance); diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 1ea5a062254a..c32f11b27f3d 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -344,7 +344,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( llfn: &'ll Value, instance: ty::Instance<'tcx>, ) { - let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def); let mut to_add = SmallVec::<[_; 16]>::new(); diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 6d68eca60afc..5a3dd90ab240 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -102,7 +102,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t let is_hidden = if is_generic { // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() - || tcx.codegen_fn_attrs(instance_def_id).inline + || tcx.codegen_instance_attrs(instance.def).inline == rustc_attr_data_structures::InlineAttr::Never) { // When not sharing generics, all instances are in the same diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 3f38e1e191bf..c471a02baa26 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -55,8 +55,8 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance)); llvm::set_linkage(lldecl, base::linkage_to_llvm(linkage)); - let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); - base::set_link_section(lldecl, attrs); + let attrs = self.tcx.codegen_instance_attrs(instance.def); + base::set_link_section(lldecl, &attrs); if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR) && self.tcx.sess.target.supports_comdat() { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index a1dd64736fc2..85d01d4f9389 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -114,7 +114,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.export_name = Some(*name); } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, - AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name), AttributeKind::LinkSection { name, .. } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index beaf89509784..42e435cf0a32 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -128,7 +128,7 @@ fn prefix_and_suffix<'tcx>( let is_arm = tcx.sess.target.arch == "arm"; let is_thumb = tcx.sess.unstable_target_features.contains(&sym::thumb_mode); - let attrs = tcx.codegen_fn_attrs(instance.def_id()); + let attrs = tcx.codegen_instance_attrs(instance.def); let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string()); // If no alignment is specified, an alignment of 4 bytes is used. diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index e90463aacc8a..2587e89417a6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -611,11 +611,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty()); let fn_ty = bx.fn_decl_backend_type(fn_abi); let fn_attrs = if bx.tcx().def_kind(instance.def_id()).has_codegen_attrs() { - Some(bx.tcx().codegen_fn_attrs(instance.def_id())) + Some(bx.tcx().codegen_instance_attrs(instance.def)) } else { None }; - bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None, Some(instance)) + bx.call( + fn_ty, + fn_attrs.as_deref(), + Some(fn_abi), + fn_ptr, + &[], + None, + Some(instance), + ) } else { bx.get_static(def_id) }; diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 2c3a6de750e2..b9040c330fb1 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -71,7 +71,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { cx.predefine_static(def_id, linkage, visibility, symbol_name); } MonoItem::Fn(instance) => { - let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()); + let attrs = cx.tcx().codegen_instance_attrs(instance.def); if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { // do not define this function; it will become a global assembly block diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 6414821e21d0..0dd274b1b000 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -890,7 +890,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(fn_val) = self.get_fn_alloc(id) { let align = match fn_val { FnVal::Instance(instance) => { - self.tcx.codegen_fn_attrs(instance.def_id()).alignment.unwrap_or(Align::ONE) + self.tcx.codegen_instance_attrs(instance.def).alignment.unwrap_or(Align::ONE) } // Machine-specific extra functions currently do not support alignment restrictions. FnVal::Other(_) => Align::ONE, diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 92670e7e018f..6eae3b51e29f 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -20,7 +20,9 @@ impl<'tcx> TyCtxt<'tcx> { // Drop the `#[naked]` attribute on non-item `InstanceKind`s, like the shims that // are generated for indirect function calls. if !matches!(instance_kind, InstanceKind::Item(_)) { - attrs.to_mut().flags.remove(CodegenFnAttrFlags::NAKED); + if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + attrs.to_mut().flags.remove(CodegenFnAttrFlags::NAKED); + } } attrs diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 47ba850d50dd..2d7ddd105bd4 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -152,7 +152,7 @@ impl<'tcx> MonoItem<'tcx> { // If the function is #[naked] or contains any other attribute that requires exactly-once // instantiation: // We emit an unused_attributes lint for this case, which should be kept in sync if possible. - let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id()); + let codegen_fn_attrs = tcx.codegen_instance_attrs(instance.def); if codegen_fn_attrs.contains_extern_indicator() || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { @@ -219,7 +219,7 @@ impl<'tcx> MonoItem<'tcx> { // functions the same as those that unconditionally get LocalCopy codegen. It's only when // we get here that we can at least not codegen a #[inline(never)] generic function in all // of our CGUs. - if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline + if let InlineAttr::Never = codegen_fn_attrs.inline && self.is_generic_fn() { return InstantiationMode::GloballyShared { may_conflict: true }; @@ -234,14 +234,13 @@ impl<'tcx> MonoItem<'tcx> { } pub fn explicit_linkage(&self, tcx: TyCtxt<'tcx>) -> Option { - let def_id = match *self { - MonoItem::Fn(ref instance) => instance.def_id(), - MonoItem::Static(def_id) => def_id, + let instance_kind = match *self { + MonoItem::Fn(ref instance) => instance.def, + MonoItem::Static(def_id) => InstanceKind::Item(def_id), MonoItem::GlobalAsm(..) => return None, }; - let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); - codegen_fn_attrs.linkage + tcx.codegen_instance_attrs(instance_kind).linkage } /// Returns `true` if this instance is instantiable - whether it has no unsatisfied diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 842d118449a5..ec9f6d918e2c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1505,6 +1505,15 @@ rustc_queries! { separate_provide_extern } + /// Returns the `CodegenFnAttrs` for the item at `def_id`. + /// + /// If possible, use `tcx.codegen_instance_attrs` instead. That function takes the + /// instance kind into account. + /// + /// For example, the `#[naked]` attribute should be applied for `InstanceKind::Item`, + /// but should not be applied if the instance kind is `InstanceKind::ReifyShim`. + /// Using this query would include the attribute regardless of the actual instance + /// kind at the call site. query codegen_fn_attrs(def_id: DefId) -> &'tcx CodegenFnAttrs { desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) } arena_cache diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index a9bf5eae445e..6bcb7f6e093c 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -180,7 +180,7 @@ fn compute_symbol_name<'tcx>( // FIXME(eddyb) Precompute a custom symbol name based on attributes. let attrs = if tcx.def_kind(def_id).has_codegen_attrs() { - tcx.codegen_fn_attrs(def_id) + &tcx.codegen_instance_attrs(instance.def) } else { CodegenFnAttrs::EMPTY }; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 35399dbf4cb0..e8ae3350e563 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1086,7 +1086,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx: &MiriInterpCx<'tcx>, instance: ty::Instance<'tcx>, ) -> InterpResult<'tcx> { - let attrs = ecx.tcx.codegen_fn_attrs(instance.def_id()); + let attrs = ecx.tcx.codegen_instance_attrs(instance.def); if attrs .target_features .iter() @@ -1790,7 +1790,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx.tcx.sess.opts.unstable_opts.cross_crate_inline_threshold, InliningThreshold::Always ) || !matches!( - ecx.tcx.codegen_fn_attrs(instance.def_id()).inline, + ecx.tcx.codegen_instance_attrs(instance.def).inline, InlineAttr::Never ); !is_generic && !can_be_inlined From fb7aa9e4fdb88a4833274303899b9801ef924100 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 May 2025 15:51:47 +1000 Subject: [PATCH 242/363] Improve path segment joining. There are many places that join path segments with `::` to produce a string. A lot of these use `join("::")`. Many in rustdoc use `join_with_double_colon`, and a few use `.joined("..")`. One in Clippy uses `itertools::join`. A couple of them look for `kw::PathRoot` in the first segment, which can be important. This commit introduces `rustc_ast::join_path_{syms,ident}` to do the joining for everyone. `rustc_ast` is as good a location for these as any, being the earliest-running of the several crates with a `Path` type. Two functions are needed because `Ident` printing is more complex than simple `Symbol` printing. The commit also removes `join_with_double_colon`, and `estimate_item_path_byte_length` with it. There are still a handful of places that join strings with "::" that are unchanged. They are not that important: some of them are in tests, and some of them first split a path around "::" and then rejoin with "::". This fixes one test case where `{{root}}` shows up in an error message. --- compiler/rustc_ast/src/ast.rs | 55 ++++++++++++++++++- .../rustc_builtin_macros/src/source_util.rs | 4 +- compiler/rustc_builtin_macros/src/test.rs | 9 +-- compiler/rustc_hir/src/hir.rs | 4 +- .../src/method/prelude_edition_lints.rs | 11 ++-- compiler/rustc_passes/src/check_attr.rs | 6 +- compiler/rustc_resolve/src/diagnostics.rs | 29 +++++----- compiler/rustc_resolve/src/rustdoc.rs | 10 ++-- src/librustdoc/clean/utils.rs | 11 +--- src/librustdoc/formats/cache.rs | 4 +- src/librustdoc/html/format.rs | 23 ++------ src/librustdoc/html/render/context.rs | 4 +- src/librustdoc/html/render/mod.rs | 9 +-- src/librustdoc/html/render/print_item.rs | 9 +-- src/librustdoc/html/render/search_index.rs | 14 ++--- src/librustdoc/html/render/write_shared.rs | 4 +- src/librustdoc/html/url_parts_builder.rs | 12 +--- .../methods/from_iter_instead_of_collect.rs | 3 +- src/tools/clippy/clippy_utils/src/lib.rs | 17 +++--- tests/ui/asm/naked-invalid-attr.stderr | 2 +- 20 files changed, 130 insertions(+), 110 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3c576316f623..fa542a810dce 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -18,7 +18,7 @@ //! - [`Attribute`]: Metadata associated with item. //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators. -use std::borrow::Cow; +use std::borrow::{Borrow, Cow}; use std::{cmp, fmt}; pub use GenericArgs::*; @@ -155,6 +155,59 @@ impl Path { } } +/// Joins multiple symbols with "::" into a path, e.g. "a::b::c". If the first +/// segment is `kw::PathRoot` it will be printed as empty, e.g. "::b::c". +/// +/// The generics on the `path` argument mean it can accept many forms, such as: +/// - `&[Symbol]` +/// - `Vec` +/// - `Vec<&Symbol>` +/// - `impl Iterator` +/// - `impl Iterator` +/// +/// Panics if `path` is empty or a segment after the first is `kw::PathRoot`. +pub fn join_path_syms(path: impl IntoIterator>) -> String { + // This is a guess at the needed capacity that works well in practice. It is slightly faster + // than (a) starting with an empty string, or (b) computing the exact capacity required. + // `8` works well because it's about the right size and jemalloc's size classes are all + // multiples of 8. + let mut iter = path.into_iter(); + let len_hint = iter.size_hint().1.unwrap_or(1); + let mut s = String::with_capacity(len_hint * 8); + + let first_sym = *iter.next().unwrap().borrow(); + if first_sym != kw::PathRoot { + s.push_str(first_sym.as_str()); + } + for sym in iter { + let sym = *sym.borrow(); + debug_assert_ne!(sym, kw::PathRoot); + s.push_str("::"); + s.push_str(sym.as_str()); + } + s +} + +/// Like `join_path_syms`, but for `Ident`s. This function is necessary because +/// `Ident::to_string` does more than just print the symbol in the `name` field. +pub fn join_path_idents(path: impl IntoIterator>) -> String { + let mut iter = path.into_iter(); + let len_hint = iter.size_hint().1.unwrap_or(1); + let mut s = String::with_capacity(len_hint * 8); + + let first_ident = *iter.next().unwrap().borrow(); + if first_ident.name != kw::PathRoot { + s.push_str(&first_ident.to_string()); + } + for ident in iter { + let ident = *ident.borrow(); + debug_assert_ne!(ident.name, kw::PathRoot); + s.push_str("::"); + s.push_str(&ident.to_string()); + } + s +} + /// A segment of a path: an identifier, an optional lifetime, and a set of types. /// /// E.g., `std`, `String` or `Box`. diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index cebfffa1e16c..ecfd46a84ec3 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -4,8 +4,8 @@ use std::sync::Arc; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{join_path_idents, token}; use rustc_ast_pretty::pprust; use rustc_expand::base::{ DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult, resolve_path, @@ -100,7 +100,7 @@ pub(crate) fn expand_mod( let sp = cx.with_def_site_ctxt(sp); check_zero_tts(cx, sp, tts, "module_path!"); let mod_path = &cx.current_expansion.module.mod_path; - let string = mod_path.iter().map(|x| x.to_string()).collect::>().join("::"); + let string = join_path_idents(mod_path); ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string)))) } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index b067578794b3..ba3d8368b2a0 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -5,7 +5,7 @@ use std::assert_matches::assert_matches; use std::iter; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, GenericParamKind, attr}; +use rustc_ast::{self as ast, GenericParamKind, attr, join_path_idents}; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, Diag, Level}; use rustc_expand::base::*; @@ -446,12 +446,7 @@ fn get_location_info(cx: &ExtCtxt<'_>, fn_: &ast::Fn) -> (Symbol, usize, usize, } fn item_path(mod_path: &[Ident], item_ident: &Ident) -> String { - mod_path - .iter() - .chain(iter::once(item_ident)) - .map(|x| x.to_string()) - .collect::>() - .join("::") + join_path_idents(mod_path.iter().chain(iter::once(item_ident))) } enum ShouldPanic { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 159518a8d871..ace2259aec38 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -7,7 +7,7 @@ use rustc_ast::token::CommentKind; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{ self as ast, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitIntType, - LitKind, TraitObjectSyntax, UintTy, UnsafeBinderCastKind, + LitKind, TraitObjectSyntax, UintTy, UnsafeBinderCastKind, join_path_idents, }; pub use rustc_ast::{ AssignOp, AssignOpKind, AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind, @@ -1168,7 +1168,7 @@ impl AttrPath { impl fmt::Display for AttrPath { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.segments.iter().map(|i| i.to_string()).collect::>().join("::")) + write!(f, "{}", join_path_idents(&self.segments)) } } diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs index 0037d5ac042b..38413cca633c 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -2,6 +2,7 @@ use std::fmt::Write; use hir::def_id::DefId; use hir::{HirId, ItemKind}; +use rustc_ast::join_path_idents; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; @@ -383,13 +384,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // All that is left is `_`! We need to use the full path. It doesn't matter which one we // pick, so just take the first one. match import_items[0].kind { - ItemKind::Use(path, _) => Some( - path.segments - .iter() - .map(|segment| segment.ident.to_string()) - .collect::>() - .join("::"), - ), + ItemKind::Use(path, _) => { + Some(join_path_idents(path.segments.iter().map(|seg| seg.ident))) + } _ => { span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind); } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2009ddc1e2d5..5b2b9c152aa7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,7 @@ use std::collections::hash_map::Entry; use std::slice; use rustc_abi::{Align, ExternAbi, Size}; -use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast}; +use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast, join_path_syms}; use rustc_attr_data_structures::{AttributeKind, InlineAttr, ReprAttr, find_attr}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; @@ -678,9 +678,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { allowed_target: Target, ) { if target != allowed_target { - let path = attr.path(); - let path: Vec<_> = path.iter().map(|s| s.as_str()).collect(); - let attr_name = path.join("::"); + let attr_name = join_path_syms(attr.path()); self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 11e4a729ae23..5a162b5d2b90 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1,6 +1,8 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path}; +use rustc_ast::{ + self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path, join_path_idents, +}; use rustc_ast_pretty::pprust; use rustc_attr_data_structures::{ self as attr, AttributeKind, CfgEntry, Stability, StrippedCfgItem, find_attr, @@ -2018,7 +2020,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - let mut sugg_paths = vec![]; + let mut sugg_paths: Vec<(Vec, bool)> = vec![]; if let Some(mut def_id) = res.opt_def_id() { // We can't use `def_path_str` in resolve. let mut path = vec![def_id]; @@ -2031,16 +2033,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } // We will only suggest importing directly if it is accessible through that path. - let path_names: Option> = path + let path_names: Option> = path .iter() .rev() .map(|def_id| { - self.tcx.opt_item_name(*def_id).map(|n| { - if def_id.is_top_level_module() { - "crate".to_string() + self.tcx.opt_item_name(*def_id).map(|name| { + Ident::with_dummy_span(if def_id.is_top_level_module() { + kw::Crate } else { - n.to_string() - } + name + }) }) }) .collect(); @@ -2084,13 +2086,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match binding.kind { NameBindingKind::Import { import, .. } => { for segment in import.module_path.iter().skip(1) { - path.push(segment.ident.to_string()); + path.push(segment.ident); } sugg_paths.push(( - path.iter() - .cloned() - .chain(vec![ident.to_string()].into_iter()) - .collect::>(), + path.iter().cloned().chain(std::iter::once(ident)).collect::>(), true, // re-export )); } @@ -2126,7 +2125,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.subdiagnostic(note); } // We prioritize shorter paths, non-core imports and direct imports over the alternatives. - sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport)); + sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0].name == sym::core, *reexport)); for (sugg, reexport) in sugg_paths { if not_publicly_reexported { break; @@ -2136,7 +2135,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // `tests/ui/imports/issue-55884-2.rs` continue; } - let path = sugg.join("::"); + let path = join_path_idents(sugg); let sugg = if reexport { errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path } } else { diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index f61cd1f0adfb..24e15ded94fe 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -7,6 +7,7 @@ use pulldown_cmark::{ }; use rustc_ast as ast; use rustc_ast::attr::AttributeExt; +use rustc_ast::join_path_syms; use rustc_ast::util::comments::beautify_doc_string; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordSet; @@ -259,7 +260,7 @@ pub fn main_body_opts() -> Options { | Options::ENABLE_SMART_PUNCTUATION } -fn strip_generics_from_path_segment(segment: Vec) -> Result { +fn strip_generics_from_path_segment(segment: Vec) -> Result { let mut stripped_segment = String::new(); let mut param_depth = 0; @@ -284,7 +285,7 @@ fn strip_generics_from_path_segment(segment: Vec) -> Result>` Err(MalformedGenerics::UnbalancedAngleBrackets) @@ -346,9 +347,8 @@ pub fn strip_generics_from_path(path_str: &str) -> Result, MalformedGen debug!("path_str: {path_str:?}\nstripped segments: {stripped_segments:?}"); - let stripped_path = stripped_segments.join("::"); - - if !stripped_path.is_empty() { + if !stripped_segments.is_empty() { + let stripped_path = join_path_syms(stripped_segments); Ok(stripped_path.into()) } else { Err(MalformedGenerics::MissingType) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index bf3f7607274d..fd1b17b64765 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -3,6 +3,7 @@ use std::fmt::{self, Display, Write as _}; use std::sync::LazyLock as Lazy; use std::{ascii, mem}; +use rustc_ast::join_path_idents; use rustc_ast::tokenstream::TokenTree; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; @@ -24,7 +25,7 @@ use crate::clean::{ clean_middle_ty, inline, }; use crate::core::DocContext; -use crate::display::{Joined as _, MaybeDisplay as _}; +use crate::display::Joined as _; #[cfg(test)] mod tests; @@ -251,13 +252,7 @@ pub(crate) fn qpath_to_string(p: &hir::QPath<'_>) -> String { hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(), }; - fmt::from_fn(|f| { - segments - .iter() - .map(|seg| (seg.ident.name != kw::PathRoot).then_some(seg.ident).maybe_display()) - .joined("::", f) - }) - .to_string() + join_path_idents(segments.iter().map(|seg| seg.ident)) } pub(crate) fn build_deref_target_impls( diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 4989bd718c9f..5191120ebdb0 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -1,5 +1,6 @@ use std::mem; +use rustc_ast::join_path_syms; use rustc_attr_data_structures::StabilityLevel; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet}; @@ -13,7 +14,6 @@ use crate::core::DocContext; use crate::fold::DocFolder; use crate::formats::Impl; use crate::formats::item_type::ItemType; -use crate::html::format::join_with_double_colon; use crate::html::markdown::short_markdown_summary; use crate::html::render::IndexItem; use crate::html::render::search_index::get_function_type_for_search; @@ -558,7 +558,7 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It clean::ItemKind::ImportItem(import) => import.source.did.unwrap_or(item_def_id), _ => item_def_id, }; - let path = join_with_double_colon(parent_path); + let path = join_path_syms(parent_path); let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { item_id.as_def_id() } else { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index bcb3e57c8442..b16485107a02 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -14,6 +14,7 @@ use std::slice; use itertools::{Either, Itertools}; use rustc_abi::ExternAbi; +use rustc_ast::join_path_syms; use rustc_attr_data_structures::{ConstStability, StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; @@ -25,7 +26,7 @@ use rustc_span::symbol::kw; use rustc_span::{Symbol, sym}; use tracing::{debug, trace}; -use super::url_parts_builder::{UrlPartsBuilder, estimate_item_path_byte_length}; +use super::url_parts_builder::UrlPartsBuilder; use crate::clean::types::ExternalLocation; use crate::clean::utils::find_nearest_parent_module; use crate::clean::{self, ExternalCrate, PrimitiveType}; @@ -369,18 +370,6 @@ pub(crate) enum HrefError { NotInExternalCache, } -// Panics if `syms` is empty. -pub(crate) fn join_with_double_colon(syms: &[Symbol]) -> String { - let mut s = String::with_capacity(estimate_item_path_byte_length(syms.len())); - // NOTE: using `Joined::joined` here causes a noticeable perf regression - s.push_str(syms[0].as_str()); - for sym in &syms[1..] { - s.push_str("::"); - s.push_str(sym.as_str()); - } - s -} - /// This function is to get the external macro path because they are not in the cache used in /// `href_with_root_path`. fn generate_macro_def_id_path( @@ -672,7 +661,7 @@ pub(crate) fn link_tooltip( write!(f, "{}", cx.tcx().item_name(id))?; } else if !fqp.is_empty() { write!(f, "{shortty} ")?; - fqp.iter().joined("::", f)?; + write!(f, "{}", join_path_syms(fqp))?; } Ok(()) }) @@ -703,7 +692,7 @@ fn resolved_path( write!( f, "{path}::{anchor}", - path = join_with_double_colon(&fqp[..fqp.len() - 1]), + path = join_path_syms(&fqp[..fqp.len() - 1]), anchor = print_anchor(did, *fqp.last().unwrap(), cx) ) } else { @@ -835,7 +824,7 @@ pub(crate) fn print_anchor(did: DefId, text: Symbol, cx: &Context<'_>) -> impl D write!( f, r#"
{text}"#, - path = join_with_double_colon(&fqp), + path = join_path_syms(fqp), text = EscapeBodyText(text.as_str()), ) } else { @@ -1095,7 +1084,7 @@ impl clean::QPathData { title=\"type {path}::{name}\">{name}", shortty = ItemType::AssocType, name = assoc.name, - path = join_with_double_colon(&path), + path = join_path_syms(path), ) } else { write!(f, "{}", assoc.name) diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 3b4dae841ee7..7b814701a732 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; use std::sync::mpsc::{Receiver, channel}; use askama::Template; +use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; use rustc_middle::ty::TyCtxt; @@ -27,7 +28,6 @@ use crate::formats::FormatRenderer; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; -use crate::html::format::join_with_double_colon; use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary}; use crate::html::render::write_shared::write_shared; use crate::html::url_parts_builder::UrlPartsBuilder; @@ -211,7 +211,7 @@ impl<'tcx> Context<'tcx> { title.push_str(" in "); } // No need to include the namespace for primitive types and keywords - title.push_str(&join_with_double_colon(&self.current)); + title.push_str(&join_path_syms(&self.current)); }; title.push_str(" - Rust"); let tyname = it.type_(); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 06de4944d97d..d8c37137bbc7 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -49,6 +49,7 @@ use std::{fs, str}; use askama::Template; use itertools::Either; +use rustc_ast::join_path_syms; use rustc_attr_data_structures::{ ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince, }; @@ -74,9 +75,9 @@ use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; use crate::html::format::{ - Ending, HrefError, PrintWithSpace, href, join_with_double_colon, print_abi_with_space, - print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause, - visibility_print_with_space, write_str, + Ending, HrefError, PrintWithSpace, href, print_abi_with_space, print_constness_with_space, + print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space, + write_str, }; use crate::html::markdown::{ HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine, @@ -2555,7 +2556,7 @@ fn collect_paths_for_type(first_ty: &clean::Type, cache: &Cache) -> Vec let fqp = cache.exact_paths.get(&did).or_else(get_extern); if let Some(path) = fqp { - out.push(join_with_double_colon(path)); + out.push(join_path_syms(path)); } }; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 667d39e9bc2f..5fbda4797cc9 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -4,6 +4,7 @@ use std::iter; use askama::Template; use rustc_abi::VariantIdx; +use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_hir as hir; use rustc_hir::def::CtorKind; @@ -30,8 +31,8 @@ use crate::formats::Impl; use crate::formats::item_type::ItemType; use crate::html::escape::{Escape, EscapeBodyTextWithWbr}; use crate::html::format::{ - Ending, PrintWithSpace, join_with_double_colon, print_abi_with_space, - print_constness_with_space, print_where_clause, visibility_print_with_space, + Ending, PrintWithSpace, print_abi_with_space, print_constness_with_space, print_where_clause, + visibility_print_with_space, }; use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine}; use crate::html::render::{document_full, document_item_info}; @@ -1424,7 +1425,7 @@ fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> iter::repeat_n("..", cx.current.len()).chain(iter::once("type.impl")).collect(); js_src_path.extend(target_fqp[..target_fqp.len() - 1].iter().copied()); js_src_path.push_fmt(format_args!("{target_type}.{}.js", target_fqp.last().unwrap())); - let self_path = fmt::from_fn(|f| self_fqp.iter().joined("::", f)); + let self_path = join_path_syms(self_fqp); write!( w, "", @@ -2256,7 +2257,7 @@ pub(crate) fn compare_names(left: &str, right: &str) -> Ordering { } pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String { - let mut s = join_with_double_colon(&cx.current); + let mut s = join_path_syms(&cx.current); s.push_str("::"); s.push_str(item.name.unwrap().as_str()); s diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index aff8684ee3a0..80a59fa218c6 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -4,6 +4,7 @@ use std::collections::hash_map::Entry; use std::collections::{BTreeMap, VecDeque}; use encode::{bitmap_to_string, write_vlqhex_to_string}; +use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; @@ -17,7 +18,6 @@ use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate}; use crate::clean::{self, utils}; use crate::formats::cache::{Cache, OrphanImplItem}; use crate::formats::item_type::ItemType; -use crate::html::format::join_with_double_colon; use crate::html::markdown::short_markdown_summary; use crate::html::render::ordered_json::OrderedJson; use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId}; @@ -78,7 +78,7 @@ pub(crate) fn build_index( ty: item.type_(), defid: item.item_id.as_def_id(), name: item.name.unwrap(), - path: join_with_double_colon(&fqp[..fqp.len() - 1]), + path: join_path_syms(&fqp[..fqp.len() - 1]), desc, parent: Some(parent), parent_idx: None, @@ -416,7 +416,7 @@ pub(crate) fn build_index( if fqp.len() < 2 { return None; } - join_with_double_colon(&fqp[..fqp.len() - 1]) + join_path_syms(&fqp[..fqp.len() - 1]) }; if path == item.path { return None; @@ -427,10 +427,10 @@ pub(crate) fn build_index( let i = >::try_into(parent_idx).unwrap(); item.path = { let p = &crate_paths[i].1; - join_with_double_colon(&p[..p.len() - 1]) + join_path_syms(&p[..p.len() - 1]) }; item.exact_path = - crate_paths[i].2.as_ref().map(|xp| join_with_double_colon(&xp[..xp.len() - 1])); + crate_paths[i].2.as_ref().map(|xp| join_path_syms(&xp[..xp.len() - 1])); } // Omit the parent path if it is same to that of the prior item. @@ -549,11 +549,11 @@ pub(crate) fn build_index( }); continue; } - let full_path = join_with_double_colon(&path[..path.len() - 1]); + let full_path = join_path_syms(&path[..path.len() - 1]); let full_exact_path = exact .as_ref() .filter(|exact| exact.last() == path.last() && exact.len() >= 2) - .map(|exact| join_with_double_colon(&exact[..exact.len() - 1])); + .map(|exact| join_path_syms(&exact[..exact.len() - 1])); let exact_path = extra_paths.len() + self.items.len(); let exact_path = full_exact_path.as_ref().map(|full_exact_path| match extra_paths .entry(full_exact_path.clone()) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 0078671fcc5a..1f691392b171 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -26,6 +26,7 @@ use std::{fmt, fs}; use indexmap::IndexMap; use regex::Regex; +use rustc_ast::join_path_syms; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_middle::ty::TyCtxt; @@ -43,7 +44,6 @@ use crate::docfs::PathError; use crate::error::Error; use crate::formats::Impl; use crate::formats::item_type::ItemType; -use crate::html::format::join_with_double_colon; use crate::html::layout; use crate::html::render::ordered_json::{EscapedJson, OrderedJson}; use crate::html::render::search_index::{SerializedSearchIndex, build_index}; @@ -608,7 +608,7 @@ impl TypeAliasPart { for &(type_alias_fqp, type_alias_item) in type_aliases { cx.id_map.borrow_mut().clear(); cx.deref_id_map.borrow_mut().clear(); - let type_alias_fqp = join_with_double_colon(&type_alias_fqp); + let type_alias_fqp = join_path_syms(type_alias_fqp); if let Some(ret) = &mut ret { ret.aliases.push(type_alias_fqp); } else { diff --git a/src/librustdoc/html/url_parts_builder.rs b/src/librustdoc/html/url_parts_builder.rs index 9a5338274415..705fa498e8d3 100644 --- a/src/librustdoc/html/url_parts_builder.rs +++ b/src/librustdoc/html/url_parts_builder.rs @@ -117,7 +117,7 @@ impl UrlPartsBuilder { /// This is just a guess at the average length of a URL part, /// used for [`String::with_capacity`] calls in the [`FromIterator`] -/// and [`Extend`] impls, and for [estimating item path lengths]. +/// and [`Extend`] impls. /// /// The value `8` was chosen for two main reasons: /// @@ -125,18 +125,8 @@ impl UrlPartsBuilder { /// * jemalloc's size classes are all multiples of eight, /// which means that the amount of memory it allocates will often match /// the amount requested, avoiding wasted bytes. -/// -/// [estimating item path lengths]: estimate_item_path_byte_length const AVG_PART_LENGTH: usize = 8; -/// Estimate the number of bytes in an item's path, based on how many segments it has. -/// -/// **Note:** This is only to be used with, e.g., [`String::with_capacity()`]; -/// the return value is just a rough estimate. -pub(crate) const fn estimate_item_path_byte_length(segment_count: usize) -> usize { - AVG_PART_LENGTH * segment_count -} - impl<'a> FromIterator<&'a str> for UrlPartsBuilder { fn from_iter>(iter: T) -> Self { let iter = iter.into_iter(); diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 045363058d19..d664eaaac704 100644 --- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -4,6 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; use clippy_utils::{is_path_diagnostic_item, sugg}; +use rustc_ast::join_path_idents; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{self as hir, Expr, ExprKind, GenericArg, QPath, TyKind}; @@ -47,7 +48,7 @@ fn build_full_type(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, app: &mut Applica && let QPath::Resolved(None, ty_path) = &ty_qpath && let Res::Def(_, ty_did) = ty_path.res { - let mut ty_str = itertools::join(ty_path.segments.iter().map(|s| s.ident), "::"); + let mut ty_str = join_path_idents(ty_path.segments.iter().map(|seg| seg.ident)); let mut first = true; let mut append = |arg: &str| { write!(&mut ty_str, "{}{arg}", [", ", "<"][usize::from(first)]).unwrap(); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index ad8c816e204f..ff1ee663f9bf 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -89,6 +89,7 @@ use std::sync::{Mutex, MutexGuard, OnceLock}; use itertools::Itertools; use rustc_abi::Integer; +use rustc_ast::join_path_syms; use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashMap; @@ -3245,8 +3246,8 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::c ::d::sym refers to // e::f::sym:: :: // result should be super::super::super::super::e::f - if let DefPathData::TypeNs(s) = l { - path.push(s.to_string()); + if let DefPathData::TypeNs(sym) = l { + path.push(sym); } if let DefPathData::TypeNs(_) = r { go_up_by += 1; @@ -3256,7 +3257,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::sym:: :: refers to // c::d::e ::f::sym // when looking at `f` - Left(DefPathData::TypeNs(sym)) => path.push(sym.to_string()), + Left(DefPathData::TypeNs(sym)) => path.push(sym), // consider: // a::b::c ::d::sym refers to // e::f::sym:: :: @@ -3268,17 +3269,17 @@ 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 - once(String::from("crate")) - .chain(to.data.iter().filter_map(|el| { + join_path_syms( + once(kw::Crate).chain(to.data.iter().filter_map(|el| { if let DefPathData::TypeNs(sym) = el.data { - Some(sym.to_string()) + Some(sym) } else { None } })) - .join("::") + ) } else { - repeat_n(String::from("super"), go_up_by).chain(path).join("::") + join_path_syms(repeat_n(kw::Super, go_up_by).chain(path)) } } diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr index 915b54b3fc23..2571c8fa9896 100644 --- a/tests/ui/asm/naked-invalid-attr.stderr +++ b/tests/ui/asm/naked-invalid-attr.stderr @@ -8,7 +8,7 @@ error[E0736]: attribute incompatible with `#[unsafe(naked)]` --> $DIR/naked-invalid-attr.rs:56:3 | LL | #[::a] - | ^^^ the `{{root}}::a` attribute is incompatible with `#[unsafe(naked)]` + | ^^^ the `::a` attribute is incompatible with `#[unsafe(naked)]` ... LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here From 6414352bff4f92db7efb177c4b3263060379ca60 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 20 Jun 2025 16:59:02 +1000 Subject: [PATCH 243/363] Use `join_path_syms` in one more place. This one is a bit marginal, because the segments are a mix of symbols and strings. --- compiler/rustc_hir/src/definitions.rs | 20 +++++++------------ compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- .../src/error_reporting/infer/mod.rs | 11 +++++----- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index f93b9e5af534..8aec11a2e81e 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -181,32 +181,26 @@ pub struct DisambiguatedDefPathData { } impl DisambiguatedDefPathData { - pub fn fmt_maybe_verbose(&self, writer: &mut impl Write, verbose: bool) -> fmt::Result { + pub fn as_sym(&self, verbose: bool) -> Symbol { match self.data.name() { DefPathDataName::Named(name) => { if verbose && self.disambiguator != 0 { - write!(writer, "{}#{}", name, self.disambiguator) + Symbol::intern(&format!("{}#{}", name, self.disambiguator)) } else { - writer.write_str(name.as_str()) + name } } DefPathDataName::Anon { namespace } => { if let DefPathData::AnonAssocTy(method) = self.data { - write!(writer, "{}::{{{}#{}}}", method, namespace, self.disambiguator) + Symbol::intern(&format!("{}::{{{}#{}}}", method, namespace, self.disambiguator)) } else { - write!(writer, "{{{}#{}}}", namespace, self.disambiguator) + Symbol::intern(&format!("{{{}#{}}}", namespace, self.disambiguator)) } } } } } -impl fmt::Display for DisambiguatedDefPathData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.fmt_maybe_verbose(f, true) - } -} - #[derive(Clone, Debug, Encodable, Decodable)] pub struct DefPath { /// The path leading from the crate root to the item. @@ -250,7 +244,7 @@ impl DefPath { let mut s = String::with_capacity(self.data.len() * 16); for component in &self.data { - write!(s, "::{component}").unwrap(); + write!(s, "::{}", component.as_sym(true)).unwrap(); } s @@ -266,7 +260,7 @@ impl DefPath { for component in &self.data { s.extend(opt_delimiter); opt_delimiter = Some('-'); - write!(s, "{component}").unwrap(); + write!(s, "{}", component.as_sym(true)).unwrap(); } s diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8f0f9b21dc16..b7088bd003af 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2430,7 +2430,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { } let verbose = self.should_print_verbose(); - disambiguated_data.fmt_maybe_verbose(self, verbose)?; + write!(self, "{}", disambiguated_data.as_sym(verbose))?; self.empty_path = false; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index bc464b099e29..b9acadc406e9 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -51,6 +51,7 @@ use std::path::PathBuf; use std::{cmp, fmt, iter}; use rustc_abi::ExternAbi; +use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize, @@ -73,7 +74,7 @@ use rustc_middle::ty::{ TypeVisitableExt, }; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, Symbol, sym}; use tracing::{debug, instrument}; use crate::error_reporting::TypeErrCtxt; @@ -225,7 +226,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { struct AbsolutePathPrinter<'tcx> { tcx: TyCtxt<'tcx>, - segments: Vec, + segments: Vec, } impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { @@ -253,7 +254,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { - self.segments = vec![self.tcx.crate_name(cnum).to_string()]; + self.segments = vec![self.tcx.crate_name(cnum)]; Ok(()) } fn path_qualified( @@ -279,7 +280,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { disambiguated_data: &DisambiguatedDefPathData, ) -> Result<(), PrintError> { print_prefix(self)?; - self.segments.push(disambiguated_data.to_string()); + self.segments.push(disambiguated_data.as_sym(true)); Ok(()) } fn path_generic_args( @@ -314,7 +315,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // known" by the same name, we use the "absolute path" which uses the original // crate name instead. let (expected, found) = if expected_str == found_str { - (expected_abs.join("::"), found_abs.join("::")) + (join_path_syms(&expected_abs), join_path_syms(&found_abs)) } else { (expected_str.clone(), found_str.clone()) }; From 5d611e55489b70482295419888844c29af11b2ee Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Jul 2025 23:17:01 +0300 Subject: [PATCH 244/363] resolve: Move `self_binding` to `ModuleData` --- compiler/rustc_resolve/src/ident.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 39 +++++++++++------------------ 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 84d66c15f00c..6ac3034d1d97 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -841,7 +841,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if ns == TypeNS { if ident.name == kw::Crate || ident.name == kw::DollarCrate { let module = self.resolve_crate_root(ident); - return Ok(self.module_self_bindings[&module]); + return Ok(module.self_binding.unwrap()); } else if ident.name == kw::Super || ident.name == kw::SelfLower { // FIXME: Implement these with renaming requirements so that e.g. // `use super;` doesn't work, but `use super as name;` does. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b0b29bc2eae2..73a6d4c0c3ec 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -585,6 +585,10 @@ struct ModuleData<'ra> { span: Span, expansion: ExpnId, + + /// Binding for implicitly declared names that come with a module, + /// like `self` (not yet used), or `crate`/`$crate` (for root modules). + self_binding: Option>, } /// All modules are unique and allocated on a same arena, @@ -613,6 +617,7 @@ impl<'ra> ModuleData<'ra> { expansion: ExpnId, span: Span, no_implicit_prelude: bool, + self_binding: Option>, ) -> Self { let is_foreign = match kind { ModuleKind::Def(_, def_id, _) => !def_id.is_local(), @@ -630,6 +635,7 @@ impl<'ra> ModuleData<'ra> { traits: RefCell::new(None), span, expansion, + self_binding, } } } @@ -1101,10 +1107,6 @@ pub struct Resolver<'ra, 'tcx> { builtin_types_bindings: FxHashMap>, builtin_attrs_bindings: FxHashMap>, registered_tool_bindings: FxHashMap>, - /// Binding for implicitly declared names that come with a module, - /// like `self` (not yet used), or `crate`/`$crate` (for root modules). - module_self_bindings: FxHashMap, NameBinding<'ra>>, - used_extern_options: FxHashSet, macro_names: FxHashSet, builtin_macros: FxHashMap, @@ -1264,24 +1266,27 @@ impl<'ra> ResolverArenas<'ra> { span: Span, no_implicit_prelude: bool, module_map: &mut FxIndexMap>, - module_self_bindings: &mut FxHashMap, NameBinding<'ra>>, ) -> Module<'ra> { + let (def_id, self_binding) = match kind { + ModuleKind::Def(def_kind, def_id, _) => ( + Some(def_id), + Some(self.new_pub_res_binding(Res::Def(def_kind, def_id), span, LocalExpnId::ROOT)), + ), + ModuleKind::Block => (None, None), + }; let module = Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new( parent, kind, expn_id, span, no_implicit_prelude, + self_binding, )))); - let def_id = module.opt_def_id(); if def_id.is_none_or(|def_id| def_id.is_local()) { self.local_modules.borrow_mut().push(module); } if let Some(def_id) = def_id { module_map.insert(def_id, module); - let res = module.res().unwrap(); - let binding = self.new_pub_res_binding(res, module.span, LocalExpnId::ROOT); - module_self_bindings.insert(module, binding); } module } @@ -1424,7 +1429,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Resolver<'ra, 'tcx> { let root_def_id = CRATE_DEF_ID.to_def_id(); let mut module_map = FxIndexMap::default(); - let mut module_self_bindings = FxHashMap::default(); let graph_root = arenas.new_module( None, ModuleKind::Def(DefKind::Mod, root_def_id, None), @@ -1432,7 +1436,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { crate_span, attr::contains_name(attrs, sym::no_implicit_prelude), &mut module_map, - &mut module_self_bindings, ); let empty_module = arenas.new_module( None, @@ -1441,7 +1444,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { DUMMY_SP, true, &mut Default::default(), - &mut Default::default(), ); let mut node_id_to_def_id = NodeMap::default(); @@ -1544,8 +1546,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (*ident, binding) }) .collect(), - module_self_bindings, - used_extern_options: Default::default(), macro_names: FxHashSet::default(), builtin_macros: Default::default(), @@ -1617,16 +1617,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { no_implicit_prelude: bool, ) -> Module<'ra> { let module_map = &mut self.module_map; - let module_self_bindings = &mut self.module_self_bindings; - self.arenas.new_module( - parent, - kind, - expn_id, - span, - no_implicit_prelude, - module_map, - module_self_bindings, - ) + self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude, module_map) } fn new_local_macro(&mut self, def_id: LocalDefId, macro_data: MacroData) -> &'ra MacroData { From 8d7193973f5beede7893969197b1661b43f254be Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Jul 2025 23:47:19 +0300 Subject: [PATCH 245/363] resolve: Use `module_map` and `get_module` less --- compiler/rustc_resolve/src/diagnostics.rs | 38 ++++++++++--------- .../src/effective_visibilities.rs | 3 +- .../rustc_resolve/src/late/diagnostics.rs | 20 +++++----- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 11e4a729ae23..d263ab25045e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2771,7 +2771,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } /// Finds a cfg-ed out item inside `module` with the matching name. - pub(crate) fn find_cfg_stripped(&self, err: &mut Diag<'_>, segment: &Symbol, module: DefId) { + pub(crate) fn find_cfg_stripped( + &mut self, + err: &mut Diag<'_>, + segment: &Symbol, + module: DefId, + ) { let local_items; let symbols = if module.is_local() { local_items = self @@ -2797,7 +2802,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn comes_from_same_module_for_glob( - r: &Resolver<'_, '_>, + r: &mut Resolver<'_, '_>, parent_module: DefId, module: DefId, visited: &mut FxHashMap, @@ -2809,24 +2814,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return cached; } visited.insert(parent_module, false); - let res = r.module_map.get(&parent_module).is_some_and(|m| { - for importer in m.glob_importers.borrow().iter() { - if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id() + let m = r.expect_module(parent_module); + let mut res = false; + for importer in m.glob_importers.borrow().iter() { + if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id() { + if next_parent_module == module + || comes_from_same_module_for_glob( + r, + next_parent_module, + module, + visited, + ) { - if next_parent_module == module - || comes_from_same_module_for_glob( - r, - next_parent_module, - module, - visited, - ) - { - return true; - } + res = true; + break; } } - false - }); + } visited.insert(parent_module, res); res } diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 5de80de3f8d3..741671b6d2f5 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -113,8 +113,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { /// Update effective visibilities of bindings in the given module, /// including their whole reexport chains. fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) { - assert!(self.r.module_map.contains_key(&module_id.to_def_id())); - let module = self.r.get_module(module_id.to_def_id()).unwrap(); + let module = self.r.expect_module(module_id.to_def_id()); let resolutions = self.r.resolutions(module); for (_, name_resolution) in resolutions.borrow().iter() { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a4601cb44ebf..70a7dbf1b047 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -926,7 +926,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { continue; }; if let Res::Def(DefKind::Mod, module) = res.expect_full_res() - && let Some(module) = self.r.get_module(module) + && let module = self.r.expect_module(module) && let item = path[idx + 1].ident && let Some(did) = find_doc_alias_name(self.r, module, item.name) { @@ -2531,16 +2531,14 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // FIXME: this is not totally accurate, but mostly works suggestion.candidate != following_seg.ident.name } - Res::Def(DefKind::Mod, def_id) => self.r.get_module(def_id).map_or_else( - || false, - |module| { - self.r - .resolutions(module) - .borrow() - .iter() - .any(|(key, _)| key.ident.name == following_seg.ident.name) - }, - ), + Res::Def(DefKind::Mod, def_id) => { + let module = self.r.expect_module(def_id); + self.r + .resolutions(module) + .borrow() + .iter() + .any(|(key, _)| key.ident.name == following_seg.ident.name) + } _ => true, }); } From 8b8889df2550fac573cbaddb1db1419080118d63 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 7 Jul 2025 00:15:13 +0300 Subject: [PATCH 246/363] resolve: Split `module_map` into two maps for local and extern modules --- .../rustc_resolve/src/build_reduced_graph.rs | 57 ++++++++++--------- compiler/rustc_resolve/src/diagnostics.rs | 11 +++- compiler/rustc_resolve/src/lib.rs | 42 +++++++++----- 3 files changed, 69 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 5a1be618ceea..676acd78ea7e 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -102,33 +102,36 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// or trait), then this function returns that module's resolver representation, otherwise it /// returns `None`. pub(crate) fn get_module(&mut self, def_id: DefId) -> Option> { - if let module @ Some(..) = self.module_map.get(&def_id) { - return module.copied(); - } + match def_id.as_local() { + Some(local_def_id) => self.local_module_map.get(&local_def_id).copied(), + None => { + if let module @ Some(..) = self.extern_module_map.borrow().get(&def_id) { + return module.copied(); + } - if !def_id.is_local() { - // Query `def_kind` is not used because query system overhead is too expensive here. - let def_kind = self.cstore().def_kind_untracked(def_id); - if def_kind.is_module_like() { - let parent = self - .tcx - .opt_parent(def_id) - .map(|parent_id| self.get_nearest_non_block_module(parent_id)); - // Query `expn_that_defined` is not used because - // hashing spans in its result is expensive. - let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess); - return Some(self.new_module( - parent, - ModuleKind::Def(def_kind, def_id, Some(self.tcx.item_name(def_id))), - expn_id, - self.def_span(def_id), - // FIXME: Account for `#[no_implicit_prelude]` attributes. - parent.is_some_and(|module| module.no_implicit_prelude), - )); + // Query `def_kind` is not used because query system overhead is too expensive here. + let def_kind = self.cstore().def_kind_untracked(def_id); + if def_kind.is_module_like() { + let parent = self + .tcx + .opt_parent(def_id) + .map(|parent_id| self.get_nearest_non_block_module(parent_id)); + // Query `expn_that_defined` is not used because + // hashing spans in its result is expensive. + let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess); + return Some(self.new_extern_module( + parent, + ModuleKind::Def(def_kind, def_id, Some(self.tcx.item_name(def_id))), + expn_id, + self.def_span(def_id), + // FIXME: Account for `#[no_implicit_prelude]` attributes. + parent.is_some_and(|module| module.no_implicit_prelude), + )); + } + + None } } - - None } pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'ra> { @@ -758,7 +761,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { self.r.mods_with_parse_errors.insert(def_id); } - self.parent_scope.module = self.r.new_module( + self.parent_scope.module = self.r.new_local_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), @@ -790,7 +793,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => { self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); - self.parent_scope.module = self.r.new_module( + self.parent_scope.module = self.r.new_local_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), @@ -986,7 +989,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; if self.block_needs_anonymous_module(block) { - let module = self.r.new_module( + let module = self.r.new_local_module( Some(parent), ModuleKind::Block, expansion.to_expn_id(), diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d263ab25045e..9e9ab7356b84 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2159,7 +2159,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .keys() .map(|ident| ident.name) .chain( - self.module_map + self.local_module_map + .iter() + .filter(|(_, module)| { + current_module.is_ancestor_of(**module) && current_module != **module + }) + .flat_map(|(_, module)| module.kind.name()), + ) + .chain( + self.extern_module_map + .borrow() .iter() .filter(|(_, module)| { current_module.is_ancestor_of(**module) && current_module != **module diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 73a6d4c0c3ec..98786c1e6f99 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1081,7 +1081,10 @@ pub struct Resolver<'ra, 'tcx> { /// some AST passes can generate identifiers that only resolve to local or /// lang items. empty_module: Module<'ra>, - module_map: FxIndexMap>, + /// Eagerly populated map of all local non-block modules. + local_module_map: FxIndexMap>, + /// Lazily populated cache of modules loaded from external crates. + extern_module_map: RefCell>>, binding_parent_modules: FxHashMap, Module<'ra>>, underscore_disambiguator: u32, @@ -1112,8 +1115,9 @@ pub struct Resolver<'ra, 'tcx> { builtin_macros: FxHashMap, registered_tools: &'tcx RegisteredTools, macro_use_prelude: FxIndexMap>, + /// Eagerly populated map of all local macro definitions. local_macro_map: FxHashMap, - /// Lazily populated cache of macros loaded from external crates. + /// Lazily populated cache of macro definitions loaded from external crates. extern_macro_map: RefCell>, dummy_ext_bang: Arc, dummy_ext_derive: Arc, @@ -1265,7 +1269,6 @@ impl<'ra> ResolverArenas<'ra> { expn_id: ExpnId, span: Span, no_implicit_prelude: bool, - module_map: &mut FxIndexMap>, ) -> Module<'ra> { let (def_id, self_binding) = match kind { ModuleKind::Def(def_kind, def_id, _) => ( @@ -1285,9 +1288,6 @@ impl<'ra> ResolverArenas<'ra> { if def_id.is_none_or(|def_id| def_id.is_local()) { self.local_modules.borrow_mut().push(module); } - if let Some(def_id) = def_id { - module_map.insert(def_id, module); - } module } fn local_modules(&'ra self) -> std::cell::Ref<'ra, Vec>> { @@ -1428,22 +1428,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { arenas: &'ra ResolverArenas<'ra>, ) -> Resolver<'ra, 'tcx> { let root_def_id = CRATE_DEF_ID.to_def_id(); - let mut module_map = FxIndexMap::default(); + let mut local_module_map = FxIndexMap::default(); let graph_root = arenas.new_module( None, ModuleKind::Def(DefKind::Mod, root_def_id, None), ExpnId::root(), crate_span, attr::contains_name(attrs, sym::no_implicit_prelude), - &mut module_map, ); + local_module_map.insert(CRATE_DEF_ID, graph_root); let empty_module = arenas.new_module( None, ModuleKind::Def(DefKind::Mod, root_def_id, None), ExpnId::root(), DUMMY_SP, true, - &mut Default::default(), ); let mut node_id_to_def_id = NodeMap::default(); @@ -1504,7 +1503,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { trait_map: NodeMap::default(), underscore_disambiguator: 0, empty_module, - module_map, + local_module_map, + extern_module_map: Default::default(), block_map: Default::default(), binding_parent_modules: FxHashMap::default(), ast_transform_scopes: FxHashMap::default(), @@ -1608,7 +1608,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { resolver } - fn new_module( + fn new_local_module( &mut self, parent: Option>, kind: ModuleKind, @@ -1616,8 +1616,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span: Span, no_implicit_prelude: bool, ) -> Module<'ra> { - let module_map = &mut self.module_map; - self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude, module_map) + let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude); + if let Some(def_id) = module.opt_def_id() { + self.local_module_map.insert(def_id.expect_local(), module); + } + module + } + + fn new_extern_module( + &mut self, + parent: Option>, + kind: ModuleKind, + expn_id: ExpnId, + span: Span, + no_implicit_prelude: bool, + ) -> Module<'ra> { + let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude); + self.extern_module_map.borrow_mut().insert(module.def_id(), module); + module } fn new_local_macro(&mut self, def_id: LocalDefId, macro_data: MacroData) -> &'ra MacroData { From 6849f816b1c908b446698a08b5cd27d258bad073 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 7 Jul 2025 00:39:07 +0300 Subject: [PATCH 247/363] resolve: Change `&mut Resolver` to `&Resolver` when possible --- compiler/rustc_expand/src/base.rs | 2 +- .../rustc_resolve/src/build_reduced_graph.rs | 14 +++++------ compiler/rustc_resolve/src/diagnostics.rs | 15 ++++-------- .../src/effective_visibilities.rs | 6 ++--- compiler/rustc_resolve/src/ident.rs | 4 ++-- compiler/rustc_resolve/src/imports.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- .../rustc_resolve/src/late/diagnostics.rs | 24 ++++++++----------- compiler/rustc_resolve/src/lib.rs | 6 ++--- compiler/rustc_resolve/src/macros.rs | 4 ++-- 10 files changed, 35 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index ce3006c2604a..1928cfd90482 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1062,7 +1062,7 @@ pub trait ResolverExpand { fn next_node_id(&mut self) -> NodeId; fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId; - fn resolve_dollar_crates(&mut self); + fn resolve_dollar_crates(&self); fn visit_ast_fragment_with_placeholders( &mut self, expn_id: LocalExpnId, diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 676acd78ea7e..e56aabfd4144 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -85,7 +85,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`, /// but they cannot use def-site hygiene, so the assumption holds /// (). - pub(crate) fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'ra> { + pub(crate) fn get_nearest_non_block_module(&self, mut def_id: DefId) -> Module<'ra> { loop { match self.get_module(def_id) { Some(module) => return module, @@ -94,14 +94,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - pub(crate) fn expect_module(&mut self, def_id: DefId) -> Module<'ra> { + pub(crate) fn expect_module(&self, def_id: DefId) -> Module<'ra> { self.get_module(def_id).expect("argument `DefId` is not a module") } /// If `def_id` refers to a module (in resolver's sense, i.e. a module item, crate root, enum, /// or trait), then this function returns that module's resolver representation, otherwise it /// returns `None`. - pub(crate) fn get_module(&mut self, def_id: DefId) -> Option> { + pub(crate) fn get_module(&self, def_id: DefId) -> Option> { match def_id.as_local() { Some(local_def_id) => self.local_module_map.get(&local_def_id).copied(), None => { @@ -134,7 +134,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'ra> { + pub(crate) fn expn_def_scope(&self, expn_id: ExpnId) -> Module<'ra> { match expn_id.expn_data().macro_def_id { Some(def_id) => self.macro_def_scope(def_id), None => expn_id @@ -144,7 +144,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - pub(crate) fn macro_def_scope(&mut self, def_id: DefId) -> Module<'ra> { + pub(crate) fn macro_def_scope(&self, def_id: DefId) -> Module<'ra> { if let Some(id) = def_id.as_local() { self.local_macro_def_scopes[&id] } else { @@ -406,7 +406,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.field_visibility_spans.insert(def_id, field_vis); } - fn block_needs_anonymous_module(&mut self, block: &Block) -> bool { + fn block_needs_anonymous_module(&self, block: &Block) -> bool { // If any statements are items, we need to create an anonymous module block .stmts @@ -1121,7 +1121,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } /// Returns `true` if this attribute list contains `macro_use`. - fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { + fn contains_macro_use(&self, attrs: &[ast::Attribute]) -> bool { for attr in attrs { if attr.has_name(sym::macro_escape) { let inner_attribute = matches!(attr.style, ast::AttrStyle::Inner); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9e9ab7356b84..aa12a842e6eb 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2150,7 +2150,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn find_similarly_named_module_or_crate( - &mut self, + &self, ident: Symbol, current_module: Module<'ra>, ) -> Option { @@ -2444,7 +2444,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn undeclared_module_suggest_declare( - &mut self, + &self, ident: Ident, path: std::path::PathBuf, ) -> Option<(Vec<(Span, String)>, String, Applicability)> { @@ -2459,7 +2459,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { )) } - fn undeclared_module_exists(&mut self, ident: Ident) -> Option { + fn undeclared_module_exists(&self, ident: Ident) -> Option { let map = self.tcx.sess.source_map(); let src = map.span_to_filename(ident.span).into_local_path()?; @@ -2780,12 +2780,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } /// Finds a cfg-ed out item inside `module` with the matching name. - pub(crate) fn find_cfg_stripped( - &mut self, - err: &mut Diag<'_>, - segment: &Symbol, - module: DefId, - ) { + pub(crate) fn find_cfg_stripped(&self, err: &mut Diag<'_>, segment: &Symbol, module: DefId) { let local_items; let symbols = if module.is_local() { local_items = self @@ -2811,7 +2806,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn comes_from_same_module_for_glob( - r: &mut Resolver<'_, '_>, + r: &Resolver<'_, '_>, parent_module: DefId, module: DefId, visited: &mut FxHashMap, diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 741671b6d2f5..34d1e9552fd7 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -38,11 +38,11 @@ pub(crate) struct EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { } impl Resolver<'_, '_> { - fn nearest_normal_mod(&mut self, def_id: LocalDefId) -> LocalDefId { + fn nearest_normal_mod(&self, def_id: LocalDefId) -> LocalDefId { self.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local() } - fn private_vis_import(&mut self, binding: NameBinding<'_>) -> Visibility { + fn private_vis_import(&self, binding: NameBinding<'_>) -> Visibility { let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() }; Visibility::Restricted( import @@ -52,7 +52,7 @@ impl Resolver<'_, '_> { ) } - fn private_vis_def(&mut self, def_id: LocalDefId) -> Visibility { + fn private_vis_def(&self, def_id: LocalDefId) -> Visibility { // For mod items `nearest_normal_mod` returns its argument, but we actually need its parent. let normal_mod_id = self.nearest_normal_mod(def_id); if normal_mod_id == def_id { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 6ac3034d1d97..34941398a2bb 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -219,7 +219,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn hygienic_lexical_parent( - &mut self, + &self, module: Module<'ra>, ctxt: &mut SyntaxContext, derive_fallback_lint_id: Option, @@ -885,7 +885,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); } - let check_usable = |this: &mut Self, binding: NameBinding<'ra>| { + let check_usable = |this: &Self, binding: NameBinding<'ra>| { let usable = this.is_accessible_from(binding.vis, parent_scope.module); if usable { Ok(binding) } else { Err((Determined, Weak::No)) } }; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 9a031ee03e0a..4b20d50c427e 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -456,7 +456,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { f: F, ) -> T where - F: FnOnce(&mut Resolver<'ra, 'tcx>, &mut NameResolution<'ra>) -> T, + F: FnOnce(&Resolver<'ra, 'tcx>, &mut NameResolution<'ra>) -> T, { // 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. diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3ef98100d094..753b9365cd87 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2491,7 +2491,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved /// label and reports an error if the label is not found or is unreachable. - fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'ra>> { + fn resolve_label(&self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'ra>> { let mut suggestion = None; for i in (0..self.label_ribs.len()).rev() { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 70a7dbf1b047..ee462d907649 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -939,7 +939,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn suggest_trait_and_bounds( - &mut self, + &self, err: &mut Diag<'_>, source: PathSource<'_, '_, '_>, res: Option, @@ -1140,7 +1140,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { /// Emit special messages for unresolved `Self` and `self`. fn suggest_self_ty( - &mut self, + &self, err: &mut Diag<'_>, source: PathSource<'_, '_, '_>, path: &[Segment], @@ -1256,7 +1256,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn detect_missing_binding_available_from_pattern( - &mut self, + &self, err: &mut Diag<'_>, path: &[Segment], following_seg: Option<&Segment>, @@ -1302,11 +1302,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } - fn suggest_at_operator_in_slice_pat_with_range( - &mut self, - err: &mut Diag<'_>, - path: &[Segment], - ) { + fn suggest_at_operator_in_slice_pat_with_range(&self, err: &mut Diag<'_>, path: &[Segment]) { let Some(pat) = self.diag_metadata.current_pat else { return }; let (bound, side, range) = match &pat.kind { ast::PatKind::Range(Some(bound), None, range) => (bound, Side::Start, range), @@ -1367,7 +1363,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn explain_functions_in_pattern( - &mut self, + &self, err: &mut Diag<'_>, res: Option, source: PathSource<'_, '_, '_>, @@ -1379,7 +1375,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn suggest_changing_type_to_const_param( - &mut self, + &self, err: &mut Diag<'_>, res: Option, source: PathSource<'_, '_, '_>, @@ -1429,7 +1425,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn suggest_pattern_match_with_let( - &mut self, + &self, err: &mut Diag<'_>, source: PathSource<'_, '_, '_>, span: Span, @@ -1485,7 +1481,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } /// Given `where ::Baz: String`, suggest `where T: Bar`. - fn restrict_assoc_type_in_where_clause(&mut self, span: Span, err: &mut Diag<'_>) -> bool { + fn restrict_assoc_type_in_where_clause(&self, span: Span, err: &mut Diag<'_>) -> bool { // Detect that we are actually in a `where` predicate. let (bounded_ty, bounds, where_span) = if let Some(ast::WherePredicate { kind: @@ -1633,7 +1629,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let ns = source.namespace(); let is_expected = &|res| source.is_expected(res); - let path_sep = |this: &mut Self, err: &mut Diag<'_>, expr: &Expr, kind: DefKind| { + let path_sep = |this: &Self, err: &mut Diag<'_>, expr: &Expr, kind: DefKind| { const MESSAGE: &str = "use the path separator to refer to an item"; let (lhs_span, rhs_span) = match &expr.kind { @@ -2587,7 +2583,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // try to give a suggestion for this pattern: `name = blah`, which is common in other languages // suggest `let name = blah` to introduce a new binding - fn let_binding_suggestion(&mut self, err: &mut Diag<'_>, ident_span: Span) -> bool { + fn let_binding_suggestion(&self, err: &mut Diag<'_>, ident_span: Span) -> bool { if ident_span.from_expansion() { return false; } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 98786c1e6f99..3202d31fdbca 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1624,7 +1624,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn new_extern_module( - &mut self, + &self, parent: Option>, kind: ModuleKind, expn_id: ExpnId, @@ -2021,7 +2021,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn resolve_crate_root(&mut self, ident: Ident) -> Module<'ra> { + fn resolve_crate_root(&self, ident: Ident) -> Module<'ra> { debug!("resolve_crate_root({:?})", ident); let mut ctxt = ident.span.ctxt(); let mark = if ident.name == kw::DollarCrate { @@ -2094,7 +2094,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module } - fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'ra>) -> Module<'ra> { + fn resolve_self(&self, ctxt: &mut SyntaxContext, module: Module<'ra>) -> Module<'ra> { let mut module = self.expect_module(module.nearest_parent_mod()); while module.span.ctxt().normalize_to_macros_2_0() != *ctxt { let parent = module.parent.unwrap_or_else(|| self.expn_def_scope(ctxt.remove_mark())); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index c17d74659db3..77ef7f56c094 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -170,7 +170,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { self.invocation_parents[&id].parent_def } - fn resolve_dollar_crates(&mut self) { + fn resolve_dollar_crates(&self) { hygiene::update_dollar_crate_names(|ctxt| { let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt)); match self.resolve_crate_root(ident).kind { @@ -835,7 +835,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) { - let check_consistency = |this: &mut Self, + let check_consistency = |this: &Self, path: &[Segment], span, kind: MacroKind, From fad8dec970f51a2d4c23593b059b1684bd85472a Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 16 Jul 2025 15:39:31 +0900 Subject: [PATCH 248/363] fix: false positive double_negations when it jumps macro boundary --- compiler/rustc_lint/src/builtin.rs | 2 ++ tests/ui/lint/lint-double-negations-macro.rs | 16 +++++++++++++++ .../lint/lint-double-negations-macro.stderr | 20 +++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 tests/ui/lint/lint-double-negations-macro.rs create mode 100644 tests/ui/lint/lint-double-negations-macro.stderr diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 255ff56f62b1..93df056c43b9 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1584,6 +1584,8 @@ impl EarlyLintPass for DoubleNegations { if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind && let ExprKind::Unary(UnOp::Neg, ref inner2) = inner.kind && !matches!(inner2.kind, ExprKind::Unary(UnOp::Neg, _)) + // Don't lint if this jumps macro expansion boundary (Issue #143980) + && expr.span.eq_ctxt(inner.span) { cx.emit_span_lint( DOUBLE_NEGATIONS, diff --git a/tests/ui/lint/lint-double-negations-macro.rs b/tests/ui/lint/lint-double-negations-macro.rs new file mode 100644 index 000000000000..a6583271d5a2 --- /dev/null +++ b/tests/ui/lint/lint-double-negations-macro.rs @@ -0,0 +1,16 @@ +//@ check-pass +macro_rules! neg { + ($e: expr) => { + -$e + }; +} +macro_rules! bad_macro { + ($e: expr) => { + --$e //~ WARN use of a double negation + }; +} + +fn main() { + neg!(-1); + bad_macro!(1); +} diff --git a/tests/ui/lint/lint-double-negations-macro.stderr b/tests/ui/lint/lint-double-negations-macro.stderr new file mode 100644 index 000000000000..d6ac9be48f30 --- /dev/null +++ b/tests/ui/lint/lint-double-negations-macro.stderr @@ -0,0 +1,20 @@ +warning: use of a double negation + --> $DIR/lint-double-negations-macro.rs:9:9 + | +LL | --$e + | ^^^^ +... +LL | bad_macro!(1); + | ------------- in this macro invocation + | + = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages + = note: use `-= 1` if you meant to decrement the value + = note: `#[warn(double_negations)]` on by default + = note: this warning originates in the macro `bad_macro` (in Nightly builds, run with -Z macro-backtrace for more info) +help: add parentheses for clarity + | +LL | -(-$e) + | + + + +warning: 1 warning emitted + From 8df6a1d26636bb60fd9f8d45e3da9c0c2529ee29 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 17 Jul 2025 05:42:53 +0200 Subject: [PATCH 249/363] some improvements to "Invariants of the type system" --- .../rustc-dev-guide/src/solve/invariants.md | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/solve/invariants.md b/src/doc/rustc-dev-guide/src/solve/invariants.md index 2f5a134f4dfe..8ec15f339e51 100644 --- a/src/doc/rustc-dev-guide/src/solve/invariants.md +++ b/src/doc/rustc-dev-guide/src/solve/invariants.md @@ -4,10 +4,10 @@ FIXME: This file talks about invariants of the type system as a whole, not only There are a lot of invariants - things the type system guarantees to be true at all times - which are desirable or expected from other languages and type systems. Unfortunately, quite -a few of them do not hold in Rust right now. This is either a fundamental to its design or -caused by bugs and something that may change in the future. +a few of them do not hold in Rust right now. This is either fundamental to its design or +caused by bugs, and something that may change in the future. -It is important to know about the things you can assume while working on - and with - the +It is important to know about the things you can assume while working on, and with, the type system, so here's an incomplete and unofficial list of invariants of the core type system: @@ -29,14 +29,15 @@ If you have a some type and equate it to itself after replacing any regions with inference variables in both the lhs and rhs, the now potentially structurally different types should still be equal to each other. -Needed to prevent goals from succeeding in HIR typeck and then failing in MIR borrowck. -If this invariant is broken MIR typeck ends up failing with an ICE. +This is needed to prevent goals from succeeding in HIR typeck and then failing in MIR borrowck. +If this invariant is broken, MIR typeck ends up failing with an ICE. ### Applying inference results from a goal does not change its result ❌ TODO: this invariant is formulated in a weird way and needs to be elaborated. Pretty much: I would like this check to only fail if there's a solver bug: -https://github.com/rust-lang/rust/blob/2ffeb4636b4ae376f716dc4378a7efb37632dc2d/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs#L391-L407 We should readd this check and see where it breaks :3 +. +We should readd this check and see where it breaks :3 If we prove some goal/equate types/whatever, apply the resulting inference constraints, and then redo the original action, the result should be the same. @@ -75,8 +76,8 @@ the issue is that the invariant is broken, not that we incorrectly rely on it. ### The type system is complete ❌ -The type system is not complete, it often adds unnecessary inference constraints, and errors -even though the goal could hold. +The type system is not complete. +It often adds unnecessary inference constraints, and errors even though the goal could hold. - method selection - opaque type inference @@ -95,11 +96,13 @@ It is interesting that we allow some incompleteness in the trait solver while st #### Normalization must not change results This invariant is relied on to allow the normalization of generic aliases. Breaking -it can easily result in unsoundness, e.g. [#57893](https://github.com/rust-lang/rust/issues/57893) +it can easily result in unsoundness, e.g. [#57893](https://github.com/rust-lang/rust/issues/57893). #### Goals may still overflow after instantiation -As they start to hit the recursion limit. We also have diverging aliases which are scuffed. It's unclear how these should be handled :3 +This happens they start to hit the recursion limit. +We also have diverging aliases which are scuffed. +It's unclear how these should be handled :3 ### Trait goals in empty environments are proven by a unique impl ✅ @@ -107,8 +110,7 @@ If a trait goal holds with an empty environment, there should be a unique `impl` either user-defined or builtin, which is used to prove that goal. This is necessary to select unique methods and associated items. -We do however break this invariant in few cases, some of which are due to bugs, -some by design: +We do however break this invariant in a few cases, some of which are due to bugs, some by design: - *marker traits* are allowed to overlap as they do not have associated items - *specialization* allows specializing impls to overlap with their parent - the builtin trait object trait implementation can overlap with a user-defined impl: @@ -117,11 +119,12 @@ some by design: #### The type system is complete during the implicit negative overlap check in coherence ✅ -For more on overlap checking: [coherence] +For more on overlap checking, see [Coherence chapter]. -During the implicit negative overlap check in coherence we must never return *error* for -goals which can be proven. This would allow for overlapping impls with potentially different -associated items, breaking a bunch of other invariants. +During the implicit negative overlap check in coherence, +we must never return *error* for goals which can be proven. +This would allow for overlapping impls with potentially different associated items, +breaking a bunch of other invariants. This invariant is currently broken in many different ways while actually something we rely on. We have to be careful as it is quite easy to break: @@ -147,8 +150,8 @@ This currently does not hold with the new solver: [trait-system-refactor-initiat Ideally we *should* not rely on ambiguity for things to compile. Not doing that will cause future improvements to be breaking changes. -Due to *incompleteness* this is not the case and improving inference can result in inference -changes, breaking existing projects. +Due to *incompleteness* this is not the case, +and improving inference can result in inference changes, breaking existing projects. ### Semantic equality implies structural equality ✅ @@ -166,4 +169,4 @@ Semantically different `'static` types need different `TypeId`s to avoid transmu for example `for<'a> fn(&'a str)` vs `fn(&'static str)` must have a different `TypeId`. -[coherence]: ../coherence.md +[coherence chapter]: ../coherence.md From 2faf5ed0cd20debd5eb6efe1795badccf6390c60 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Thu, 17 Jul 2025 04:14:28 +0000 Subject: [PATCH 250/363] Prepare for merging from rust-lang/rust This updates the rust-version file to fd2eb391d032181459773f3498c17b198513e0d0. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index e444613e6311..3f10132b684b 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -c96a69059ecc618b519da385a6ccd03155aa0237 +fd2eb391d032181459773f3498c17b198513e0d0 From dd364bd2261b37b6cd0d7f823b158a0c2903746b Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 17 Jul 2025 06:32:23 +0200 Subject: [PATCH 251/363] copy-paste convenience --- src/doc/rustc-dev-guide/src/external-repos.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index 68986a0bc688..ecc65b26ab7a 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -60,7 +60,10 @@ Currently, we are migrating Josh repositories to it. So far, it is used in: - rustc-dev-guide - stdarch -To use the tool, first install it with `cargo install --locked --git https://github.com/rust-lang/josh-sync`. +To install the tool: +``` +cargo install --locked --git https://github.com/rust-lang/josh-sync +``` Both pulls (synchronize changes from rust-lang/rust into the subtree) and pushes (synchronize changes from the subtree to rust-lang/rust) are performed from the subtree repository (so first From 49ae52e3ffeb3d98f19845eba5eb9fa1408fa432 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Thu, 17 Jul 2025 08:02:26 +0200 Subject: [PATCH 252/363] Fix encoding of `link_section` and `no_mangle` cross crate --- .../rustc_attr_data_structures/src/encode_cross_crate.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 3e2dc0a15b2f..c24b45e83f90 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -40,9 +40,9 @@ impl AttributeKind { Fundamental { .. } => Yes, Ignore { .. } => No, Inline(..) => No, - LinkName { .. } => Yes, + LinkName { .. } => Yes, // Needed for rustdoc LinkOrdinal { .. } => No, - LinkSection { .. } => No, + LinkSection { .. } => Yes, // Needed for rustdoc LoopMatch(..) => No, MacroTransparency(..) => Yes, Marker(..) => No, @@ -50,8 +50,8 @@ impl AttributeKind { MustUse { .. } => Yes, Naked(..) => No, NoImplicitPrelude(..) => No, - NoMangle(..) => No, - NonExhaustive(..) => Yes, + NoMangle(..) => Yes, // Needed for rustdoc + NonExhaustive(..) => Yes, // Needed for rustdoc OmitGdbPrettyPrinterSection => No, Optimize(..) => No, ParenSugar(..) => No, From 9f16db6611b0fb35f4a16dcbf326fb9aee3d87f3 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Thu, 17 Jul 2025 08:03:17 +0200 Subject: [PATCH 253/363] Regression test --- .../reexport/auxiliary/reexports-attrs.rs | 14 +++++++++++++ tests/rustdoc/reexport/reexport-attrs.rs | 20 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/rustdoc/reexport/auxiliary/reexports-attrs.rs create mode 100644 tests/rustdoc/reexport/reexport-attrs.rs diff --git a/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs b/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs new file mode 100644 index 000000000000..96fa8209cde8 --- /dev/null +++ b/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs @@ -0,0 +1,14 @@ +#[unsafe(no_mangle)] +pub fn f0() {} + +#[unsafe(link_section = ".here")] +pub fn f1() {} + +#[unsafe(export_name = "f2export")] +pub fn f2() {} + +#[repr(u8)] +pub enum T0 { V1 } + +#[non_exhaustive] +pub enum T1 {} diff --git a/tests/rustdoc/reexport/reexport-attrs.rs b/tests/rustdoc/reexport/reexport-attrs.rs new file mode 100644 index 000000000000..0ec645841f0b --- /dev/null +++ b/tests/rustdoc/reexport/reexport-attrs.rs @@ -0,0 +1,20 @@ +//@ aux-build: reexports-attrs.rs + +#![crate_name = "foo"] + +extern crate reexports_attrs; + +//@ has 'foo/fn.f0.html' '//pre[@class="rust item-decl"]' '#[no_mangle]' +pub use reexports_attrs::f0; + +//@ has 'foo/fn.f1.html' '//pre[@class="rust item-decl"]' '#[link_section = ".here"]' +pub use reexports_attrs::f1; + +//@ has 'foo/fn.f2.html' '//pre[@class="rust item-decl"]' '#[export_name = "f2export"]' +pub use reexports_attrs::f2; + +//@ has 'foo/enum.T0.html' '//pre[@class="rust item-decl"]' '#[repr(u8)]' +pub use reexports_attrs::T0; + +//@ has 'foo/enum.T1.html' '//pre[@class="rust item-decl"]' '#[non_exhaustive]' +pub use reexports_attrs::T1; From 5bb6b9db300870f436e8a45ffbe11efa41e44cad Mon Sep 17 00:00:00 2001 From: usamoi Date: Mon, 14 Jul 2025 16:41:42 +0800 Subject: [PATCH 254/363] remove no_gc_sections --- compiler/rustc_codegen_ssa/src/back/link.rs | 2 -- compiler/rustc_codegen_ssa/src/back/linker.rs | 33 ------------------- .../export-executable-symbols/rmake.rs | 1 + tests/ui/linking/export-executable-symbols.rs | 1 + 4 files changed, 2 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ae148287a601..5ce301c0eb98 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2543,8 +2543,6 @@ fn add_order_independent_options( let keep_metadata = crate_type == CrateType::Dylib || sess.opts.cg.profile_generate.enabled(); cmd.gc_sections(keep_metadata); - } else { - cmd.no_gc_sections(); } cmd.set_output_kind(link_output_kind, crate_type, out_filename); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index e0a3ad55be08..050797354b4a 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -326,7 +326,6 @@ pub(crate) trait Linker { link_or_cc_args(self, &[path]); } fn gc_sections(&mut self, keep_metadata: bool); - fn no_gc_sections(&mut self); fn full_relro(&mut self); fn partial_relro(&mut self); fn no_relro(&mut self); @@ -688,12 +687,6 @@ impl<'a> Linker for GccLinker<'a> { } } - fn no_gc_sections(&mut self) { - if self.is_gnu || self.sess.target.is_like_wasm { - self.link_arg("--no-gc-sections"); - } - } - fn optimize(&mut self) { if !self.is_gnu && !self.sess.target.is_like_wasm { return; @@ -1010,10 +1003,6 @@ impl<'a> Linker for MsvcLinker<'a> { } } - fn no_gc_sections(&mut self) { - self.link_arg("/OPT:NOREF,NOICF"); - } - fn full_relro(&mut self) { // noop } @@ -1243,10 +1232,6 @@ impl<'a> Linker for EmLinker<'a> { // noop } - fn no_gc_sections(&mut self) { - // noop - } - fn optimize(&mut self) { // Emscripten performs own optimizations self.cc_arg(match self.sess.opts.optimize { @@ -1418,10 +1403,6 @@ impl<'a> Linker for WasmLd<'a> { self.link_arg("--gc-sections"); } - fn no_gc_sections(&mut self) { - self.link_arg("--no-gc-sections"); - } - fn optimize(&mut self) { // The -O flag is, as of late 2023, only used for merging of strings and debuginfo, and // only differentiates -O0 and -O1. It does not apply to LTO. @@ -1567,10 +1548,6 @@ impl<'a> Linker for L4Bender<'a> { } } - fn no_gc_sections(&mut self) { - self.link_arg("--no-gc-sections"); - } - fn optimize(&mut self) { // GNU-style linkers support optimization with -O. GNU ld doesn't // need a numeric argument, but other linkers do. @@ -1734,10 +1711,6 @@ impl<'a> Linker for AixLinker<'a> { self.link_arg("-bgc"); } - fn no_gc_sections(&mut self) { - self.link_arg("-bnogc"); - } - fn optimize(&mut self) {} fn pgo_gen(&mut self) { @@ -1982,8 +1955,6 @@ impl<'a> Linker for PtxLinker<'a> { fn gc_sections(&mut self, _keep_metadata: bool) {} - fn no_gc_sections(&mut self) {} - fn pgo_gen(&mut self) {} fn no_crt_objects(&mut self) {} @@ -2057,8 +2028,6 @@ impl<'a> Linker for LlbcLinker<'a> { fn gc_sections(&mut self, _keep_metadata: bool) {} - fn no_gc_sections(&mut self) {} - fn pgo_gen(&mut self) {} fn no_crt_objects(&mut self) {} @@ -2139,8 +2108,6 @@ impl<'a> Linker for BpfLinker<'a> { fn gc_sections(&mut self, _keep_metadata: bool) {} - fn no_gc_sections(&mut self) {} - fn pgo_gen(&mut self) {} fn no_crt_objects(&mut self) {} diff --git a/tests/run-make/export-executable-symbols/rmake.rs b/tests/run-make/export-executable-symbols/rmake.rs index c602a43f9572..aa130b0855b7 100644 --- a/tests/run-make/export-executable-symbols/rmake.rs +++ b/tests/run-make/export-executable-symbols/rmake.rs @@ -5,6 +5,7 @@ // See https://github.com/rust-lang/rust/pull/85673 //@ ignore-wasm +//@ ignore-cross-compile use run_make_support::object::Object; use run_make_support::{bin_name, is_darwin, object, rustc}; diff --git a/tests/ui/linking/export-executable-symbols.rs b/tests/ui/linking/export-executable-symbols.rs index edaf312f1928..2bff58ca38a8 100644 --- a/tests/ui/linking/export-executable-symbols.rs +++ b/tests/ui/linking/export-executable-symbols.rs @@ -1,6 +1,7 @@ //@ run-pass //@ compile-flags: -Ctarget-feature=-crt-static -Zexport-executable-symbols //@ ignore-wasm +//@ ignore-cross-compile //@ edition: 2024 // Regression test for . From 6645bf54c159e5b06f829dbf04b6f6360a832993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 17 Jul 2025 10:12:55 +0200 Subject: [PATCH 255/363] Copy GCC sources into the build directory even outside CI --- src/bootstrap/src/core/build_steps/gcc.rs | 25 ++++++++++------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index 899e3fd9a45a..d4cbbe60921f 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -220,21 +220,18 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) { t!(fs::create_dir_all(install_dir)); // GCC creates files (e.g. symlinks to the downloaded dependencies) - // in the source directory, which does not work with our CI setup, where we mount + // in the source directory, which does not work with our CI/Docker setup, where we mount // source directories as read-only on Linux. - // Therefore, as a part of the build in CI, we first copy the whole source directory - // to the build directory, and perform the build from there. - let src_dir = if builder.config.is_running_on_ci { - let src_dir = builder.gcc_out(target).join("src"); - if src_dir.exists() { - builder.remove_dir(&src_dir); - } - builder.create_dir(&src_dir); - builder.cp_link_r(root, &src_dir); - src_dir - } else { - root.clone() - }; + // And in general, we shouldn't be modifying the source directories if possible, even for local + // builds. + // Therefore, we first copy the whole source directory to the build directory, and perform the + // build from there. + let src_dir = builder.gcc_out(target).join("src"); + if src_dir.exists() { + builder.remove_dir(&src_dir); + } + builder.create_dir(&src_dir); + builder.cp_link_r(root, &src_dir); command(src_dir.join("contrib/download_prerequisites")).current_dir(&src_dir).run(builder); let mut configure_cmd = command(src_dir.join("configure")); From 853333d4bdc7570b74e4bf02d506c2951a9d3e4b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 15 Jul 2025 09:57:44 +0000 Subject: [PATCH 256/363] constify `Option` methods --- library/core/src/option.rs | 137 ++++++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 40 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 9f432758a66f..7633429fc5c0 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -577,6 +577,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::iter::{self, FusedIterator, TrustedLen}; +use crate::marker::Destruct; use crate::ops::{self, ControlFlow, Deref, DerefMut}; use crate::panicking::{panic, panic_display}; use crate::pin::Pin; @@ -649,7 +650,8 @@ impl Option { #[must_use] #[inline] #[stable(feature = "is_some_and", since = "1.70.0")] - pub fn is_some_and(self, f: impl FnOnce(T) -> bool) -> bool { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn is_some_and(self, f: impl ~const FnOnce(T) -> bool + ~const Destruct) -> bool { match self { None => false, Some(x) => f(x), @@ -697,7 +699,8 @@ impl Option { #[must_use] #[inline] #[stable(feature = "is_none_or", since = "1.82.0")] - pub fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn is_none_or(self, f: impl ~const FnOnce(T) -> bool + ~const Destruct) -> bool { match self { None => true, Some(x) => f(x), @@ -1023,7 +1026,12 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or(self, default: T) -> T { + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn unwrap_or(self, default: T) -> T + where + T: ~const Destruct, + { match self { Some(x) => x, None => default, @@ -1042,9 +1050,10 @@ impl Option { #[inline] #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or_else(self, f: F) -> T + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn unwrap_or_else(self, f: F) -> T where - F: FnOnce() -> T, + F: ~const FnOnce() -> T + ~const Destruct, { match self { Some(x) => x, @@ -1073,9 +1082,10 @@ impl Option { /// [`FromStr`]: crate::str::FromStr #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or_default(self) -> T + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn unwrap_or_default(self) -> T where - T: Default, + T: ~const Default, { match self { Some(x) => x, @@ -1139,9 +1149,10 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn map(self, f: F) -> Option + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn map(self, f: F) -> Option where - F: FnOnce(T) -> U, + F: ~const FnOnce(T) -> U + ~const Destruct, { match self { Some(x) => Some(f(x)), @@ -1169,7 +1180,11 @@ impl Option { /// ``` #[inline] #[stable(feature = "result_option_inspect", since = "1.76.0")] - pub fn inspect(self, f: F) -> Self { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn inspect(self, f: F) -> Self + where + F: ~const FnOnce(&T) + ~const Destruct, + { if let Some(ref x) = self { f(x); } @@ -1198,9 +1213,11 @@ impl Option { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you don't need the returned value, use `if let` instead"] - pub fn map_or(self, default: U, f: F) -> U + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn map_or(self, default: U, f: F) -> U where - F: FnOnce(T) -> U, + F: ~const FnOnce(T) -> U + ~const Destruct, + U: ~const Destruct, { match self { Some(t) => f(t), @@ -1243,10 +1260,11 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn map_or_else(self, default: D, f: F) -> U + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn map_or_else(self, default: D, f: F) -> U where - D: FnOnce() -> U, - F: FnOnce(T) -> U, + D: ~const FnOnce() -> U + ~const Destruct, + F: ~const FnOnce(T) -> U + ~const Destruct, { match self { Some(t) => f(t), @@ -1273,10 +1291,11 @@ impl Option { /// [default value]: Default::default #[inline] #[unstable(feature = "result_option_map_or_default", issue = "138099")] - pub fn map_or_default(self, f: F) -> U + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn map_or_default(self, f: F) -> U where - U: Default, - F: FnOnce(T) -> U, + U: ~const Default, + F: ~const FnOnce(T) -> U + ~const Destruct, { match self { Some(t) => f(t), @@ -1307,7 +1326,8 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn ok_or(self, err: E) -> Result { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn ok_or(self, err: E) -> Result { match self { Some(v) => Ok(v), None => Err(err), @@ -1332,9 +1352,10 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn ok_or_else(self, err: F) -> Result + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn ok_or_else(self, err: F) -> Result where - F: FnOnce() -> E, + F: ~const FnOnce() -> E + ~const Destruct, { match self { Some(v) => Ok(v), @@ -1463,7 +1484,12 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn and(self, optb: Option) -> Option { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn and(self, optb: Option) -> Option + where + T: ~const Destruct, + U: ~const Destruct, + { match self { Some(_) => optb, None => None, @@ -1502,9 +1528,10 @@ impl Option { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("flat_map", "flatmap")] - pub fn and_then(self, f: F) -> Option + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn and_then(self, f: F) -> Option where - F: FnOnce(T) -> Option, + F: ~const FnOnce(T) -> Option + ~const Destruct, { match self { Some(x) => f(x), @@ -1538,9 +1565,11 @@ impl Option { /// [`Some(t)`]: Some #[inline] #[stable(feature = "option_filter", since = "1.27.0")] - pub fn filter

(self, predicate: P) -> Self + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn filter

(self, predicate: P) -> Self where - P: FnOnce(&T) -> bool, + P: ~const FnOnce(&T) -> bool + ~const Destruct, + T: ~const Destruct, { if let Some(x) = self { if predicate(&x) { @@ -1579,7 +1608,11 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn or(self, optb: Option) -> Option { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn or(self, optb: Option) -> Option + where + T: ~const Destruct, + { match self { x @ Some(_) => x, None => optb, @@ -1601,9 +1634,13 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn or_else(self, f: F) -> Option + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn or_else(self, f: F) -> Option where - F: FnOnce() -> Option, + F: ~const FnOnce() -> Option + ~const Destruct, + //FIXME(const_hack): this `T: ~const Destruct` is unnecessary, but even precise live drops can't tell + // no value of type `T` gets dropped here + T: ~const Destruct, { match self { x @ Some(_) => x, @@ -1634,7 +1671,11 @@ impl Option { /// ``` #[inline] #[stable(feature = "option_xor", since = "1.37.0")] - pub fn xor(self, optb: Option) -> Option { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn xor(self, optb: Option) -> Option + where + T: ~const Destruct, + { match (self, optb) { (a @ Some(_), None) => a, (None, b @ Some(_)) => b, @@ -1668,7 +1709,11 @@ impl Option { #[must_use = "if you intended to set a value, consider assignment instead"] #[inline] #[stable(feature = "option_insert", since = "1.53.0")] - pub fn insert(&mut self, value: T) -> &mut T { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn insert(&mut self, value: T) -> &mut T + where + T: ~const Destruct, + { *self = Some(value); // SAFETY: the code above just filled the option @@ -1720,9 +1765,10 @@ impl Option { /// ``` #[inline] #[stable(feature = "option_get_or_insert_default", since = "1.83.0")] - pub fn get_or_insert_default(&mut self) -> &mut T + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn get_or_insert_default(&mut self) -> &mut T where - T: Default, + T: ~const Default + ~const Destruct, { self.get_or_insert_with(T::default) } @@ -1746,9 +1792,11 @@ impl Option { /// ``` #[inline] #[stable(feature = "option_entry", since = "1.20.0")] - pub fn get_or_insert_with(&mut self, f: F) -> &mut T + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn get_or_insert_with(&mut self, f: F) -> &mut T where - F: FnOnce() -> T, + F: ~const FnOnce() -> T + ~const Destruct, + T: ~const Destruct, { if let None = self { *self = Some(f()); @@ -1812,9 +1860,10 @@ impl Option { /// ``` #[inline] #[stable(feature = "option_take_if", since = "1.80.0")] - pub fn take_if

(&mut self, predicate: P) -> Option + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn take_if

(&mut self, predicate: P) -> Option where - P: FnOnce(&mut T) -> bool, + P: ~const FnOnce(&mut T) -> bool + ~const Destruct, { if self.as_mut().map_or(false, predicate) { self.take() } else { None } } @@ -1859,7 +1908,12 @@ impl Option { /// assert_eq!(x.zip(z), None); /// ``` #[stable(feature = "option_zip_option", since = "1.46.0")] - pub fn zip(self, other: Option) -> Option<(T, U)> { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn zip(self, other: Option) -> Option<(T, U)> + where + T: ~const Destruct, + U: ~const Destruct, + { match (self, other) { (Some(a), Some(b)) => Some((a, b)), _ => None, @@ -1895,9 +1949,12 @@ impl Option { /// assert_eq!(x.zip_with(None, Point::new), None); /// ``` #[unstable(feature = "option_zip", issue = "70086")] - pub fn zip_with(self, other: Option, f: F) -> Option + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn zip_with(self, other: Option, f: F) -> Option where - F: FnOnce(T, U) -> R, + F: ~const FnOnce(T, U) -> R + ~const Destruct, + T: ~const Destruct, + U: ~const Destruct, { match (self, other) { (Some(a), Some(b)) => Some(f(a, b)), From 2ca2d93035ecb4b7afab079329979262aae379a4 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 17 Jul 2025 17:32:26 +0800 Subject: [PATCH 257/363] Auto-label `src/ci` and `.github/workflows` with `A-CI` And include `.github/workflows` for `T-infra` trigger files. --- triagebot.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 2f8114aeb3b6..cddb867c4715 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -471,6 +471,7 @@ trigger_files = [ [autolabel."T-infra"] trigger_files = [ + ".github/workflows", "src/ci", "src/tools/bump-stage0", "src/tools/cargotest", @@ -598,6 +599,12 @@ trigger_files = [ "src/tools/clippy", ] +[autolabel."A-CI"] +trigger_files = [ + ".github/workflows", + "src/ci", +] + # ------------------------------------------------------------------------------ # Prioritization and team nominations # ------------------------------------------------------------------------------ From 491b873d83052acb89d6b6ad5a5ab31d0a88a8c5 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 17 Jul 2025 17:33:44 +0800 Subject: [PATCH 258/363] Add myself to `infra-ci` reviewer group --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index cddb867c4715..61d8a814c89e 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1323,6 +1323,7 @@ infra-ci = [ "@Kobzol", "@marcoieni", "@jdno", + "@jieyouxu", ] rustdoc = [ "@GuillaumeGomez", From 69326878eeabb713e2d4a85215b87f18e498313c Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 13 Jul 2025 16:49:19 +0800 Subject: [PATCH 259/363] parse `const trait Trait` --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast/src/visit.rs | 3 +- compiler/rustc_ast_lowering/src/item.rs | 13 ++++++- compiler/rustc_ast_passes/messages.ftl | 4 +- .../rustc_ast_passes/src/ast_validation.rs | 38 +++++++++++-------- compiler/rustc_ast_passes/src/errors.rs | 2 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 2 + .../src/attributes/traits.rs | 1 + .../rustc_const_eval/src/check_consts/mod.rs | 2 +- .../src/const_eval/machine.rs | 4 +- compiler/rustc_feature/src/builtin_attrs.rs | 1 + compiler/rustc_hir/src/hir.rs | 19 +++++++--- compiler/rustc_hir/src/intravisit.rs | 10 ++++- compiler/rustc_hir_analysis/messages.ftl | 12 +++--- compiler/rustc_hir_analysis/src/collect.rs | 13 +++++-- .../src/collect/predicates_of.rs | 4 +- .../src/collect/resolve_bound_vars.rs | 2 +- compiler/rustc_hir_analysis/src/errors.rs | 2 + .../errors/wrong_number_of_generic_args.rs | 2 +- .../src/hir_ty_lowering/bounds.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 11 +++++- .../rustc_hir_typeck/src/method/suggest.rs | 6 +-- .../src/multiple_supertrait_upcastable.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_middle/src/hir/map.rs | 2 +- compiler/rustc_middle/src/ty/trait_def.rs | 2 +- compiler/rustc_parse/messages.ftl | 1 + compiler/rustc_parse/src/errors.rs | 8 ++++ compiler/rustc_parse/src/parser/item.rs | 28 ++++++++++---- compiler/rustc_passes/messages.ftl | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- .../src/error_reporting/traits/mod.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 10 ++--- compiler/rustc_trait_selection/src/errors.rs | 2 +- src/doc/rustc-dev-guide/src/effects.md | 9 ++--- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/clean/types.rs | 2 +- .../src/arbitrary_source_item_ordering.rs | 2 +- src/tools/clippy/clippy_lints/src/doc/mod.rs | 2 +- src/tools/clippy/clippy_lints/src/len_zero.rs | 2 +- .../clippy/clippy_lints/src/missing_inline.rs | 2 +- .../clippy/clippy_lints/src/trait_bounds.rs | 4 +- .../clippy_lints/src/upper_case_acronyms.rs | 2 +- .../clippy/clippy_utils/src/ast_utils/mod.rs | 5 ++- .../clippy_utils/src/check_proc_macro.rs | 4 +- src/tools/clippy/tests/ui/assign_ops.fixed | 3 +- src/tools/clippy/tests/ui/assign_ops.rs | 3 +- .../ui/missing_const_for_fn/const_trait.fixed | 3 +- .../ui/missing_const_for_fn/const_trait.rs | 3 +- .../missing_const_for_fn/const_trait.stderr | 2 +- .../ui/trait_duplication_in_bounds.fixed | 3 +- .../tests/ui/trait_duplication_in_bounds.rs | 3 +- .../ui/trait_duplication_in_bounds.stderr | 6 +-- .../crates/test-utils/src/minicore.rs | 3 +- src/tools/rustfmt/src/items.rs | 4 +- tests/crashes/117629.rs | 3 +- .../const-super-trait-nightly-disabled.stderr | 10 ++--- .../const-super-trait-nightly-enabled.stderr | 10 ++--- .../const-super-trait-stable-disabled.stderr | 10 ++--- .../const-super-trait-stable-enabled.stderr | 10 ++--- .../const-trait-stable-toolchain/rmake.rs | 10 ++--- tests/ui/consts/const-try.rs | 4 +- tests/ui/consts/const-try.stderr | 8 ++-- .../consts/rustc-impl-const-stability.stderr | 4 +- .../ui/specialization/const_trait_impl.stderr | 24 ++++++------ .../missing-const-stability.rs | 3 +- .../missing-const-stability.stderr | 6 +-- .../conditionally-const-invalid-places.stderr | 8 ++-- .../const-bounds-non-const-trait.rs | 6 +-- .../const-bounds-non-const-trait.stderr | 12 +++--- .../const-impl-requires-const-trait.rs | 2 +- .../const-impl-requires-const-trait.stderr | 6 +-- .../const-trait-bounds-trait-objects.rs | 8 ++-- .../const-trait-bounds-trait-objects.stderr | 20 +++++----- .../const_derives/derive-const-gate.rs | 2 +- .../const_derives/derive-const-gate.stderr | 4 +- .../derive-const-non-const-type.stderr | 4 +- .../ice-119717-constant-lifetime.rs | 2 +- .../ice-119717-constant-lifetime.stderr | 4 +- .../ice-126148-failed-to-normalize.rs | 4 +- .../ice-126148-failed-to-normalize.stderr | 8 ++-- .../traits/const-traits/spec-effectvar-ice.rs | 6 +-- .../const-traits/spec-effectvar-ice.stderr | 16 ++++---- .../super-traits-fail-2.nn.stderr | 14 +++---- .../super-traits-fail-2.ny.stderr | 20 +++++----- .../const-traits/super-traits-fail-2.rs | 10 ++--- .../super-traits-fail-2.yn.stderr | 2 +- .../super-traits-fail-3.nnn.stderr | 22 +++++------ .../super-traits-fail-3.nny.stderr | 22 +++++------ .../const-traits/super-traits-fail-3.rs | 14 +++---- .../super-traits-fail-3.ynn.stderr | 22 +++++------ .../super-traits-fail-3.yny.stderr | 20 +++++----- .../super-traits-fail-3.yyn.stderr | 10 ++--- .../trait-default-body-stability.stderr | 8 ++-- 94 files changed, 365 insertions(+), 299 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fa542a810dce..8c2b521c560d 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3690,6 +3690,7 @@ impl Default for FnHeader { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Trait { + pub constness: Const, pub safety: Safety, pub is_auto: IsAuto, pub ident: Ident, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 37fcc0d2167b..a344f23c345f 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -738,7 +738,8 @@ macro_rules! common_visitor_and_walkers { try_visit!(vis.visit_ty(self_ty)); visit_assoc_items(vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() }) } - ItemKind::Trait(box Trait { safety, is_auto: _, ident, generics, bounds, items }) => { + ItemKind::Trait(box Trait { constness, safety, is_auto: _, ident, generics, bounds, items }) => { + try_visit!(visit_constness(vis, constness)); try_visit!(visit_safety(vis, safety)); try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_generics(generics)); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 9d40a7386f69..abd70c7517c8 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -417,7 +417,16 @@ impl<'hir> LoweringContext<'_, 'hir> { items: new_impl_items, })) } - ItemKind::Trait(box Trait { is_auto, safety, ident, generics, bounds, items }) => { + ItemKind::Trait(box Trait { + constness, + is_auto, + safety, + ident, + generics, + bounds, + items, + }) => { + let constness = self.lower_constness(*constness); let ident = self.lower_ident(*ident); let (generics, (safety, items, bounds)) = self.lower_generics( generics, @@ -435,7 +444,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (safety, items, bounds) }, ); - hir::ItemKind::Trait(*is_auto, safety, ident, generics, bounds, items) + hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items) } ItemKind::TraitAlias(ident, generics, bounds) => { let ident = self.lower_ident(*ident); diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index c5780c957c97..e419154d65d1 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -240,10 +240,10 @@ ast_passes_static_without_body = ast_passes_tilde_const_disallowed = `[const]` is not allowed here .closure = closures cannot have `[const]` trait bounds .function = this function is not `const`, so it cannot have `[const]` trait bounds - .trait = this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds + .trait = this trait is not `const`, so it cannot have `[const]` trait bounds .trait_impl = this impl is not `const`, so it cannot have `[const]` trait bounds .impl = inherent impls cannot have `[const]` trait bounds - .trait_assoc_ty = associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds + .trait_assoc_ty = associated types in non-`const` traits cannot have `[const]` trait bounds .trait_impl_assoc_ty = associated types in non-const impls cannot have `[const]` trait bounds .inherent_assoc_ty = inherent associated types cannot have `[const]` trait bounds .object = trait objects cannot have `[const]` trait bounds diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 38889d28151b..c69250c03052 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -49,14 +49,14 @@ enum SelfSemantic { } enum TraitOrTraitImpl { - Trait { span: Span, constness_span: Option }, + Trait { span: Span, constness: Const }, TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span }, } impl TraitOrTraitImpl { fn constness(&self) -> Option { match self { - Self::Trait { constness_span: Some(span), .. } + Self::Trait { constness: Const::Yes(span), .. } | Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span), _ => None, } @@ -110,15 +110,10 @@ impl<'a> AstValidator<'a> { self.outer_trait_or_trait_impl = old; } - fn with_in_trait( - &mut self, - span: Span, - constness_span: Option, - f: impl FnOnce(&mut Self), - ) { + fn with_in_trait(&mut self, span: Span, constness: Const, f: impl FnOnce(&mut Self)) { let old = mem::replace( &mut self.outer_trait_or_trait_impl, - Some(TraitOrTraitImpl::Trait { span, constness_span }), + Some(TraitOrTraitImpl::Trait { span, constness }), ); f(self); self.outer_trait_or_trait_impl = old; @@ -273,7 +268,7 @@ impl<'a> AstValidator<'a> { }; let make_trait_const_sugg = if const_trait_impl - && let TraitOrTraitImpl::Trait { span, constness_span: None } = parent + && let TraitOrTraitImpl::Trait { span, constness: ast::Const::No } = parent { Some(span.shrink_to_lo()) } else { @@ -1131,10 +1126,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } visit::walk_item(self, item) } - ItemKind::Trait(box Trait { is_auto, generics, ident, bounds, items, .. }) => { + ItemKind::Trait(box Trait { + constness, + is_auto, + generics, + ident, + bounds, + items, + .. + }) => { self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); - let is_const_trait = + // FIXME(const_trait_impl) remove this + let alt_const_trait_span = attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span); + let constness = match (*constness, alt_const_trait_span) { + (Const::Yes(span), _) | (Const::No, Some(span)) => Const::Yes(span), + (Const::No, None) => Const::No, + }; if *is_auto == IsAuto::Yes { // Auto traits cannot have generics, super traits nor contain items. self.deny_generic_params(generics, ident.span); @@ -1145,13 +1153,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound // context for the supertraits. - let disallowed = - is_const_trait.is_none().then(|| TildeConstReason::Trait { span: item.span }); + let disallowed = matches!(constness, ast::Const::No) + .then(|| TildeConstReason::Trait { span: item.span }); self.with_tilde_const(disallowed, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) }); - self.with_in_trait(item.span, is_const_trait, |this| { + self.with_in_trait(item.span, constness, |this| { walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait); }); } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 3b2730d4ff9d..c1ebd025c7a4 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -590,7 +590,7 @@ pub(crate) struct ConstBoundTraitObject { } // FIXME(const_trait_impl): Consider making the note/reason the message of the diagnostic. -// FIXME(const_trait_impl): Provide structured suggestions (e.g., add `const` / `#[const_trait]` here). +// FIXME(const_trait_impl): Provide structured suggestions (e.g., add `const` here). #[derive(Diagnostic)] #[diag(ast_passes_tilde_const_disallowed)] pub(crate) struct TildeConstDisallowed { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 6c442553976e..11c97a552c69 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -357,6 +357,7 @@ impl<'a> State<'a> { self.bclose(item.span, empty, cb); } ast::ItemKind::Trait(box ast::Trait { + constness, safety, is_auto, ident, @@ -366,6 +367,7 @@ impl<'a> State<'a> { }) => { let (cb, ib) = self.head(""); self.print_visibility(&item.vis); + self.print_constness(*constness); self.print_safety(*safety); self.print_is_auto(*is_auto); self.word_nbsp("trait"); diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index d5e088effd51..e69a533699ba 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -91,6 +91,7 @@ impl NoArgsAttributeParser for DoNotImplementViaObjectParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject; } +// FIXME(const_trait_impl): remove this // Const traits pub(crate) struct ConstTraitParser; diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 9ab8e0692e16..ebf18c6f2ac8 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -93,7 +93,7 @@ pub fn rustc_allow_const_fn_unstable( /// world into two functions: those that are safe to expose on stable (and hence may not use /// unstable features, not even recursively), and those that are not. pub fn is_fn_or_trait_safe_to_expose_on_stable(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - // A default body in a `#[const_trait]` is const-stable when the trait is const-stable. + // A default body in a `const trait` is const-stable when the trait is const-stable. if tcx.is_const_default_method(def_id) { return is_fn_or_trait_safe_to_expose_on_stable(tcx, tcx.parent(def_id)); } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 70ad57b2b11b..f24fb18f83b1 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -363,8 +363,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { if let ty::InstanceKind::Item(def) = instance.def { // Execution might have wandered off into other crates, so we cannot do a stability- // sensitive check here. But we can at least rule out functions that are not const at - // all. That said, we have to allow calling functions inside a trait marked with - // #[const_trait]. These *are* const-checked! + // all. That said, we have to allow calling functions inside a `const trait`. These + // *are* const-checked! if !ecx.tcx.is_const_fn(def) || ecx.tcx.has_attr(def, sym::rustc_do_not_const_check) { // We certainly do *not* want to actually call the fn // though, so be sure we return here. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e2827f227abf..74872504b79f 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -614,6 +614,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // RFC 2632 + // FIXME(const_trait_impl) remove this gated!( const_trait, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, const_trait_impl, "`const_trait` is a temporary placeholder for marking a trait that is suitable for `const` \ diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ace2259aec38..e7898648c2b0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4163,6 +4163,7 @@ impl<'hir> Item<'hir> { expect_trait, ( + Constness, IsAuto, Safety, Ident, @@ -4170,8 +4171,8 @@ impl<'hir> Item<'hir> { GenericBounds<'hir>, &'hir [TraitItemId] ), - ItemKind::Trait(is_auto, safety, ident, generics, bounds, items), - (*is_auto, *safety, *ident, generics, bounds, items); + ItemKind::Trait(constness, is_auto, safety, ident, generics, bounds, items), + (*constness, *is_auto, *safety, *ident, generics, bounds, items); expect_trait_alias, (Ident, &'hir Generics<'hir>, GenericBounds<'hir>), ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds); @@ -4341,7 +4342,15 @@ pub enum ItemKind<'hir> { /// A union definition, e.g., `union Foo {x: A, y: B}`. Union(Ident, &'hir Generics<'hir>, VariantData<'hir>), /// A trait definition. - Trait(IsAuto, Safety, Ident, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemId]), + Trait( + Constness, + IsAuto, + Safety, + Ident, + &'hir Generics<'hir>, + GenericBounds<'hir>, + &'hir [TraitItemId], + ), /// A trait alias. TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>), @@ -4385,7 +4394,7 @@ impl ItemKind<'_> { | ItemKind::Enum(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Union(ident, ..) - | ItemKind::Trait(_, _, ident, ..) + | ItemKind::Trait(_, _, _, ident, ..) | ItemKind::TraitAlias(ident, ..) => Some(ident), ItemKind::Use(_, UseKind::Glob | UseKind::ListStem) @@ -4403,7 +4412,7 @@ impl ItemKind<'_> { | ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _) | ItemKind::Union(_, generics, _) - | ItemKind::Trait(_, _, _, generics, _, _) + | ItemKind::Trait(_, _, _, _, generics, _, _) | ItemKind::TraitAlias(_, generics, _) | ItemKind::Impl(Impl { generics, .. }) => generics, _ => return None, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3edb94c28da7..f33915d5b077 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -618,7 +618,15 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_variant_data(struct_definition)); } - ItemKind::Trait(_is_auto, _safety, ident, ref generics, bounds, trait_item_refs) => { + ItemKind::Trait( + _constness, + _is_auto, + _safety, + ident, + ref generics, + bounds, + trait_item_refs, + ) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds); diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 529d3578985a..a20becbe7e84 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -117,15 +117,15 @@ hir_analysis_coercion_between_struct_same_note = expected coercion between the s hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found -hir_analysis_const_bound_for_non_const_trait = `{$modifier}` can only be applied to `#[const_trait]` traits +hir_analysis_const_bound_for_non_const_trait = `{$modifier}` can only be applied to `const` traits .label = can't be applied to `{$trait_name}` - .note = `{$trait_name}` can't be used with `{$modifier}` because it isn't annotated with `#[const_trait]` - .suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations + .note = `{$trait_name}` can't be used with `{$modifier}` because it isn't `const` + .suggestion = {$suggestion_pre}mark `{$trait_name}` as `const` to allow it to have `const` implementations -hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]` +hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not `const` .label = this trait is not `const` - .suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations - .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const` + .suggestion = {$suggestion_pre}mark `{$trait_name}` as `const` to allow it to have `const` implementations + .note = marking a trait with `const` ensures all default method bodies are `const` .adding = adding a non-const method body in the future would be a breaking change hir_analysis_const_param_ty_impl_on_non_adt = diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 28a8758178ff..0728b24eb142 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -844,15 +844,20 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let item = tcx.hir_expect_item(def_id); - let (is_alias, is_auto, safety) = match item.kind { - hir::ItemKind::Trait(is_auto, safety, ..) => (false, is_auto == hir::IsAuto::Yes, safety), - hir::ItemKind::TraitAlias(..) => (true, false, hir::Safety::Safe), + let (constness, is_alias, is_auto, safety) = match item.kind { + hir::ItemKind::Trait(constness, is_auto, safety, ..) => { + (constness, false, is_auto == hir::IsAuto::Yes, safety) + } + hir::ItemKind::TraitAlias(..) => (hir::Constness::NotConst, true, false, hir::Safety::Safe), _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"), }; let attrs = tcx.get_all_attrs(def_id); // Only regular traits can be const. - let constness = if !is_alias && find_attr!(attrs, AttributeKind::ConstTrait(_)) { + // FIXME(const_trait_impl): remove this + let constness = if constness == hir::Constness::Const + || !is_alias && find_attr!(attrs, AttributeKind::ConstTrait(_)) + { hir::Constness::Const } else { hir::Constness::NotConst diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index af78130899e4..f2f1560d8b22 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -163,7 +163,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen .map(|t| ty::Binder::dummy(t.instantiate_identity())); } } - ItemKind::Trait(_, _, _, _, self_bounds, ..) + ItemKind::Trait(_, _, _, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, _, self_bounds) => { is_trait = Some((self_bounds, item.span)); } @@ -1022,7 +1022,7 @@ pub(super) fn const_conditions<'tcx>( Node::Item(item) => match item.kind { hir::ItemKind::Impl(impl_) => (impl_.generics, None, false), hir::ItemKind::Fn { generics, .. } => (generics, None, false), - hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => { + hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { (generics, Some((item.owner_id.def_id, supertraits)), false) } _ => bug!("const_conditions called on wrong item: {def_id:?}"), diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 8d7ac7db67bd..77e63e38c8c8 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -634,7 +634,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { | hir::ItemKind::Enum(_, generics, _) | hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Union(_, generics, _) - | hir::ItemKind::Trait(_, _, _, generics, ..) + | hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::TraitAlias(_, generics, ..) | hir::ItemKind::Impl(&hir::Impl { generics, .. }) => { // These kinds of items have only early-bound lifetime parameters. diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index c1c828392126..eb65050c17c7 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -525,6 +525,7 @@ pub(crate) struct ConstImplForNonConstTrait { pub trait_name: String, #[suggestion( applicability = "machine-applicable", + // FIXME(const_trait_impl) fix this suggestion code = "#[const_trait] ", style = "verbose" )] @@ -548,6 +549,7 @@ pub(crate) struct ConstBoundForNonConstTrait { pub suggestion_pre: &'static str, #[suggestion( applicability = "machine-applicable", + // FIXME(const_trait_impl) fix this suggestion code = "#[const_trait] ", style = "verbose" )] 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 3f928fd056e4..2d60c9561a98 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 @@ -635,7 +635,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { self.suggest_adding_type_and_const_args(err); } ExcessTypesOrConsts { .. } => { - // this can happen with `[const] T` where T isn't a const_trait. + // this can happen with `[const] T` where T isn't a `const trait`. } _ => unreachable!(), } 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 4784cfb5235b..9a752aeccdd2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -334,7 +334,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let (trait_generics, trait_bounds) = match parent_trait.kind { - hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits), + hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => (generics, supertraits), hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits), _ => unreachable!(), }; diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 2c13c9ef4387..bda02042aa66 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -735,8 +735,17 @@ impl<'a> State<'a> { } self.bclose(item.span, cb); } - hir::ItemKind::Trait(is_auto, safety, ident, generics, bounds, trait_items) => { + hir::ItemKind::Trait( + constness, + is_auto, + safety, + ident, + generics, + bounds, + trait_items, + ) => { let (cb, ib) = self.head(""); + self.print_constness(constness); self.print_is_auto(is_auto); self.print_safety(safety); self.word_nbsp("trait"); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 2815621ffdec..dbfa7e6273c8 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1189,7 +1189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { entry.1.insert((self_ty.span, "")); } Some(Node::Item(hir::Item { - kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..), + kind: hir::ItemKind::Trait(_, rustc_ast::ast::IsAuto::Yes, ..), span: item_span, .. })) => { @@ -1201,7 +1201,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some( Node::Item(hir::Item { kind: - hir::ItemKind::Trait(_, _, ident, ..) + hir::ItemKind::Trait(_, _, _, ident, ..) | hir::ItemKind::TraitAlias(ident, ..), .. }) @@ -4084,7 +4084,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, ident, _, bounds, _), + kind: hir::ItemKind::Trait(_, _, _, ident, _, bounds, _), .. }) => { let (sp, sep, article) = if bounds.is_empty() { diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 3cc55eaa0f2c..5513c703f1d5 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -39,7 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { let def_id = item.owner_id.to_def_id(); // NOTE(nbdd0121): use `dyn_compatibility_violations` instead of `is_dyn_compatible` because // the latter will report `where_clause_object_safety` lint. - if let hir::ItemKind::Trait(_, _, ident, ..) = item.kind + if let hir::ItemKind::Trait(_, _, _, ident, ..) = item.kind && cx.tcx.is_dyn_compatible(def_id) { let direct_super_traits_iter = cx diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b50453cb0dfd..5cd98038fc6d 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1131,7 +1131,7 @@ fn should_encode_mir( && reachable_set.contains(&def_id) && (generics.requires_monomorphization(tcx) || tcx.cross_crate_inlinable(def_id))); - // The function has a `const` modifier or is in a `#[const_trait]`. + // The function has a `const` modifier or is in a `const trait`. let is_const_fn = tcx.is_const_fn(def_id.to_def_id()) || tcx.is_const_default_method(def_id.to_def_id()); (is_const_fn, opt) diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 84710e5e636e..42a1e7377f4b 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -940,7 +940,7 @@ impl<'tcx> TyCtxt<'tcx> { }) => until_within(*outer_span, ty.span), // With generics and bounds. Node::Item(Item { - kind: ItemKind::Trait(_, _, _, generics, bounds, _), + kind: ItemKind::Trait(_, _, _, _, generics, bounds, _), span: outer_span, .. }) diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index ea25ce65f772..59e2b2a034de 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -20,7 +20,7 @@ pub struct TraitDef { pub safety: hir::Safety, - /// Whether this trait has been annotated with `#[const_trait]`. + /// Whether this trait is `const`. pub constness: hir::Constness, /// If `true`, then this trait had the `#[rustc_paren_sugar]` diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index af9f87355491..859118a4adee 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -855,6 +855,7 @@ parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern .suggestion = remove the `{$token}` parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto` +parse_trait_alias_cannot_be_const = trait aliases cannot be `const` parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe` parse_transpose_dyn_or_impl = `for<...>` expected after `{$kw}`, not before diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 7f1b0991f0c8..4aaaba01faeb 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1961,6 +1961,14 @@ pub(crate) struct TraitAliasCannotBeAuto { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_trait_alias_cannot_be_const)] +pub(crate) struct TraitAliasCannotBeConst { + #[primary_span] + #[label(parse_trait_alias_cannot_be_const)] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_trait_alias_cannot_be_unsafe)] pub(crate) struct TraitAliasCannotBeUnsafe { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index d6cc98d505cd..b767b0fcf994 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -244,6 +244,9 @@ impl<'a> Parser<'a> { self.bump(); // `static` let mutability = self.parse_mutability(); self.parse_static_item(safety, mutability)? + } else if self.check_keyword(exp!(Trait)) || self.check_trait_front_matter() { + // TRAIT ITEM + self.parse_item_trait(attrs, lo)? } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM if self.token.is_keyword(kw::Impl) { @@ -262,9 +265,6 @@ impl<'a> Parser<'a> { define_opaque: None, })) } - } else if self.check_keyword(exp!(Trait)) || self.check_auto_or_unsafe_trait_item() { - // TRAIT ITEM - self.parse_item_trait(attrs, lo)? } else if self.check_keyword(exp!(Impl)) || self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Impl]) { @@ -373,7 +373,7 @@ impl<'a> Parser<'a> { pub(super) fn is_path_start_item(&mut self) -> bool { self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }` || self.is_reuse_path_item() - || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }` + || self.check_trait_front_matter() // no: `auto::b`, yes: `auto trait X { .. }` || self.is_async_fn() // no(2015): `async::b`, yes: `async fn` || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac` } @@ -872,16 +872,19 @@ impl<'a> Parser<'a> { } } - /// Is this an `(unsafe auto? | auto) trait` item? - fn check_auto_or_unsafe_trait_item(&mut self) -> bool { + /// Is this an `(const unsafe? auto?| unsafe auto? | auto) trait` item? + fn check_trait_front_matter(&mut self) -> bool { // auto trait self.check_keyword(exp!(Auto)) && self.is_keyword_ahead(1, &[kw::Trait]) // unsafe auto trait || self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) + || self.check_keyword(exp!(Const)) && ((self.is_keyword_ahead(1, &[kw::Trait]) || self.is_keyword_ahead(1, &[kw::Auto]) && self.is_keyword_ahead(2, &[kw::Trait])) + || self.is_keyword_ahead(1, &[kw::Unsafe]) && self.is_keyword_ahead(2, &[kw::Trait, kw::Auto])) } /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemKind> { + let constness = self.parse_constness(Case::Sensitive); let safety = self.parse_safety(Case::Sensitive); // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(exp!(Auto)) { @@ -913,6 +916,9 @@ impl<'a> Parser<'a> { self.expect_semi()?; let whole_span = lo.to(self.prev_token.span); + if let Const::Yes(_) = constness { + self.dcx().emit_err(errors::TraitAliasCannotBeConst { span: whole_span }); + } if is_auto == IsAuto::Yes { self.dcx().emit_err(errors::TraitAliasCannotBeAuto { span: whole_span }); } @@ -927,7 +933,15 @@ impl<'a> Parser<'a> { // It's a normal trait. generics.where_clause = self.parse_where_clause()?; let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?; - Ok(ItemKind::Trait(Box::new(Trait { is_auto, safety, ident, generics, bounds, items }))) + Ok(ItemKind::Trait(Box::new(Trait { + constness, + is_auto, + safety, + ident, + generics, + bounds, + items, + }))) } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 500b4279588a..d1b856ca4157 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -784,7 +784,7 @@ passes_unused_capture_maybe_capture_ref = value captured by `{$name}` is never r .help = did you mean to capture by reference instead? passes_unused_default_method_body_const_note = - `default_method_body_is_const` has been replaced with `#[const_trait]` on traits + `default_method_body_is_const` has been replaced with `const` on traits passes_unused_duplicate = unused attribute diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1285e0ddf8ed..d8ffcedeb88a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1160,7 +1160,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match item.kind { ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _) if generics.params.len() != 0 => {} - ItemKind::Trait(_, _, _, generics, _, items) + ItemKind::Trait(_, _, _, _, generics, _, items) if generics.params.len() != 0 || items.iter().any(|item| { matches!(self.tcx.def_kind(item.owner_id), DefKind::AssocTy) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index d4cc1ceb2800..1d8b934cef3f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -453,7 +453,7 @@ pub fn report_dyn_incompatibility<'tcx>( let trait_str = tcx.def_path_str(trait_def_id); let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node { hir::Node::Item(item) => match item.kind { - hir::ItemKind::Trait(_, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => { + hir::ItemKind::Trait(_, _, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => { Some(ident.span) } _ => unreachable!(), 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 bd1d29826e60..cbbfad663db0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -267,7 +267,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let node = self.tcx.hir_node_by_def_id(body_id); match node { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, ident, generics, bounds, _), + kind: hir::ItemKind::Trait(_, _, _, ident, generics, bounds, _), .. }) if self_ty == self.tcx.types.self_param => { assert!(param_ty); @@ -330,7 +330,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } hir::Node::Item(hir::Item { kind: - hir::ItemKind::Trait(_, _, _, generics, ..) + hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }), .. }) if projection.is_some() => { @@ -354,7 +354,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Enum(_, generics, _) | hir::ItemKind::Union(_, generics, _) - | hir::ItemKind::Trait(_, _, _, generics, ..) + | hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) @@ -414,7 +414,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Enum(_, generics, _) | hir::ItemKind::Union(_, generics, _) - | hir::ItemKind::Trait(_, _, _, generics, ..) + | hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) @@ -3436,7 +3436,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut is_auto_trait = false; match tcx.hir_get_if_local(data.impl_or_alias_def_id) { Some(Node::Item(hir::Item { - kind: hir::ItemKind::Trait(is_auto, _, ident, ..), + kind: hir::ItemKind::Trait(_, is_auto, _, ident, ..), .. })) => { // FIXME: we should do something else so that it works even on crate foreign diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 90cdf75265dd..7901d52dffb6 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -534,7 +534,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope)) { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, _, generics, ..), + kind: hir::ItemKind::Trait(_, _, _, _, generics, ..), .. }) | hir::Node::Item(hir::Item { diff --git a/src/doc/rustc-dev-guide/src/effects.md b/src/doc/rustc-dev-guide/src/effects.md index c7aa27146686..87b0103a7bc4 100644 --- a/src/doc/rustc-dev-guide/src/effects.md +++ b/src/doc/rustc-dev-guide/src/effects.md @@ -67,10 +67,8 @@ in [`wfcheck::check_impl`]. Here's an example: ```rust -#[const_trait] -trait Bar {} -#[const_trait] -trait Foo: ~const Bar {} +const trait Bar {} +const trait Foo: ~const Bar {} // `const_conditions` contains `HostEffect(Self: Bar, maybe)` impl const Bar for () {} @@ -85,8 +83,7 @@ predicates of the trait method, and we attempt to prove the predicates of the impl method. We do the same for `const_conditions`: ```rust -#[const_trait] -trait Foo { +const trait Foo { fn hi(); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3df04091f163..1265a39d27ba 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2865,7 +2865,7 @@ fn clean_maybe_renamed_item<'tcx>( ItemKind::Fn { ref sig, generics, body: body_id, .. } => { clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) } - ItemKind::Trait(_, _, _, generics, bounds, item_ids) => { + ItemKind::Trait(_, _, _, _, generics, bounds, item_ids) => { let items = item_ids .iter() .map(|&ti| clean_trait_item(cx.tcx.hir_trait_item(ti), cx)) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 20babc6168b9..09647492d933 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -648,7 +648,7 @@ impl Item { let sig = tcx.fn_sig(def_id).skip_binder(); let constness = if tcx.is_const_fn(def_id) { // rustc's `is_const_fn` returns `true` for associated functions that have an `impl const` parent - // or that have a `#[const_trait]` parent. Do not display those as `const` in rustdoc because we + // or that have a `const trait` parent. Do not display those as `const` in rustdoc because we // won't be printing correct syntax plus the syntax is unstable. match tcx.opt_associated_item(def_id) { Some(ty::AssocItem { 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 07df893ae3ca..a9d3015ce5c4 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 @@ -306,7 +306,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { cur_f = Some(field); } }, - ItemKind::Trait(is_auto, _safety, _ident, _generics, _generic_bounds, item_ref) + ItemKind::Trait(_constness, is_auto, _safety, _ident, _generics, _generic_bounds, item_ref) if self.enable_ordering_for_trait && *is_auto == IsAuto::No => { let mut cur_t: Option<(TraitItemId, Ident)> = None; diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 2bf52216b832..22b781b89294 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -740,7 +740,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { ); } }, - ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) { + ItemKind::Trait(_, _, unsafety, ..) => match (headers.safety, unsafety) { (false, Safety::Unsafe) => span_lint( cx, MISSING_SAFETY_DOC, diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index d32017a8b414..1bf03480c825 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -125,7 +125,7 @@ declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMP impl<'tcx> LateLintPass<'tcx> for LenZero { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Trait(_, _, ident, _, _, trait_items) = item.kind + if let ItemKind::Trait(_, _, _, ident, _, _, trait_items) = item.kind && !item.span.from_expansion() { check_trait_items(cx, item, ident, trait_items); diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 329f71934375..c4a3d10299b6 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { let attrs = cx.tcx.hir_attrs(it.hir_id()); check_missing_inline_attrs(cx, attrs, it.span, desc); }, - hir::ItemKind::Trait(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 { diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 45e54302e32c..9182a55081f4 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { // special handling for self trait bounds as these are not considered generics // ie. trait Foo: Display {} if let Item { - kind: ItemKind::Trait(_, _, _, _, bounds, ..), + kind: ItemKind::Trait(_, _, _, _, _, bounds, ..), .. } = item { @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { .. }) = segments.first() && let Some(Node::Item(Item { - kind: ItemKind::Trait(_, _, _, _, self_bounds, _), + kind: ItemKind::Trait(_, _, _, _, _, self_bounds, _), .. })) = cx.tcx.hir_get_if_local(*def_id) { diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs index 02281b9e9223..944cd91a7fda 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -131,7 +131,7 @@ impl LateLintPass<'_> for UpperCaseAcronyms { return; } match it.kind { - ItemKind::TyAlias(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Trait(_, _, ident, ..) => { + ItemKind::TyAlias(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Trait(_, _, _, ident, ..) => { check_ident(cx, &ident, it.hir_id(), self.upper_case_acronyms_aggressive); }, ItemKind::Enum(ident, _, ref enumdef) => { diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 42254ec8e92d..96f0273c4396 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -444,6 +444,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { }, ( Trait(box ast::Trait { + constness: lc, is_auto: la, safety: lu, ident: li, @@ -452,6 +453,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { items: lis, }), Trait(box ast::Trait { + constness: rc, is_auto: ra, safety: ru, ident: ri, @@ -460,7 +462,8 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { items: ris, }), ) => { - la == ra + matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No) + && la == ra && matches!(lu, Safety::Default) == matches!(ru, Safety::Default) && eq_id(*li, *ri) && eq_generics(lg, rg) diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index ce61fffe0def..dc31ed08fb71 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -252,11 +252,11 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::Struct(_, _, VariantData::Struct { .. }) => (Pat::Str("struct"), Pat::Str("}")), ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")), ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")), - ItemKind::Trait(_, Safety::Unsafe, ..) + ItemKind::Trait(_, _, Safety::Unsafe, ..) | ItemKind::Impl(Impl { safety: Safety::Unsafe, .. }) => (Pat::Str("unsafe"), Pat::Str("}")), - ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), + ItemKind::Trait(_, IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")), ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")), _ => return (Pat::Str(""), Pat::Str("")), diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed index 99beea850a25..eee61f949e76 100644 --- a/src/tools/clippy/tests/ui/assign_ops.fixed +++ b/src/tools/clippy/tests/ui/assign_ops.fixed @@ -84,8 +84,7 @@ mod issue14871 { const ONE: Self; } - #[const_trait] - pub trait NumberConstants { + 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 900d5ad38e03..13ffcee0a3c8 100644 --- a/src/tools/clippy/tests/ui/assign_ops.rs +++ b/src/tools/clippy/tests/ui/assign_ops.rs @@ -84,8 +84,7 @@ mod issue14871 { const ONE: Self; } - #[const_trait] - pub trait NumberConstants { + pub const trait NumberConstants { fn constant(value: usize) -> Self; } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed index f1d5579a7230..c113c1caaa65 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed @@ -3,8 +3,7 @@ // Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658 -#[const_trait] -trait ConstTrait { +const trait ConstTrait { fn method(self); } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs index d495759526d3..69248bc52d5c 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs @@ -3,8 +3,7 @@ // Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658 -#[const_trait] -trait ConstTrait { +const trait ConstTrait { fn method(self); } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr index b994b88fac68..7ea009cfc9be 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr @@ -1,5 +1,5 @@ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/const_trait.rs:24:1 + --> tests/ui/missing_const_for_fn/const_trait.rs:23:1 | LL | / fn can_be_const() { LL | | 0u64.method(); diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed index cf52ecf2f032..88ba5f810b4e 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed @@ -167,8 +167,7 @@ where } // #13476 -#[const_trait] -trait ConstTrait {} +const trait ConstTrait {} const fn const_trait_bounds_good() {} const fn const_trait_bounds_bad() {} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs index 955562f08dc3..19a4e70e294e 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs @@ -167,8 +167,7 @@ where } // #13476 -#[const_trait] -trait ConstTrait {} +const trait ConstTrait {} const fn const_trait_bounds_good() {} const fn const_trait_bounds_bad() {} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr index ab31721ef515..a56a683de973 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr @@ -59,19 +59,19 @@ LL | fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { | ^^^^^^^^^^^^^^^^^ help: try: `Any + Send` error: these bounds contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:174:36 + --> tests/ui/trait_duplication_in_bounds.rs:173:36 | LL | const fn const_trait_bounds_bad() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[const] ConstTrait` error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:181:8 + --> tests/ui/trait_duplication_in_bounds.rs:180:8 | LL | T: IntoIterator + IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `IntoIterator` error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:203:8 + --> tests/ui/trait_duplication_in_bounds.rs:202:8 | LL | T: AssocConstTrait + AssocConstTrait, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `AssocConstTrait` diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index dc1eba1a1abf..e5d8f78d9484 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -1011,8 +1011,7 @@ pub mod ops { } #[lang = "add_assign"] - #[const_trait] - pub trait AddAssign { + pub const trait AddAssign { fn add_assign(&mut self, rhs: Rhs); } diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 1a3897b51cb8..7084639aca9a 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1172,6 +1172,7 @@ pub(crate) fn format_trait( unreachable!(); }; let ast::Trait { + constness, is_auto, safety, ident, @@ -1182,7 +1183,8 @@ pub(crate) fn format_trait( let mut result = String::with_capacity(128); let header = format!( - "{}{}{}trait ", + "{}{}{}{}trait ", + format_constness(constness), format_visibility(context, &item.vis), format_safety(safety), format_auto(is_auto), diff --git a/tests/crashes/117629.rs b/tests/crashes/117629.rs index d8b5f328545d..f63365395c6b 100644 --- a/tests/crashes/117629.rs +++ b/tests/crashes/117629.rs @@ -3,8 +3,7 @@ #![feature(const_trait_impl)] -#[const_trait] -trait Tr { +const trait Tr { async fn ft1() {} } diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr index 5ce815b9aed4..464208f989e3 100644 --- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here LL | trait Bar: ~const Foo {} | ^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> const-super-trait.rs:7:1 | LL | trait Bar: ~const Foo {} @@ -30,24 +30,24 @@ LL | const fn foo(x: &T) { = 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: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:7:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ can't be applied to `Foo` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:9:17 | LL | const fn foo(x: &T) { | ^^^^^^ can't be applied to `Bar` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: ~const Foo {} | ++++++++++++++ diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr index ef764a62b066..569e559186f7 100644 --- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr @@ -4,30 +4,30 @@ error: `[const]` is not allowed here LL | trait Bar: ~const Foo {} | ^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> const-super-trait.rs:7:1 | LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:7:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:9:17 | LL | const fn foo(x: &T) { | ^^^^^^ can't be applied to `Bar` | -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: ~const Foo {} | ++++++++++++++ diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr index 3dc147e076ff..694e06fb6ea2 100644 --- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here 7 | trait Bar: ~const Foo {} | ^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> const-super-trait.rs:7:1 | 7 | trait Bar: ~const Foo {} @@ -26,25 +26,25 @@ error[E0658]: const trait impls are experimental | = note: see issue #143874 for more information -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:7:12 | 7 | trait Bar: ~const Foo {} | ^^^^^^ can't be applied to `Foo` | -note: `Foo` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Foo` can't be used with `[const]` because it isn't `const` --> const-super-trait.rs:3:1 | 3 | trait Foo { | ^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:9:17 | 9 | const fn foo(x: &T) { | ^^^^^^ can't be applied to `Bar` | -note: `Bar` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Bar` can't be used with `[const]` because it isn't `const` --> const-super-trait.rs:7:1 | 7 | trait Bar: ~const Foo {} diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr index 2cdeb277ca4a..2109f0deb729 100644 --- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here 7 | trait Bar: ~const Foo {} | ^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> const-super-trait.rs:7:1 | 7 | trait Bar: ~const Foo {} @@ -16,25 +16,25 @@ error[E0554]: `#![feature]` may not be used on the NIGHTLY release channel 1 | #![cfg_attr(feature_enabled, feature(const_trait_impl))] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:7:12 | 7 | trait Bar: ~const Foo {} | ^^^^^^ can't be applied to `Foo` | -note: `Foo` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Foo` can't be used with `[const]` because it isn't `const` --> const-super-trait.rs:3:1 | 3 | trait Foo { | ^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:9:17 | 9 | const fn foo(x: &T) { | ^^^^^^ can't be applied to `Bar` | -note: `Bar` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Bar` can't be used with `[const]` because it isn't `const` --> const-super-trait.rs:7:1 | 7 | trait Bar: ~const Foo {} diff --git a/tests/run-make/const-trait-stable-toolchain/rmake.rs b/tests/run-make/const-trait-stable-toolchain/rmake.rs index 09a7c27a1064..729b71457e9e 100644 --- a/tests/run-make/const-trait-stable-toolchain/rmake.rs +++ b/tests/run-make/const-trait-stable-toolchain/rmake.rs @@ -11,9 +11,7 @@ fn main() { .env("RUSTC_BOOTSTRAP", "-1") .cfg("feature_enabled") .run_fail() - .assert_stderr_not_contains( - "as `#[const_trait]` to allow it to have `const` implementations", - ) + .assert_stderr_not_contains("as `const` to allow it to have `const` implementations") .stderr_utf8(); diff() .expected_file("const-super-trait-stable-enabled.stderr") @@ -29,7 +27,7 @@ fn main() { .ui_testing() .run_fail() .assert_stderr_not_contains("enable `#![feature(const_trait_impl)]` in your crate and mark") - .assert_stderr_contains("as `#[const_trait]` to allow it to have `const` implementations") + .assert_stderr_contains("as `const` to allow it to have `const` implementations") .stderr_utf8(); diff() .expected_file("const-super-trait-nightly-enabled.stderr") @@ -40,9 +38,7 @@ fn main() { .env("RUSTC_BOOTSTRAP", "-1") .run_fail() .assert_stderr_not_contains("enable `#![feature(const_trait_impl)]` in your crate and mark") - .assert_stderr_not_contains( - "as `#[const_trait]` to allow it to have `const` implementations", - ) + .assert_stderr_not_contains("as `const` to allow it to have `const` implementations") .stderr_utf8(); diff() .expected_file("const-super-trait-stable-disabled.stderr") diff --git a/tests/ui/consts/const-try.rs b/tests/ui/consts/const-try.rs index 26aa9230a398..e13fad78441d 100644 --- a/tests/ui/consts/const-try.rs +++ b/tests/ui/consts/const-try.rs @@ -13,14 +13,14 @@ struct TryMe; struct Error; impl const FromResidual for TryMe { - //~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` + //~^ ERROR const `impl` for trait `FromResidual` which is not `const` fn from_residual(residual: Error) -> Self { TryMe } } impl const Try for TryMe { - //~^ ERROR const `impl` for trait `Try` which is not marked with `#[const_trait]` + //~^ ERROR const `impl` for trait `Try` which is not `const` type Output = (); type Residual = Error; fn from_output(output: Self::Output) -> Self { diff --git a/tests/ui/consts/const-try.stderr b/tests/ui/consts/const-try.stderr index 4209ca1d5266..7004ea3e6dbb 100644 --- a/tests/ui/consts/const-try.stderr +++ b/tests/ui/consts/const-try.stderr @@ -1,19 +1,19 @@ -error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +error: const `impl` for trait `FromResidual` which is not `const` --> $DIR/const-try.rs:15:12 | LL | impl const FromResidual for TryMe { | ^^^^^^^^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error: const `impl` for trait `Try` which is not marked with `#[const_trait]` +error: const `impl` for trait `Try` which is not `const` --> $DIR/const-try.rs:22:12 | LL | impl const Try for TryMe { | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0015]: `?` is not allowed on `TryMe` in constant functions diff --git a/tests/ui/consts/rustc-impl-const-stability.stderr b/tests/ui/consts/rustc-impl-const-stability.stderr index a3ef4031a13e..55c085396882 100644 --- a/tests/ui/consts/rustc-impl-const-stability.stderr +++ b/tests/ui/consts/rustc-impl-const-stability.stderr @@ -1,10 +1,10 @@ -error: const `impl` for trait `Debug` which is not marked with `#[const_trait]` +error: const `impl` for trait `Debug` which is not `const` --> $DIR/rustc-impl-const-stability.rs:15:12 | LL | impl const std::fmt::Debug for Data { | ^^^^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error: aborting due to 1 previous error diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr index b9c768812c83..a21a48997ee7 100644 --- a/tests/ui/specialization/const_trait_impl.stderr +++ b/tests/ui/specialization/const_trait_impl.stderr @@ -1,57 +1,57 @@ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:36:9 | LL | impl const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:42:9 | LL | impl const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:48:9 | LL | impl const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:42:9 | LL | impl const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:36:9 | LL | impl const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:48:9 | LL | impl const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/stability-attribute/missing-const-stability.rs b/tests/ui/stability-attribute/missing-const-stability.rs index c3e72e839488..8a37f19ffb0d 100644 --- a/tests/ui/stability-attribute/missing-const-stability.rs +++ b/tests/ui/stability-attribute/missing-const-stability.rs @@ -20,8 +20,7 @@ impl Foo { } #[stable(feature = "stable", since = "1.0.0")] -#[const_trait] -pub trait Bar { +pub const trait Bar { //~^ ERROR trait has missing const stability attribute #[stable(feature = "stable", since = "1.0.0")] fn fun(); diff --git a/tests/ui/stability-attribute/missing-const-stability.stderr b/tests/ui/stability-attribute/missing-const-stability.stderr index 09461e6fb54d..70a2450c53a0 100644 --- a/tests/ui/stability-attribute/missing-const-stability.stderr +++ b/tests/ui/stability-attribute/missing-const-stability.stderr @@ -5,9 +5,9 @@ LL | pub const fn foo() {} | ^^^^^^^^^^^^^^^^^^^^^ error: trait has missing const stability attribute - --> $DIR/missing-const-stability.rs:24:1 + --> $DIR/missing-const-stability.rs:23:1 | -LL | / pub trait Bar { +LL | / pub const trait Bar { LL | | LL | | #[stable(feature = "stable", since = "1.0.0")] LL | | fn fun(); @@ -15,7 +15,7 @@ LL | | } | |_^ error: function has missing const stability attribute - --> $DIR/missing-const-stability.rs:37:1 + --> $DIR/missing-const-stability.rs:36:1 | LL | pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr b/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr index d0dd95029159..010b15846436 100644 --- a/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr +++ b/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr @@ -72,7 +72,7 @@ error: `[const]` is not allowed here LL | type Type: [const] Trait; | ^^^^^^^ | -note: associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds +note: associated types in non-`const` traits cannot have `[const]` trait bounds --> $DIR/conditionally-const-invalid-places.rs:25:5 | LL | type Type: [const] Trait; @@ -84,7 +84,7 @@ error: `[const]` is not allowed here LL | type Type: [const] Trait; | ^^^^^^^ | -note: associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds +note: associated types in non-`const` traits cannot have `[const]` trait bounds --> $DIR/conditionally-const-invalid-places.rs:25:5 | LL | type Type: [const] Trait; @@ -180,7 +180,7 @@ error: `[const]` is not allowed here LL | trait Child0: [const] Trait {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/conditionally-const-invalid-places.rs:52:1 | LL | trait Child0: [const] Trait {} @@ -192,7 +192,7 @@ error: `[const]` is not allowed here LL | trait Child1 where Self: [const] Trait {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/conditionally-const-invalid-places.rs:53:1 | LL | trait Child1 where Self: [const] Trait {} diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs index ae31d9ae0ac0..baded1792014 100644 --- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs +++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs @@ -4,10 +4,10 @@ trait NonConst {} const fn perform() {} -//~^ ERROR `[const]` can only be applied to `#[const_trait]` traits -//~| ERROR `[const]` can only be applied to `#[const_trait]` traits +//~^ ERROR `[const]` can only be applied to `const` traits +//~| ERROR `[const]` can only be applied to `const` traits fn operate() {} -//~^ ERROR `const` can only be applied to `#[const_trait]` traits +//~^ ERROR `const` can only be applied to `const` traits fn main() {} diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr index 6c68e4ec3acc..304d81bb9171 100644 --- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr +++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr @@ -1,33 +1,33 @@ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const-bounds-non-const-trait.rs:6:21 | LL | const fn perform() {} | ^^^^^^^ can't be applied to `NonConst` | -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const-bounds-non-const-trait.rs:6:21 | LL | const fn perform() {} | ^^^^^^^ can't be applied to `NonConst` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ -error: `const` can only be applied to `#[const_trait]` traits +error: `const` can only be applied to `const` traits --> $DIR/const-bounds-non-const-trait.rs:10:15 | LL | fn operate() {} | ^^^^^ can't be applied to `NonConst` | -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs index 6bea664b65fe..176ae091a41a 100644 --- a/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs +++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs @@ -4,6 +4,6 @@ pub trait A {} impl const A for () {} -//~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]` +//~^ ERROR: const `impl` for trait `A` which is not `const` fn main() {} diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr index c728eda069ec..bf73436b78d3 100644 --- a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr +++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr @@ -1,12 +1,12 @@ -error: const `impl` for trait `A` which is not marked with `#[const_trait]` +error: const `impl` for trait `A` which is not `const` --> $DIR/const-impl-requires-const-trait.rs:6:12 | LL | impl const A for () {} | ^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -help: mark `A` as `#[const_trait]` to allow it to have `const` implementations +help: mark `A` as `const` to allow it to have `const` implementations | LL | #[const_trait] pub trait A {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs index 1d1da9b0e3df..658132441c26 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs @@ -1,9 +1,7 @@ #![feature(const_trait_impl)] -// FIXME(const_trait_impl) add effects //@ edition: 2021 -#[const_trait] -trait Trait {} +const trait Trait {} fn main() { let _: &dyn const Trait; //~ ERROR const trait bounds are not allowed in trait object types @@ -14,7 +12,7 @@ fn main() { trait NonConst {} const fn handle(_: &dyn const NonConst) {} //~^ ERROR const trait bounds are not allowed in trait object types -//~| ERROR `const` can only be applied to `#[const_trait]` traits +//~| ERROR `const` can only be applied to `const` traits const fn take(_: &dyn [const] NonConst) {} //~^ ERROR `[const]` is not allowed here -//~| ERROR `[const]` can only be applied to `#[const_trait]` traits +//~| ERROR `[const]` can only be applied to `const` traits diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr index 06e0493024c1..3ba5da39106d 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr @@ -1,11 +1,11 @@ error: const trait bounds are not allowed in trait object types - --> $DIR/const-trait-bounds-trait-objects.rs:9:17 + --> $DIR/const-trait-bounds-trait-objects.rs:7:17 | LL | let _: &dyn const Trait; | ^^^^^^^^^^^ error: `[const]` is not allowed here - --> $DIR/const-trait-bounds-trait-objects.rs:10:17 + --> $DIR/const-trait-bounds-trait-objects.rs:8:17 | LL | let _: &dyn [const] Trait; | ^^^^^^^ @@ -13,37 +13,37 @@ LL | let _: &dyn [const] Trait; = note: trait objects cannot have `[const]` trait bounds error: const trait bounds are not allowed in trait object types - --> $DIR/const-trait-bounds-trait-objects.rs:15:25 + --> $DIR/const-trait-bounds-trait-objects.rs:13:25 | LL | const fn handle(_: &dyn const NonConst) {} | ^^^^^^^^^^^^^^ error: `[const]` is not allowed here - --> $DIR/const-trait-bounds-trait-objects.rs:18:23 + --> $DIR/const-trait-bounds-trait-objects.rs:16:23 | LL | const fn take(_: &dyn [const] NonConst) {} | ^^^^^^^ | = note: trait objects cannot have `[const]` trait bounds -error: `const` can only be applied to `#[const_trait]` traits - --> $DIR/const-trait-bounds-trait-objects.rs:15:25 +error: `const` can only be applied to `const` traits + --> $DIR/const-trait-bounds-trait-objects.rs:13:25 | LL | const fn handle(_: &dyn const NonConst) {} | ^^^^^ can't be applied to `NonConst` | -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-trait-bounds-trait-objects.rs:18:23 +error: `[const]` can only be applied to `const` traits + --> $DIR/const-trait-bounds-trait-objects.rs:16:23 | LL | const fn take(_: &dyn [const] NonConst) {} | ^^^^^^^ can't be applied to `NonConst` | -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs b/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs index 04fea1189aea..c0796907855a 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs +++ b/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs @@ -1,5 +1,5 @@ #[derive_const(Debug)] //~ ERROR use of unstable library feature -//~^ ERROR const `impl` for trait `Debug` which is not marked with `#[const_trait]` +//~^ ERROR const `impl` for trait `Debug` which is not `const` //~| ERROR cannot call non-const method pub struct S; diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr index 5bde358001cb..5ed12b370529 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr @@ -7,13 +7,13 @@ LL | #[derive_const(Debug)] = help: add `#![feature(derive_const)]` 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: const `impl` for trait `Debug` which is not marked with `#[const_trait]` +error: const `impl` for trait `Debug` which is not `const` --> $DIR/derive-const-gate.rs:1:16 | LL | #[derive_const(Debug)] | ^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0015]: cannot call non-const method `Formatter::<'_>::write_str` in constant functions diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr index c0bd360ebe5d..93638801895d 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr @@ -1,10 +1,10 @@ -error: const `impl` for trait `Debug` which is not marked with `#[const_trait]` +error: const `impl` for trait `Debug` which is not `const` --> $DIR/derive-const-non-const-type.rs:12:16 | LL | #[derive_const(Debug)] | ^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0015]: cannot call non-const method `Formatter::<'_>::debug_tuple_field1_finish` in constant functions diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs index e53b87274d3a..47c85980aca0 100644 --- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs +++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs @@ -4,7 +4,7 @@ use std::ops::FromResidual; impl const FromResidual for T { - //~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` + //~^ ERROR const `impl` for trait `FromResidual` which is not `const` //~| ERROR type parameter `T` must be used as the type parameter for some local type fn from_residual(t: T) -> _ { //~^ ERROR the placeholder `_` is not allowed diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr index a165ef12060d..5c5fba95f024 100644 --- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr +++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr @@ -1,10 +1,10 @@ -error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +error: const `impl` for trait `FromResidual` which is not `const` --> $DIR/ice-119717-constant-lifetime.rs:6:15 | LL | impl const FromResidual for T { | ^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs index 3473be565c18..5e368b9e6a96 100644 --- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs @@ -6,11 +6,11 @@ struct TryMe; struct Error; impl const FromResidual for TryMe {} -//~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +//~^ ERROR const `impl` for trait `FromResidual` which is not `const` //~| ERROR not all trait items implemented impl const Try for TryMe { - //~^ ERROR const `impl` for trait `Try` which is not marked with `#[const_trait]` + //~^ ERROR const `impl` for trait `Try` which is not `const` //~| ERROR not all trait items implemented type Output = (); type Residual = Error; diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr index 41f99c2d375e..849d6522cd6e 100644 --- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr @@ -1,10 +1,10 @@ -error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +error: const `impl` for trait `FromResidual` which is not `const` --> $DIR/ice-126148-failed-to-normalize.rs:8:12 | LL | impl const FromResidual for TryMe {} | ^^^^^^^^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0046]: not all trait items implemented, missing: `from_residual` @@ -15,13 +15,13 @@ LL | impl const FromResidual for TryMe {} | = help: implement the missing item: `fn from_residual(_: Error) -> Self { todo!() }` -error: const `impl` for trait `Try` which is not marked with `#[const_trait]` +error: const `impl` for trait `Try` which is not `const` --> $DIR/ice-126148-failed-to-normalize.rs:12:12 | LL | impl const Try for TryMe { | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0046]: not all trait items implemented, missing: `from_output`, `branch` diff --git a/tests/ui/traits/const-traits/spec-effectvar-ice.rs b/tests/ui/traits/const-traits/spec-effectvar-ice.rs index c85b17469675..46f71b114a37 100644 --- a/tests/ui/traits/const-traits/spec-effectvar-ice.rs +++ b/tests/ui/traits/const-traits/spec-effectvar-ice.rs @@ -8,11 +8,11 @@ trait Specialize {} trait Foo {} impl const Foo for T {} -//~^ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` +//~^ error: const `impl` for trait `Foo` which is not `const` impl const Foo for T where T: const Specialize {} -//~^ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` -//~| error: `const` can only be applied to `#[const_trait]` traits +//~^ error: const `impl` for trait `Foo` which is not `const` +//~| error: `const` can only be applied to `const` traits //~| error: specialization impl does not specialize any associated items //~| error: cannot specialize on trait `Specialize` diff --git a/tests/ui/traits/const-traits/spec-effectvar-ice.stderr b/tests/ui/traits/const-traits/spec-effectvar-ice.stderr index 474d96698d56..ef5e58e1c3df 100644 --- a/tests/ui/traits/const-traits/spec-effectvar-ice.stderr +++ b/tests/ui/traits/const-traits/spec-effectvar-ice.stderr @@ -1,36 +1,36 @@ -error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` +error: const `impl` for trait `Foo` which is not `const` --> $DIR/spec-effectvar-ice.rs:10:15 | LL | impl const Foo for T {} | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo {} | ++++++++++++++ -error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` +error: const `impl` for trait `Foo` which is not `const` --> $DIR/spec-effectvar-ice.rs:13:15 | LL | impl const Foo for T where T: const Specialize {} | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo {} | ++++++++++++++ -error: `const` can only be applied to `#[const_trait]` traits +error: `const` can only be applied to `const` traits --> $DIR/spec-effectvar-ice.rs:13:34 | LL | impl const Foo for T where T: const Specialize {} | ^^^^^ can't be applied to `Specialize` | -help: mark `Specialize` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Specialize` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Specialize {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr index 19f072b289e2..0ecbad64bc85 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr @@ -4,43 +4,43 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-2.rs:11:1 | LL | trait Bar: [const] Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr index 4921f78d3acd..0e5b697d1dde 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr @@ -1,58 +1,58 @@ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.rs b/tests/ui/traits/const-traits/super-traits-fail-2.rs index 781dacb81a19..36e7c1c4e4ac 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.rs +++ b/tests/ui/traits/const-traits/super-traits-fail-2.rs @@ -9,11 +9,11 @@ trait Foo { #[cfg_attr(any(yy, ny), const_trait)] trait Bar: [const] Foo {} -//[ny,nn]~^ ERROR: `[const]` can only be applied to `#[const_trait]` -//[ny,nn]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[ny,nn]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[ny]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[ny]~| ERROR: `[const]` can only be applied to `#[const_trait]` +//[ny,nn]~^ ERROR: `[const]` can only be applied to `const` traits +//[ny,nn]~| ERROR: `[const]` can only be applied to `const` traits +//[ny,nn]~| ERROR: `[const]` can only be applied to `const` traits +//[ny]~| ERROR: `[const]` can only be applied to `const` traits +//[ny]~| ERROR: `[const]` can only be applied to `const` traits //[yn,nn]~^^^^^^ ERROR: `[const]` is not allowed here const fn foo(x: &T) { diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr index a151349822ec..657e8ee82e32 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-2.rs:11:1 | LL | trait Bar: [const] Foo {} diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr index 3f48375dd045..a0ae60526ef3 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: [const] Foo {} @@ -30,60 +30,60 @@ LL | const fn foo(x: &T) { = 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: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr index 3f48375dd045..a0ae60526ef3 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: [const] Foo {} @@ -30,60 +30,60 @@ LL | const fn foo(x: &T) { = 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: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.rs b/tests/ui/traits/const-traits/super-traits-fail-3.rs index 5370f607decb..d74bd3467840 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.rs +++ b/tests/ui/traits/const-traits/super-traits-fail-3.rs @@ -21,17 +21,17 @@ trait Foo { #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)] //[nyy,nyn]~^ ERROR: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future trait Bar: [const] Foo {} -//[yny,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `#[const_trait]` -//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[yny]~^^^^ ERROR: `[const]` can only be applied to `#[const_trait]` -//[yny]~| ERROR: `[const]` can only be applied to `#[const_trait]` +//[yny,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `const` traits +//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `const` traits +//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `const` traits +//[yny]~^^^^ ERROR: `[const]` can only be applied to `const` traits +//[yny]~| ERROR: `[const]` can only be applied to `const` traits //[yyn,ynn,nny,nnn]~^^^^^^ ERROR: `[const]` is not allowed here //[nyy,nyn,nny,nnn]~^^^^^^^ ERROR: const trait impls are experimental const fn foo(x: &T) { - //[yyn,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `#[const_trait]` - //[yyn,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]` + //[yyn,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `const` traits + //[yyn,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `const` traits //[nyy,nyn,nny,nnn]~^^^ ERROR: const trait impls are experimental x.a(); //[yyn]~^ ERROR: the trait bound `T: [const] Foo` is not satisfied diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr index 89e090b7d1cf..c8ec77c2f093 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr @@ -4,66 +4,66 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: [const] Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr index 683eeb738500..a820239cde01 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr @@ -1,58 +1,58 @@ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr index 39cfdfe20301..de3664dae841 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr @@ -4,31 +4,31 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: [const] Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/trait-default-body-stability.stderr b/tests/ui/traits/const-traits/trait-default-body-stability.stderr index a13d9a1e075b..b995d6f4f3d4 100644 --- a/tests/ui/traits/const-traits/trait-default-body-stability.stderr +++ b/tests/ui/traits/const-traits/trait-default-body-stability.stderr @@ -1,19 +1,19 @@ -error: const `impl` for trait `Try` which is not marked with `#[const_trait]` +error: const `impl` for trait `Try` which is not `const` --> $DIR/trait-default-body-stability.rs:19:12 | LL | impl const Try for T { | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +error: const `impl` for trait `FromResidual` which is not `const` --> $DIR/trait-default-body-stability.rs:34:12 | LL | impl const FromResidual for T { | ^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0015]: `?` is not allowed on `T` in constant functions From c0597fbd80acdc23434ed8f59c41f0728a2d9ba6 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Mon, 14 Jul 2025 02:19:24 +0500 Subject: [PATCH 260/363] cleaned up some tests Reverting file name weird-exprs.rs due to its historical use, recognition in community and references --- .../deduplicate-diagnostics.deduplicate.stderr | 4 ++-- .../deduplicate-diagnostics.duplicate.stderr | 10 +++++----- tests/ui/diagnostic-flags/deduplicate-diagnostics.rs | 2 ++ ...{syntax-edge-cases-lint-clean.rs => weird-exprs.rs} | 0 tests/ui/fmt/println-debug-different-types.rs | 4 +++- tests/ui/linking/ld64-cross-compilation.rs | 8 ++++---- tests/ui/shadowed/shadowing-generic-item.rs | 2 ++ tests/ui/shadowed/shadowing-generic-item.stderr | 4 ++-- tests/ui/symbol-names/struct-constructor-mangling.rs | 4 ++-- 9 files changed, 22 insertions(+), 16 deletions(-) rename tests/ui/expr/{syntax-edge-cases-lint-clean.rs => weird-exprs.rs} (100%) diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr index 5df2c687bddc..c0d568eb5384 100644 --- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr +++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr @@ -1,11 +1,11 @@ error[E0452]: malformed lint attribute input - --> $DIR/deduplicate-diagnostics.rs:8:8 + --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] | ^^^^^^^^^ bad attribute argument error: cannot find derive macro `Unresolved` in this scope - --> $DIR/deduplicate-diagnostics.rs:4:10 + --> $DIR/deduplicate-diagnostics.rs:6:10 | LL | #[derive(Unresolved)] | ^^^^^^^^^^ diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr index 48e2ba7b86aa..74d7066293f3 100644 --- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr +++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr @@ -1,17 +1,17 @@ error[E0452]: malformed lint attribute input - --> $DIR/deduplicate-diagnostics.rs:8:8 + --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] | ^^^^^^^^^ bad attribute argument error: cannot find derive macro `Unresolved` in this scope - --> $DIR/deduplicate-diagnostics.rs:4:10 + --> $DIR/deduplicate-diagnostics.rs:6:10 | LL | #[derive(Unresolved)] | ^^^^^^^^^^ error: cannot find derive macro `Unresolved` in this scope - --> $DIR/deduplicate-diagnostics.rs:4:10 + --> $DIR/deduplicate-diagnostics.rs:6:10 | LL | #[derive(Unresolved)] | ^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | #[derive(Unresolved)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0452]: malformed lint attribute input - --> $DIR/deduplicate-diagnostics.rs:8:8 + --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] | ^^^^^^^^^ bad attribute argument @@ -27,7 +27,7 @@ LL | #[deny("literal")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0452]: malformed lint attribute input - --> $DIR/deduplicate-diagnostics.rs:8:8 + --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] | ^^^^^^^^^ bad attribute argument diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs index 299c1f5f4610..48705266e358 100644 --- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs +++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs @@ -1,3 +1,5 @@ +//! Test that `-Z deduplicate-diagnostics` flag properly deduplicates diagnostic messages. + //@ revisions: duplicate deduplicate //@[deduplicate] compile-flags: -Z deduplicate-diagnostics=yes diff --git a/tests/ui/expr/syntax-edge-cases-lint-clean.rs b/tests/ui/expr/weird-exprs.rs similarity index 100% rename from tests/ui/expr/syntax-edge-cases-lint-clean.rs rename to tests/ui/expr/weird-exprs.rs diff --git a/tests/ui/fmt/println-debug-different-types.rs b/tests/ui/fmt/println-debug-different-types.rs index 64994a558174..9e21be1f03fc 100644 --- a/tests/ui/fmt/println-debug-different-types.rs +++ b/tests/ui/fmt/println-debug-different-types.rs @@ -1,8 +1,10 @@ +//! Smoke test for println!() with debug format specifiers. + //@ run-pass #[derive(Debug)] enum Numbers { - Three + Three, } pub fn main() { diff --git a/tests/ui/linking/ld64-cross-compilation.rs b/tests/ui/linking/ld64-cross-compilation.rs index 75acc07a002c..d6c6d1ff91de 100644 --- a/tests/ui/linking/ld64-cross-compilation.rs +++ b/tests/ui/linking/ld64-cross-compilation.rs @@ -1,11 +1,11 @@ +//! This is a regression test for https://github.com/rust-lang/rust/issues/140686. +//! Although this is a ld64(ld-classic) bug, we still need to support it +//! due to cross-compilation and support for older Xcode. + //@ compile-flags: -Copt-level=3 -Ccodegen-units=256 -Clink-arg=-ld_classic //@ run-pass //@ only-x86_64-apple-darwin -// This is a regression test for https://github.com/rust-lang/rust/issues/140686. -// Although this is a ld64(ld-classic) bug, we still need to support it -// due to cross-compilation and support for older Xcode. - fn main() { let dst: Vec = Vec::new(); let len = broken_func(std::hint::black_box(2), dst); diff --git a/tests/ui/shadowed/shadowing-generic-item.rs b/tests/ui/shadowed/shadowing-generic-item.rs index 46cfdf1efa8f..c3a0ced04e7f 100644 --- a/tests/ui/shadowed/shadowing-generic-item.rs +++ b/tests/ui/shadowed/shadowing-generic-item.rs @@ -1,3 +1,5 @@ +//! Test that generic parameters shadow structs and modules with the same name. + struct T { i: i32 } fn f() { let t = T { i: 0 }; //~ ERROR expected struct, variant or union type, found type parameter `T` diff --git a/tests/ui/shadowed/shadowing-generic-item.stderr b/tests/ui/shadowed/shadowing-generic-item.stderr index f0eaa1a5c64c..55a0bb36ea80 100644 --- a/tests/ui/shadowed/shadowing-generic-item.stderr +++ b/tests/ui/shadowed/shadowing-generic-item.stderr @@ -1,5 +1,5 @@ error[E0574]: expected struct, variant or union type, found type parameter `T` - --> $DIR/lexical-scopes.rs:3:13 + --> $DIR/shadowing-generic-item.rs:5:13 | LL | struct T { i: i32 } | - you might have meant to refer to this struct @@ -9,7 +9,7 @@ LL | let t = T { i: 0 }; | ^ not a struct, variant or union type error[E0599]: no function or associated item named `f` found for type parameter `Foo` in the current scope - --> $DIR/lexical-scopes.rs:10:10 + --> $DIR/shadowing-generic-item.rs:12:10 | LL | fn g() { | --- function or associated item `f` not found for this type parameter diff --git a/tests/ui/symbol-names/struct-constructor-mangling.rs b/tests/ui/symbol-names/struct-constructor-mangling.rs index f32cbb7aaae9..ec8791e21549 100644 --- a/tests/ui/symbol-names/struct-constructor-mangling.rs +++ b/tests/ui/symbol-names/struct-constructor-mangling.rs @@ -1,3 +1,5 @@ +//! Test that the symbol mangling of Foo-the-constructor-function versus Foo-the-type do not collide + //@ run-pass fn size_of_val(_: &T) -> usize { @@ -6,8 +8,6 @@ fn size_of_val(_: &T) -> usize { struct Foo(#[allow(dead_code)] i64); -// Test that the (symbol) mangling of `Foo` (the `struct` type) and that of -// `typeof Foo` (the function type of the `struct` constructor) don't collide. fn main() { size_of_val(&Foo(0)); size_of_val(&Foo); From f2048019718409885ac57c480f010bdfbfe5bfd0 Mon Sep 17 00:00:00 2001 From: codedump Date: Wed, 16 Jul 2025 23:21:47 +0800 Subject: [PATCH 261/363] fix: fix issue 143740, Wrong messages from compiler confusing methods with the same name from different traits --- compiler/rustc_hir_typeck/src/method/probe.rs | 3 +- ...all_method_without_import.no_import.stderr | 7 +--- .../no-method-suggested-traits.stderr | 8 ----- ...e-trait-object-with-separate-params.stderr | 16 ++------- tests/ui/methods/wrong-ambig-message.rs | 34 +++++++++++++++++++ tests/ui/methods/wrong-ambig-message.stderr | 30 ++++++++++++++++ 6 files changed, 70 insertions(+), 28 deletions(-) create mode 100644 tests/ui/methods/wrong-ambig-message.rs create mode 100644 tests/ui/methods/wrong-ambig-message.stderr diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 94c93e736274..d5ac17bd7858 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1649,7 +1649,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - let sources = candidates.iter().map(|p| self.candidate_source(p, self_ty)).collect(); + let sources = + applicable_candidates.iter().map(|p| self.candidate_source(p.0, self_ty)).collect(); return Some(Err(MethodError::Ambiguity(sources))); } diff --git a/tests/ui/impl-trait/call_method_without_import.no_import.stderr b/tests/ui/impl-trait/call_method_without_import.no_import.stderr index e59409ea27e6..dbac74b22479 100644 --- a/tests/ui/impl-trait/call_method_without_import.no_import.stderr +++ b/tests/ui/impl-trait/call_method_without_import.no_import.stderr @@ -22,15 +22,10 @@ LL | x.fmt(f); = help: items from traits can only be used if the trait is in scope help: the following traits which provide `fmt` are implemented but not in scope; perhaps you want to import one of them | -LL + use std::fmt::Binary; - | LL + use std::fmt::Debug; | -LL + use std::fmt::Display; +LL + use std::fmt::Pointer; | -LL + use std::fmt::LowerExp; - | - = and 5 other candidates error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/no-method-suggested-traits.stderr b/tests/ui/impl-trait/no-method-suggested-traits.stderr index 061c9bd8f350..b376f205411c 100644 --- a/tests/ui/impl-trait/no-method-suggested-traits.stderr +++ b/tests/ui/impl-trait/no-method-suggested-traits.stderr @@ -9,12 +9,8 @@ help: the following traits which provide `method` are implemented but not in sco | LL + use foo::Bar; | -LL + use no_method_suggested_traits::Reexported; - | LL + use no_method_suggested_traits::foo::PubPub; | -LL + use no_method_suggested_traits::qux::PrivPub; - | help: there is a method `method2` with a similar name | LL | 1u32.method2(); @@ -31,12 +27,8 @@ help: the following traits which provide `method` are implemented but not in sco | LL + use foo::Bar; | -LL + use no_method_suggested_traits::Reexported; - | LL + use no_method_suggested_traits::foo::PubPub; | -LL + use no_method_suggested_traits::qux::PrivPub; - | help: there is a method `method2` with a similar name | LL | std::rc::Rc::new(&mut Box::new(&1u32)).method2(); diff --git a/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr index 32cff62284e0..aeecb82e9d91 100644 --- a/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr +++ b/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr @@ -20,17 +20,12 @@ error[E0034]: multiple applicable items in scope LL | let z = x.foo(); | ^^^ multiple `foo` found | -note: candidate #1 is defined in the trait `FinalFoo` - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:60:5 - | -LL | fn foo(&self) -> u8; - | ^^^^^^^^^^^^^^^^^^^^ -note: candidate #2 is defined in an impl of the trait `NuisanceFoo` for the type `T` +note: candidate #1 is defined in an impl of the trait `NuisanceFoo` for the type `T` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:73:9 | LL | fn foo(self) {} | ^^^^^^^^^^^^ -note: candidate #3 is defined in an impl of the trait `X` for the type `T` +note: candidate #2 is defined in an impl of the trait `X` for the type `T` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:46:9 | LL | fn foo(self: Smaht) -> u64 { @@ -38,14 +33,9 @@ LL | fn foo(self: Smaht) -> u64 { help: disambiguate the method for candidate #1 | LL - let z = x.foo(); -LL + let z = FinalFoo::foo(&x); - | -help: disambiguate the method for candidate #2 - | -LL - let z = x.foo(); LL + let z = NuisanceFoo::foo(x); | -help: disambiguate the method for candidate #3 +help: disambiguate the method for candidate #2 | LL - let z = x.foo(); LL + let z = X::foo(x); diff --git a/tests/ui/methods/wrong-ambig-message.rs b/tests/ui/methods/wrong-ambig-message.rs new file mode 100644 index 000000000000..f88d77e259d6 --- /dev/null +++ b/tests/ui/methods/wrong-ambig-message.rs @@ -0,0 +1,34 @@ +fn main() { + trait Hello { + fn name(&self) -> String; + } + + #[derive(Debug)] + struct Container2 { + val: String, + } + + trait AName2 { + fn name(&self) -> String; + } + + trait BName2 { + fn name(&self, v: bool) -> String; + } + + impl AName2 for Container2 { + fn name(&self) -> String { + "aname2".into() + } + } + + impl BName2 for Container2 { + fn name(&self, _v: bool) -> String { + "bname2".into() + } + } + + let c2 = Container2 { val: "abc".into() }; + println!("c2 = {:?}", c2.name()); + //~^ ERROR: multiple applicable items in scope +} diff --git a/tests/ui/methods/wrong-ambig-message.stderr b/tests/ui/methods/wrong-ambig-message.stderr new file mode 100644 index 000000000000..9a254595e40b --- /dev/null +++ b/tests/ui/methods/wrong-ambig-message.stderr @@ -0,0 +1,30 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/wrong-ambig-message.rs:32:30 + | +LL | println!("c2 = {:?}", c2.name()); + | ^^^^ multiple `name` found + | +note: candidate #1 is defined in an impl of the trait `AName2` for the type `Container2` + --> $DIR/wrong-ambig-message.rs:20:9 + | +LL | fn name(&self) -> String { + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `BName2` for the type `Container2` + --> $DIR/wrong-ambig-message.rs:26:9 + | +LL | fn name(&self, _v: bool) -> String { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method for candidate #1 + | +LL - println!("c2 = {:?}", c2.name()); +LL + println!("c2 = {:?}", AName2::name(&c2)); + | +help: disambiguate the method for candidate #2 + | +LL - println!("c2 = {:?}", c2.name()); +LL + println!("c2 = {:?}", BName2::name(&c2)); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. From 16d8f3c895c8278a6519b6015b6e9d9a5a1fd311 Mon Sep 17 00:00:00 2001 From: dianqk Date: Thu, 17 Jul 2025 19:53:13 +0800 Subject: [PATCH 262/363] Update LLVM submodule --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index d3c793b02564..e8a2ffcf322f 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit d3c793b025645a4565ac59aceb30d2d116ff1a41 +Subproject commit e8a2ffcf322f45b8dce82c65ab27a3e2430a6b51 From a886852e23fad1be91648871b0240805fd52c13c Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 17 Jul 2025 14:54:14 +0200 Subject: [PATCH 263/363] ci: use windows 22 for all free runners --- src/ci/github-actions/jobs.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 6c5e37b51ef2..f0c52fe3d1ca 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -34,6 +34,8 @@ runners: os: windows-2022 <<: *base-job + # NOTE: windows-2025 has less disk space available than windows-2022, + # because the D drive is missing. - &job-windows-25 os: windows-2025 <<: *base-job @@ -542,13 +544,13 @@ auto: env: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler SCRIPT: make ci-msvc-py - <<: *job-windows-25 + <<: *job-windows - name: x86_64-msvc-2 env: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler SCRIPT: make ci-msvc-ps1 - <<: *job-windows-25 + <<: *job-windows # i686-msvc is split into two jobs to run tests in parallel. - name: i686-msvc-1 From 998df3a3e851908afd05c3318f16d99849af5c55 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 15 Jul 2025 23:42:35 +0300 Subject: [PATCH 264/363] resolve: Make disambiguators for underscore bindings module-local --- .../rustc_resolve/src/build_reduced_graph.rs | 30 ++++++++------- compiler/rustc_resolve/src/imports.rs | 38 ++++++++++++------- compiler/rustc_resolve/src/lib.rs | 33 ++++++++-------- compiler/rustc_resolve/src/macros.rs | 2 +- 4 files changed, 58 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 5a1be618ceea..9a5c18247e76 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -49,8 +49,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, binding: NameBinding<'ra>, ) { - let key = self.new_disambiguated_key(ident, ns); - if let Err(old_binding) = self.try_define(parent, key, binding, false) { + if let Err(old_binding) = self.try_define(parent, ident, ns, binding, false) { self.report_conflict(parent, ident, ns, old_binding, binding); } } @@ -439,16 +438,18 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.indeterminate_imports.push(import); match import.kind { - // Don't add unresolved underscore imports to modules - ImportKind::Single { target: Ident { name: kw::Underscore, .. }, .. } => {} ImportKind::Single { target, type_ns_only, .. } => { - 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); - } - }); + // Don't add underscore imports to `single_imports` + // because they cannot define any usable names. + if target.name != kw::Underscore { + 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); + } + }); + } } // We don't add prelude imports to the globs since they only affect lexical scopes, // which are not relevant to import resolution. @@ -1402,9 +1403,12 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { 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); - } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) { + } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) + && ident.name != kw::Underscore + { + // Don't add underscore names, they cannot be looked up anyway. let impl_def_id = self.r.tcx.local_parent(local_def_id); - let key = BindingKey::new(ident.normalize_to_macros_2_0(), ns); + let key = BindingKey::new(ident, ns); self.r.impl_binding_keys.entry(impl_def_id).or_default().insert(key); } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index c3e39d2071b5..888322c0fd62 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -25,7 +25,7 @@ use rustc_span::{Ident, Span, Symbol, kw, sym}; use smallvec::SmallVec; use tracing::debug; -use crate::Namespace::*; +use crate::Namespace::{self, *}; use crate::diagnostics::{DiagMode, Suggestion, import_candidates}; use crate::errors::{ CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate, @@ -338,13 +338,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn try_define( &mut self, module: Module<'ra>, - key: BindingKey, + ident: Ident, + ns: Namespace, binding: NameBinding<'ra>, warn_ambiguity: bool, ) -> Result<(), NameBinding<'ra>> { let res = binding.res(); - self.check_reserved_macro_name(key.ident, res); + self.check_reserved_macro_name(ident, res); self.set_binding_parent_module(binding, module); + // 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, || { + (module.0.0.lazy_resolutions.borrow().len() + 1).try_into().unwrap() + }); self.update_resolution(module, key, warn_ambiguity, |this, resolution| { if let Some(old_binding) = resolution.best_binding() { if res == Res::Err && old_binding.res() != Res::Err { @@ -383,7 +390,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (old_glob @ true, false) | (old_glob @ false, true) => { let (glob_binding, non_glob_binding) = if old_glob { (old_binding, binding) } else { (binding, old_binding) }; - if key.ns == MacroNS + if ns == MacroNS && non_glob_binding.expansion != LocalExpnId::ROOT && glob_binding.res() != non_glob_binding.res() { @@ -489,10 +496,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; if self.is_accessible_from(binding.vis, scope) { let imported_binding = self.import(binding, *import); - let key = BindingKey { ident, ..key }; let _ = self.try_define( import.parent_scope.module, - key, + ident, + key.ns, imported_binding, warn_ambiguity, ); @@ -514,11 +521,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let dummy_binding = self.dummy_binding; let dummy_binding = self.import(dummy_binding, import); self.per_ns(|this, ns| { - let key = BindingKey::new(target, ns); - let _ = this.try_define(import.parent_scope.module, key, dummy_binding, false); - this.update_resolution(import.parent_scope.module, key, false, |_, resolution| { - resolution.single_imports.swap_remove(&import); - }) + let module = import.parent_scope.module; + let _ = this.try_define(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| { + resolution.single_imports.swap_remove(&import); + }) + } }); self.record_use(target, dummy_binding, Used::Other); } else if import.imported_module.get().is_none() { @@ -895,7 +906,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { PendingBinding::Ready(Some(imported_binding)) } Err(Determinacy::Determined) => { - // Don't update the resolution for underscores, because it was never added. + // 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| { @@ -1510,7 +1521,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .is_some_and(|binding| binding.warn_ambiguity_recursive()); let _ = self.try_define( import.parent_scope.module, - key, + key.ident, + key.ns, imported_binding, warn_ambiguity, ); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f904f3262969..81907881f449 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -532,15 +532,26 @@ struct BindingKey { /// identifier. ident: Ident, ns: Namespace, - /// 0 if ident is not `_`, otherwise a value that's unique to the specific - /// `_` in the expanded AST that introduced this binding. + /// When we add an underscore binding (with ident `_`) to some module, this field has + /// a non-zero value that uniquely identifies this binding in that module. + /// For non-underscore bindings this field is zero. + /// When a key is constructed for name lookup (as opposed to name definition), this field is + /// also zero, even for underscore names, so for underscores the lookup will never succeed. disambiguator: u32, } impl BindingKey { fn new(ident: Ident, ns: Namespace) -> Self { - let ident = ident.normalize_to_macros_2_0(); - BindingKey { ident, ns, disambiguator: 0 } + BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator: 0 } + } + + fn new_disambiguated( + ident: Ident, + ns: Namespace, + disambiguator: impl FnOnce() -> u32, + ) -> BindingKey { + let disambiguator = if ident.name == kw::Underscore { disambiguator() } else { 0 }; + BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator } } } @@ -1078,8 +1089,6 @@ pub struct Resolver<'ra, 'tcx> { module_map: FxIndexMap>, binding_parent_modules: FxHashMap, Module<'ra>>, - underscore_disambiguator: u32, - /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap>, glob_error: Option, @@ -1500,7 +1509,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { extern_crate_map: Default::default(), module_children: Default::default(), trait_map: NodeMap::default(), - underscore_disambiguator: 0, empty_module, module_map, block_map: Default::default(), @@ -1880,17 +1888,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { import_ids } - fn new_disambiguated_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey { - let ident = ident.normalize_to_macros_2_0(); - let disambiguator = if ident.name == kw::Underscore { - self.underscore_disambiguator += 1; - self.underscore_disambiguator - } else { - 0 - }; - BindingKey { ident, ns, disambiguator } - } - fn resolutions(&mut self, module: Module<'ra>) -> &'ra Resolutions<'ra> { if module.populate_on_access.get() { module.populate_on_access.set(false); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index c17d74659db3..2b5632805b6f 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -530,7 +530,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { target_trait.for_each_child(self, |this, ident, ns, _binding| { // FIXME: Adjust hygiene for idents from globs, like for glob imports. if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id) - && overriding_keys.contains(&BindingKey::new(ident.normalize_to_macros_2_0(), ns)) + && overriding_keys.contains(&BindingKey::new(ident, ns)) { // The name is overridden, do not produce it from the glob delegation. } else { From 0a71873c34d38978121853f0d97358427bd54038 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Thu, 17 Jul 2025 14:12:03 +0000 Subject: [PATCH 265/363] panic_main.rs panic=unwind tests needs unwinding Only run the panic=unwind tests on platforms that support unwinding. --- tests/ui/panics/panic-main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/ui/panics/panic-main.rs b/tests/ui/panics/panic-main.rs index bf79de78a579..2395f68241f5 100644 --- a/tests/ui/panics/panic-main.rs +++ b/tests/ui/panics/panic-main.rs @@ -14,12 +14,15 @@ //@[unwind-zero] compile-flags: -Cpanic=unwind //@[unwind-zero] exec-env:RUST_BACKTRACE=0 +//@[unwind-zero] needs-unwind //@[unwind-one] compile-flags: -Cpanic=unwind //@[unwind-one] exec-env:RUST_BACKTRACE=1 +//@[unwind-one] needs-unwind //@[unwind-full] compile-flags: -Cpanic=unwind //@[unwind-full] exec-env:RUST_BACKTRACE=full +//@[unwind-full] needs-unwind //@ run-fail //@ error-pattern:moop From 2f5722cf1bdd4ffcdf46e85ffbd97455aaeec7de Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Jul 2025 10:21:29 +0000 Subject: [PATCH 266/363] Make `Option` `const PartialEq` --- library/core/src/option.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 9f432758a66f..da6e311ff5e1 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2243,7 +2243,8 @@ impl<'a, T> From<&'a mut Option> for Option<&'a mut T> { #[stable(feature = "rust1", since = "1.0.0")] impl crate::marker::StructuralPartialEq for Option {} #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Option { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialEq for Option { #[inline] fn eq(&self, other: &Self) -> bool { // Spelling out the cases explicitly optimizes better than From 9d29583355018f00d65b9d5e08758e3f9bcba97c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Jul 2025 10:34:29 +0000 Subject: [PATCH 267/363] Make `NonZero` `const PartialEq` --- library/core/src/num/nonzero.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 11d50e0f89f3..b8900c4113ad 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -200,9 +200,10 @@ impl UseCloned for NonZero where T: ZeroablePrimitive {} impl Copy for NonZero where T: ZeroablePrimitive {} #[stable(feature = "nonzero", since = "1.28.0")] -impl PartialEq for NonZero +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialEq for NonZero where - T: ZeroablePrimitive + PartialEq, + T: ZeroablePrimitive + ~const PartialEq, { #[inline] fn eq(&self, other: &Self) -> bool { From 250648e871c1e685f09427bd31fd399090f15640 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Jul 2025 10:20:25 +0000 Subject: [PATCH 268/363] Make `derive_const` usable within libcore again Also make it *only* usable on nightly --- .../src/deriving/bounds.rs | 4 ++ .../src/deriving/clone.rs | 1 + .../src/deriving/cmp/eq.rs | 1 + .../src/deriving/cmp/ord.rs | 1 + .../src/deriving/cmp/partial_eq.rs | 2 + .../src/deriving/cmp/partial_ord.rs | 1 + .../src/deriving/debug.rs | 1 + .../src/deriving/default.rs | 1 + .../src/deriving/generic/mod.rs | 47 +++++++++++++++++-- .../rustc_builtin_macros/src/deriving/hash.rs | 1 + compiler/rustc_expand/src/build.rs | 10 +++- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/macros/mod.rs | 2 +- library/core/src/prelude/v1.rs | 2 +- library/std/src/prelude/v1.rs | 2 +- .../consts/const-eval/auxiliary/stability.rs | 9 ++-- .../const_derives/derive-const-gate.stderr | 1 + 17 files changed, 75 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index a98e9c6d1c7f..dd8f0e46a0e0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -23,6 +23,7 @@ pub(crate) fn expand_deriving_copy( methods: Vec::new(), associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push); @@ -46,6 +47,7 @@ pub(crate) fn expand_deriving_const_param_ty( methods: Vec::new(), associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push); @@ -60,6 +62,7 @@ pub(crate) fn expand_deriving_const_param_ty( methods: Vec::new(), associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push); @@ -83,6 +86,7 @@ pub(crate) fn expand_deriving_unsized_const_param_ty( methods: Vec::new(), associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push); diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 69f8c273797e..3c78f53c5cb0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -87,6 +87,7 @@ pub(crate) fn expand_deriving_clone( }], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand_ext(cx, mitem, item, push, is_simple) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index eca79e4dc489..29d531219a69 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -43,6 +43,7 @@ pub(crate) fn expand_deriving_eq( }], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand_ext(cx, mitem, item, push, true) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 1ed44c20bc61..0e1ecf3118ac 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -34,6 +34,7 @@ pub(crate) fn expand_deriving_ord( }], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index b1d950b8d89d..990835fa2773 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -30,6 +30,7 @@ pub(crate) fn expand_deriving_partial_eq( methods: Vec::new(), associated_types: Vec::new(), is_const: false, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; structural_trait_def.expand(cx, mitem, item, push); @@ -58,6 +59,7 @@ pub(crate) fn expand_deriving_partial_eq( methods, associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 0a076dd670b3..f5d262ece36e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -64,6 +64,7 @@ pub(crate) fn expand_deriving_partial_ord( methods: vec![partial_cmp_def], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 8ab21986e68a..1d63ce7d5fd2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -41,6 +41,7 @@ pub(crate) fn expand_deriving_debug( }], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 1fe567e23f45..b4e2d27fed33 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -51,6 +51,7 @@ pub(crate) fn expand_deriving_default( }], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index c55a9e73e382..b24e55637613 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -181,9 +181,11 @@ use std::{iter, vec}; pub(crate) use StaticFields::*; pub(crate) use SubstructureFields::*; use rustc_ast::ptr::P; +use rustc_ast::token::{IdentIsRaw, LitKind, Token, TokenKind}; +use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenTree}; use rustc_ast::{ - self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, - Generics, Mutability, PatKind, VariantData, + self as ast, AnonConst, AttrArgs, BindingMode, ByRef, DelimArgs, EnumDef, Expr, GenericArg, + GenericParamKind, Generics, Mutability, PatKind, Safety, VariantData, }; use rustc_attr_data_structures::{AttributeKind, ReprPacked}; use rustc_attr_parsing::AttributeParser; @@ -222,6 +224,8 @@ pub(crate) struct TraitDef<'a> { pub associated_types: Vec<(Ident, Ty)>, pub is_const: bool, + + pub is_staged_api_crate: bool, } pub(crate) struct MethodDef<'a> { @@ -784,8 +788,45 @@ impl<'a> TraitDef<'a> { // Create the type of `self`. let path = cx.path_all(self.span, false, vec![type_ident], self_params); let self_type = cx.ty_path(path); + let rustc_const_unstable = + cx.path_ident(self.span, Ident::new(sym::rustc_const_unstable, self.span)); + + let mut attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span),]; + + // Only add `rustc_const_unstable` attributes if `derive_const` is used within libcore/libstd, + // Other crates don't need stability attributes, so adding them is not useful, but libcore needs them + // on all const trait impls. + if self.is_const && self.is_staged_api_crate { + attrs.push( + cx.attr_nested( + rustc_ast::AttrItem { + unsafety: Safety::Default, + path: rustc_const_unstable, + args: AttrArgs::Delimited(DelimArgs { + dspan: DelimSpan::from_single(self.span), + delim: rustc_ast::token::Delimiter::Parenthesis, + tokens: [ + TokenKind::Ident(sym::feature, IdentIsRaw::No), + TokenKind::Eq, + TokenKind::lit(LitKind::Str, sym::derive_const, None), + TokenKind::Comma, + TokenKind::Ident(sym::issue, IdentIsRaw::No), + TokenKind::Eq, + TokenKind::lit(LitKind::Str, sym::derive_const_issue, None), + ] + .into_iter() + .map(|kind| { + TokenTree::Token(Token { kind, span: self.span }, Spacing::Alone) + }) + .collect(), + }), + tokens: None, + }, + self.span, + ), + ) + } - let attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span),]; let opt_trait_ref = Some(trait_ref); cx.item( diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 6e6dbe19e4d1..78534449895c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -41,6 +41,7 @@ pub(crate) fn expand_deriving_hash( }], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; hash_trait_def.expand(cx, mitem, item, push); diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 85683c1a03ff..51d6e43ab672 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -3,8 +3,8 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::literal; use rustc_ast::{ - self as ast, AnonConst, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp, - attr, token, tokenstream, + self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, + UnOp, attr, token, tokenstream, }; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; @@ -766,4 +766,10 @@ impl<'a> ExtCtxt<'a> { span, ) } + + // Builds an attribute fully manually. + pub fn attr_nested(&self, inner: AttrItem, span: Span) -> ast::Attribute { + let g = &self.sess.psess.attr_id_generator; + attr::mk_attr_from_item(g, inner, None, ast::AttrStyle::Outer, span) + } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index bd34055f8513..769ac4f7f22a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -839,6 +839,7 @@ symbols! { derive, derive_coerce_pointee, derive_const, + derive_const_issue: "118304", derive_default_enum, derive_smart_pointer, destruct, diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 1b6dbc2f428f..8ac6ce2242d4 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1615,7 +1615,7 @@ pub(crate) mod builtin { /// See [the reference] for more info. /// /// [the reference]: ../../../reference/attributes/derive.html - #[unstable(feature = "derive_const", issue = "none")] + #[unstable(feature = "derive_const", issue = "118304")] #[rustc_builtin_macro] pub macro derive_const($item:item) { /* compiler built-in */ diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 7b9e04920d51..a4be66b90cab 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -80,7 +80,7 @@ pub use crate::macros::builtin::{ alloc_error_handler, bench, derive, global_allocator, test, test_case, }; -#[unstable(feature = "derive_const", issue = "none")] +#[unstable(feature = "derive_const", issue = "118304")] pub use crate::macros::builtin::derive_const; #[unstable( diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 69f033531535..70c111315565 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -67,7 +67,7 @@ pub use core::prelude::v1::{ alloc_error_handler, bench, derive, global_allocator, test, test_case, }; -#[unstable(feature = "derive_const", issue = "none")] +#[unstable(feature = "derive_const", issue = "118304")] pub use core::prelude::v1::derive_const; // Do not `doc(no_inline)` either. diff --git a/tests/ui/consts/const-eval/auxiliary/stability.rs b/tests/ui/consts/const-eval/auxiliary/stability.rs index e61595518602..48ced3bc51e6 100644 --- a/tests/ui/consts/const-eval/auxiliary/stability.rs +++ b/tests/ui/consts/const-eval/auxiliary/stability.rs @@ -1,10 +1,11 @@ // Crate that exports a const fn. Used for testing cross-crate. -#![crate_type="rlib"] +#![crate_type = "rlib"] #![stable(feature = "rust1", since = "1.0.0")] - #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature="foo", issue = "none")] -pub const fn foo() -> u32 { 42 } +#[rustc_const_unstable(feature = "foo", issue = "none")] +pub const fn foo() -> u32 { + 42 +} diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr index 5bde358001cb..f5d90544411b 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr @@ -4,6 +4,7 @@ error[E0658]: use of unstable library feature `derive_const` LL | #[derive_const(Debug)] | ^^^^^^^^^^^^ | + = note: see issue #118304 for more information = help: add `#![feature(derive_const)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date From 10762d5001f6abe686b14bffb83e618ec8fa2bb6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:17:40 +0000 Subject: [PATCH 269/363] Fix debuginfo-lto-alloc.rs test This should have used build-pass rather than check-pass. --- tests/ui/lto/debuginfo-lto-alloc.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ui/lto/debuginfo-lto-alloc.rs b/tests/ui/lto/debuginfo-lto-alloc.rs index 89043275329d..d6855f8760d5 100644 --- a/tests/ui/lto/debuginfo-lto-alloc.rs +++ b/tests/ui/lto/debuginfo-lto-alloc.rs @@ -8,8 +8,9 @@ // This test reproduces the circumstances that caused the error to appear, and checks // that compilation is successful. -//@ check-pass +//@ build-pass //@ compile-flags: --test -C debuginfo=2 -C lto=fat +//@ no-prefer-dynamic //@ incremental extern crate alloc; From cecf9ead40352f77e2e83765f0f6a796277299ec Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 1 Jul 2025 20:34:45 +0800 Subject: [PATCH 270/363] Add test raw-underscore-lifetime.rs Signed-off-by: xizheyin --- .../raw-underscore-lifetime.rs | 10 ++++++++++ .../raw-underscore-lifetime.stderr | 15 +++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/ui/underscore-lifetime/raw-underscore-lifetime.rs create mode 100644 tests/ui/underscore-lifetime/raw-underscore-lifetime.stderr diff --git a/tests/ui/underscore-lifetime/raw-underscore-lifetime.rs b/tests/ui/underscore-lifetime/raw-underscore-lifetime.rs new file mode 100644 index 000000000000..9ab040f2eab8 --- /dev/null +++ b/tests/ui/underscore-lifetime/raw-underscore-lifetime.rs @@ -0,0 +1,10 @@ +// This test is to ensure that the raw underscore lifetime won't emit two duplicate errors. +// See issue #143152 + +//@ edition: 2021 + +fn f<'r#_>(){} +//~^ ERROR `_` cannot be a raw lifetime +//~| ERROR `'_` cannot be used here [E0637] + +fn main() {} diff --git a/tests/ui/underscore-lifetime/raw-underscore-lifetime.stderr b/tests/ui/underscore-lifetime/raw-underscore-lifetime.stderr new file mode 100644 index 000000000000..39627d8a4763 --- /dev/null +++ b/tests/ui/underscore-lifetime/raw-underscore-lifetime.stderr @@ -0,0 +1,15 @@ +error: `_` cannot be a raw lifetime + --> $DIR/raw-underscore-lifetime.rs:6:6 + | +LL | fn f<'r#_>(){} + | ^^^^ + +error[E0637]: `'_` cannot be used here + --> $DIR/raw-underscore-lifetime.rs:6:6 + | +LL | fn f<'r#_>(){} + | ^^^^ `'_` is a reserved lifetime name + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0637`. From 848d4a5a381ddda172a5629d8050a58388ecb2b9 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 1 Jul 2025 20:49:07 +0800 Subject: [PATCH 271/363] Remove similar errors about raw underscore lifetime Signed-off-by: xizheyin --- compiler/rustc_resolve/src/late.rs | 14 +++++++++++++- .../underscore-lifetime/raw-underscore-lifetime.rs | 1 - .../raw-underscore-lifetime.stderr | 9 +-------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 753b9365cd87..93cec8daa5a4 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2899,9 +2899,21 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } if param.ident.name == kw::UnderscoreLifetime { + // To avoid emitting two similar errors, + // we need to check if the span is a raw underscore lifetime, see issue #143152 + let is_raw_underscore_lifetime = self + .r + .tcx + .sess + .psess + .raw_identifier_spans + .iter() + .any(|span| span == param.span()); + self.r .dcx() - .emit_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span }); + .create_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span }) + .emit_unless(is_raw_underscore_lifetime); // Record lifetime res, so lowering knows there is something fishy. self.record_lifetime_param(param.id, LifetimeRes::Error); continue; diff --git a/tests/ui/underscore-lifetime/raw-underscore-lifetime.rs b/tests/ui/underscore-lifetime/raw-underscore-lifetime.rs index 9ab040f2eab8..874b3d2c48db 100644 --- a/tests/ui/underscore-lifetime/raw-underscore-lifetime.rs +++ b/tests/ui/underscore-lifetime/raw-underscore-lifetime.rs @@ -5,6 +5,5 @@ fn f<'r#_>(){} //~^ ERROR `_` cannot be a raw lifetime -//~| ERROR `'_` cannot be used here [E0637] fn main() {} diff --git a/tests/ui/underscore-lifetime/raw-underscore-lifetime.stderr b/tests/ui/underscore-lifetime/raw-underscore-lifetime.stderr index 39627d8a4763..bdb357a47f4b 100644 --- a/tests/ui/underscore-lifetime/raw-underscore-lifetime.stderr +++ b/tests/ui/underscore-lifetime/raw-underscore-lifetime.stderr @@ -4,12 +4,5 @@ error: `_` cannot be a raw lifetime LL | fn f<'r#_>(){} | ^^^^ -error[E0637]: `'_` cannot be used here - --> $DIR/raw-underscore-lifetime.rs:6:6 - | -LL | fn f<'r#_>(){} - | ^^^^ `'_` is a reserved lifetime name +error: aborting due to 1 previous error -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0637`. From 96171dc78f23430a28ed8eb6a3879758d3d0d3d5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 25 Jun 2025 16:03:52 +0000 Subject: [PATCH 272/363] Check if type has coroutines before visiting --- .../rustc_trait_selection/src/solve/fulfill.rs | 11 +++++++---- compiler/rustc_type_ir/src/flags.rs | 16 ++++++++++++---- compiler/rustc_type_ir/src/visit.rs | 4 ++++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index d56042a5ca2a..72770535b3e8 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -10,7 +10,8 @@ use rustc_infer::traits::{ FromSolverError, PredicateObligation, PredicateObligations, TraitEngine, }; use rustc_middle::ty::{ - self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode, + self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + TypingMode, }; use rustc_next_trait_solver::delegate::SolverDelegate as _; use rustc_next_trait_solver::solve::{ @@ -332,10 +333,12 @@ impl<'tcx> TypeVisitor> for StalledOnCoroutines<'tcx> { if let ty::CoroutineWitness(def_id, _) = *ty.kind() && def_id.as_local().is_some_and(|def_id| self.stalled_generators.contains(&def_id)) { - return ControlFlow::Break(()); + ControlFlow::Break(()) + } else if ty.has_coroutines() { + ty.super_visit_with(self) + } else { + ControlFlow::Continue(()) } - - ty.super_visit_with(self) } } diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index a231908f874c..d7b9e0ca340a 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -130,6 +130,12 @@ bitflags::bitflags! { /// Does this have any binders with bound vars (e.g. that need to be anonymized)? const HAS_BINDER_VARS = 1 << 23; + + /// Does this type have any coroutine witnesses in it? + // FIXME: This should probably be changed to track whether the type has any + // *coroutines* in it, though this will happen if we remove coroutine witnesses + // altogether. + const HAS_TY_CORO = 1 << 24; } } @@ -240,10 +246,12 @@ impl FlagComputation { self.add_flags(TypeFlags::HAS_TY_PARAM); } - ty::Closure(_, args) - | ty::Coroutine(_, args) - | ty::CoroutineClosure(_, args) - | ty::CoroutineWitness(_, args) => { + ty::Closure(_, args) | ty::Coroutine(_, args) | ty::CoroutineClosure(_, args) => { + self.add_args(args.as_slice()); + } + + ty::CoroutineWitness(_, args) => { + self.add_flags(TypeFlags::HAS_TY_CORO); self.add_args(args.as_slice()); } diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index a96ac97f785d..5104484e9c43 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -269,6 +269,10 @@ pub trait TypeVisitableExt: TypeVisitable { self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) } + fn has_coroutines(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_CORO) + } + fn references_error(&self) -> bool { self.has_type_flags(TypeFlags::HAS_ERROR) } From 72bc11d14688599fbcaedf2be9175aa374e1c0d9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 29 May 2025 12:34:24 +0000 Subject: [PATCH 273/363] Unstall obligations by looking for coroutines in old solver --- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 51 +++++-------------- .../src/solve/fulfill.rs | 16 +++--- .../src/traits/fulfill.rs | 39 +++++++++++--- 3 files changed, 52 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index af1fc045ac87..0b3d50ff2199 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -625,50 +625,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // trigger query cycle ICEs, as doing so requires MIR. self.select_obligations_where_possible(|_| {}); - let coroutines = std::mem::take(&mut *self.deferred_coroutine_interiors.borrow_mut()); - debug!(?coroutines); + let ty::TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode() + else { + bug!(); + }; - let mut obligations = vec![]; - - if !self.next_trait_solver() { - for &(coroutine_def_id, interior) in coroutines.iter() { - debug!(?coroutine_def_id); - - // Create the `CoroutineWitness` type that we will unify with `interior`. - let args = ty::GenericArgs::identity_for_item( - self.tcx, - self.tcx.typeck_root_def_id(coroutine_def_id.to_def_id()), - ); - let witness = - Ty::new_coroutine_witness(self.tcx, coroutine_def_id.to_def_id(), args); - - // Unify `interior` with `witness` and collect all the resulting obligations. - let span = self.tcx.hir_body_owned_by(coroutine_def_id).value.span; - let ty::Infer(ty::InferTy::TyVar(_)) = interior.kind() else { - span_bug!(span, "coroutine interior witness not infer: {:?}", interior.kind()) - }; - let ok = self - .at(&self.misc(span), self.param_env) - // Will never define opaque types, as all we do is instantiate a type variable. - .eq(DefineOpaqueTypes::Yes, interior, witness) - .expect("Failed to unify coroutine interior type"); - - obligations.extend(ok.obligations); - } - } - - if !coroutines.is_empty() { - obligations.extend( + if defining_opaque_types_and_generators + .iter() + .any(|def_id| self.tcx.is_coroutine(def_id.to_def_id())) + { + self.typeck_results.borrow_mut().coroutine_stalled_predicates.extend( self.fulfillment_cx .borrow_mut() - .drain_stalled_obligations_for_coroutines(&self.infcx), + .drain_stalled_obligations_for_coroutines(&self.infcx) + .into_iter() + .map(|o| (o.predicate, o.cause)), ); } - - self.typeck_results - .borrow_mut() - .coroutine_stalled_predicates - .extend(obligations.into_iter().map(|o| (o.predicate, o.cause))); } #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 72770535b3e8..3ce0f0255124 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -255,7 +255,7 @@ where &mut self, infcx: &InferCtxt<'tcx>, ) -> PredicateObligations<'tcx> { - let stalled_generators = match infcx.typing_mode() { + let stalled_coroutines = match infcx.typing_mode() { TypingMode::Analysis { defining_opaque_types_and_generators } => { defining_opaque_types_and_generators } @@ -265,7 +265,7 @@ where | TypingMode::PostAnalysis => return Default::default(), }; - if stalled_generators.is_empty() { + if stalled_coroutines.is_empty() { return Default::default(); } @@ -276,7 +276,7 @@ where .visit_proof_tree( obl.as_goal(), &mut StalledOnCoroutines { - stalled_generators, + stalled_coroutines, span: obl.cause.span, cache: Default::default(), }, @@ -298,10 +298,10 @@ where /// /// This function can be also return false positives, which will lead to poor diagnostics /// so we want to keep this visitor *precise* too. -struct StalledOnCoroutines<'tcx> { - stalled_generators: &'tcx ty::List, - span: Span, - cache: DelayedSet>, +pub struct StalledOnCoroutines<'tcx> { + pub stalled_coroutines: &'tcx ty::List, + pub span: Span, + pub cache: DelayedSet>, } impl<'tcx> inspect::ProofTreeVisitor<'tcx> for StalledOnCoroutines<'tcx> { @@ -331,7 +331,7 @@ impl<'tcx> TypeVisitor> for StalledOnCoroutines<'tcx> { } if let ty::CoroutineWitness(def_id, _) = *ty.kind() - && def_id.as_local().is_some_and(|def_id| self.stalled_generators.contains(&def_id)) + && def_id.as_local().is_some_and(|def_id| self.stalled_coroutines.contains(&def_id)) { ControlFlow::Break(()) } else if ty.has_coroutines() { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 2b5a41ef5a71..c6c68b1c4016 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -3,6 +3,7 @@ use std::marker::PhantomData; use rustc_data_structures::obligation_forest::{ Error, ForestObligation, ObligationForest, ObligationProcessor, Outcome, ProcessResult, }; +use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::traits::{ FromSolverError, PolyTraitObligation, PredicateObligations, ProjectionCacheKey, SelectionError, @@ -12,8 +13,9 @@ use rustc_middle::bug; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ - self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode, may_use_unstable_feature, + self, Binder, Const, GenericArgsRef, TypeVisitable, TypeVisitableExt, TypingMode, }; +use rustc_span::DUMMY_SP; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, debug_span, instrument}; @@ -26,6 +28,7 @@ use super::{ }; use crate::error_reporting::InferCtxtErrorExt; use crate::infer::{InferCtxt, TyOrConstInferVar}; +use crate::solve::StalledOnCoroutines; use crate::traits::normalize::normalize_with_depth_to; use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt; @@ -168,8 +171,25 @@ where &mut self, infcx: &InferCtxt<'tcx>, ) -> PredicateObligations<'tcx> { - let mut processor = - DrainProcessor { removed_predicates: PredicateObligations::new(), infcx }; + let stalled_coroutines = match infcx.typing_mode() { + TypingMode::Analysis { defining_opaque_types_and_generators } => { + defining_opaque_types_and_generators + } + TypingMode::Coherence + | TypingMode::Borrowck { defining_opaque_types: _ } + | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } + | TypingMode::PostAnalysis => return Default::default(), + }; + + if stalled_coroutines.is_empty() { + return Default::default(); + } + + let mut processor = DrainProcessor { + infcx, + removed_predicates: PredicateObligations::new(), + stalled_coroutines, + }; let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut processor); assert!(outcome.errors.is_empty()); return processor.removed_predicates; @@ -177,6 +197,7 @@ where struct DrainProcessor<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, removed_predicates: PredicateObligations<'tcx>, + stalled_coroutines: &'tcx ty::List, } impl<'tcx> ObligationProcessor for DrainProcessor<'_, 'tcx> { @@ -185,10 +206,14 @@ where type OUT = Outcome; fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool { - pending_obligation - .stalled_on - .iter() - .any(|&var| self.infcx.ty_or_const_infer_var_changed(var)) + self.infcx + .resolve_vars_if_possible(pending_obligation.obligation.predicate) + .visit_with(&mut StalledOnCoroutines { + stalled_coroutines: self.stalled_coroutines, + span: DUMMY_SP, + cache: Default::default(), + }) + .is_break() } fn process_obligation( From 216cdb7b22b637cef75b7225c642cb7587192643 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 29 May 2025 12:34:50 +0000 Subject: [PATCH 274/363] Eagerly unify coroutine witness in old solver --- compiler/rustc_hir_typeck/src/closure.rs | 11 +- .../rustc_hir_typeck/src/typeck_root_ctxt.rs | 3 - compiler/rustc_middle/src/ty/context.rs | 18 ++- compiler/rustc_trait_selection/src/infer.rs | 4 +- compiler/rustc_trait_selection/src/solve.rs | 2 +- .../src/traits/fulfill.rs | 1 + .../src/traits/select/candidate_assembly.rs | 33 +++-- .../src/traits/select/mod.rs | 15 ++- .../async-closures/def-path.stderr | 4 +- tests/ui/coroutine/clone-impl.rs | 25 ++-- tests/ui/coroutine/clone-impl.stderr | 113 +++++++----------- .../print/coroutine-print-verbose-3.stderr | 2 +- tests/ui/impl-trait/issues/issue-55872-3.rs | 1 + .../ui/impl-trait/issues/issue-55872-3.stderr | 16 ++- 14 files changed, 125 insertions(+), 123 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 459c0498d500..a413f805873d 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -161,16 +161,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Resume type defaults to `()` if the coroutine has no argument. let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit); - // In the new solver, we can just instantiate this eagerly - // with the witness. This will ensure that goals that don't need - // to stall on interior types will get processed eagerly. - let interior = if self.next_trait_solver() { - Ty::new_coroutine_witness(tcx, expr_def_id.to_def_id(), parent_args) - } else { - self.next_ty_var(expr_span) - }; - - self.deferred_coroutine_interiors.borrow_mut().push((expr_def_id, interior)); + let interior = Ty::new_coroutine_witness(tcx, expr_def_id.to_def_id(), parent_args); // Coroutines that come from coroutine closures have not yet determined // their kind ty, so make a fresh infer var which will be constrained diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 26be5fc6d190..9f4ab8ca5d41 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -63,8 +63,6 @@ pub(crate) struct TypeckRootCtxt<'tcx> { pub(super) deferred_asm_checks: RefCell, HirId)>>, - pub(super) deferred_coroutine_interiors: RefCell)>>, - pub(super) deferred_repeat_expr_checks: RefCell, Ty<'tcx>, ty::Const<'tcx>)>>, @@ -103,7 +101,6 @@ impl<'tcx> TypeckRootCtxt<'tcx> { deferred_cast_checks: RefCell::new(Vec::new()), deferred_transmute_checks: RefCell::new(Vec::new()), deferred_asm_checks: RefCell::new(Vec::new()), - deferred_coroutine_interiors: RefCell::new(Vec::new()), deferred_repeat_expr_checks: RefCell::new(Vec::new()), diverging_type_vars: RefCell::new(Default::default()), infer_var_info: RefCell::new(Default::default()), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 915b062417f2..684d13e147e8 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -714,17 +714,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self, defining_anchor: Self::LocalDefId, ) -> Self::LocalDefIds { - if self.next_trait_solver_globally() { - let coroutines_defined_by = self - .nested_bodies_within(defining_anchor) - .iter() - .filter(|def_id| self.is_coroutine(def_id.to_def_id())); - self.mk_local_def_ids_from_iter( - self.opaque_types_defined_by(defining_anchor).iter().chain(coroutines_defined_by), - ) - } else { - self.opaque_types_defined_by(defining_anchor) - } + let coroutines_defined_by = self + .nested_bodies_within(defining_anchor) + .iter() + .filter(|def_id| self.is_coroutine(def_id.to_def_id())); + self.mk_local_def_ids_from_iter( + self.opaque_types_defined_by(defining_anchor).iter().chain(coroutines_defined_by), + ) } } diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 0118321befbb..7c6b7b14ecbe 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -33,8 +33,8 @@ impl<'tcx> InferCtxt<'tcx> { let ty = self.resolve_vars_if_possible(ty); // FIXME(#132279): This should be removed as it causes us to incorrectly - // handle opaques in their defining scope. - if !self.next_trait_solver() && !(param_env, ty).has_infer() { + // handle opaques in their defining scope, and stalled coroutines. + if !self.next_trait_solver() && !(param_env, ty).has_infer() && !ty.has_coroutines() { return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty); } diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index 5a5d16167d28..f58961683a9c 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -7,7 +7,7 @@ mod normalize; mod select; pub(crate) use delegate::SolverDelegate; -pub use fulfill::{FulfillmentCtxt, NextSolverError}; +pub use fulfill::{FulfillmentCtxt, NextSolverError, StalledOnCoroutines}; pub(crate) use normalize::deeply_normalize_for_diagnostics; pub use normalize::{ deeply_normalize, deeply_normalize_with_skipped_universes, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index c6c68b1c4016..e35f89358e9f 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ self, Binder, Const, GenericArgsRef, TypeVisitable, TypeVisitableExt, TypingMode, + may_use_unstable_feature, }; use rustc_span::DUMMY_SP; use thin_vec::{ThinVec, thin_vec}; diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index cc188a280aa6..2c7089507a89 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -842,6 +842,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::CoroutineWitness(def_id, _) => { + if self.should_stall_coroutine_witness(def_id) { + candidates.ambiguous = true; + } else { + candidates.vec.push(AutoImplCandidate); + } + } + ty::Bool | ty::Char | ty::Int(_) @@ -861,7 +869,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Coroutine(..) | ty::Never | ty::Tuple(_) - | ty::CoroutineWitness(..) | ty::UnsafeBinder(_) => { // Only consider auto impls of unsafe traits when there are // no unsafe fields. @@ -1119,12 +1126,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match *self_ty.kind() { // These impls are built-in because we cannot express sufficiently // generic impls in libcore. - ty::FnDef(..) - | ty::FnPtr(..) - | ty::Error(_) - | ty::Tuple(..) - | ty::CoroutineWitness(..) - | ty::Pat(..) => { + ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) | ty::Tuple(..) | ty::Pat(..) => { candidates.vec.push(BuiltinCandidate); } @@ -1192,6 +1194,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::CoroutineWitness(coroutine_def_id, _) => { + if self.should_stall_coroutine_witness(coroutine_def_id) { + candidates.ambiguous = true; + } else { + candidates.vec.push(SizedCandidate); + } + } + // Fallback to whatever user-defined impls or param-env clauses exist in this case. ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {} @@ -1229,7 +1239,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Char | ty::Ref(..) | ty::Coroutine(..) - | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) | ty::CoroutineClosure(..) @@ -1238,6 +1247,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.vec.push(SizedCandidate); } + ty::CoroutineWitness(coroutine_def_id, _) => { + if self.should_stall_coroutine_witness(coroutine_def_id) { + candidates.ambiguous = true; + } else { + candidates.vec.push(SizedCandidate); + } + } + // Conditionally `Sized`. ty::Tuple(..) | ty::Pat(..) | ty::Adt(..) | ty::UnsafeBinder(_) => { candidates.vec.push(SizedCandidate); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 10bcf861d35b..d0b88d2fb18f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1512,7 +1512,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { defining_opaque_types_and_generators: defining_opaque_types, } | TypingMode::Borrowck { defining_opaque_types } => { - defining_opaque_types.is_empty() || !pred.has_opaque_types() + defining_opaque_types.is_empty() + || (!pred.has_opaque_types() && !pred.has_coroutines()) } // The hidden types of `defined_opaque_types` is not local to the current // inference context, so we can freely move this to the global cache. @@ -2811,6 +2812,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligations } + + fn should_stall_coroutine_witness(&self, def_id: DefId) -> bool { + match self.infcx.typing_mode() { + TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators } => { + def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id)) + } + TypingMode::Coherence + | TypingMode::PostAnalysis + | TypingMode::Borrowck { defining_opaque_types: _ } + | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => false, + } + } } impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { diff --git a/tests/ui/async-await/async-closures/def-path.stderr b/tests/ui/async-await/async-closures/def-path.stderr index b50e353b6988..58a5b0b79c4e 100644 --- a/tests/ui/async-await/async-closures/def-path.stderr +++ b/tests/ui/async-await/async-closures/def-path.stderr @@ -5,11 +5,11 @@ LL | let x = async || {}; | -- the expected `async` closure body LL | LL | let () = x(); - | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?5t}` + | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?15t resume_ty=ResumeTy yield_ty=() return_ty=() witness={main::{closure#0}::{closure#0}}}` | | | expected `async` closure body, found `()` | - = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?5t}` + = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?15t resume_ty=ResumeTy yield_ty=() return_ty=() witness={main::{closure#0}::{closure#0}}}` found unit type `()` error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/clone-impl.rs b/tests/ui/coroutine/clone-impl.rs index b07fad18aee1..e528f031d526 100644 --- a/tests/ui/coroutine/clone-impl.rs +++ b/tests/ui/coroutine/clone-impl.rs @@ -38,39 +38,40 @@ fn test2() { check_clone(&gen_copy_1); } -fn test3() { +fn test3_upvars() { let clonable_0: Vec = Vec::new(); let gen_clone_0 = #[coroutine] move || { - let v = vec!['a']; - yield; - drop(v); drop(clonable_0); }; check_copy(&gen_clone_0); //~^ ERROR the trait bound `Vec: Copy` is not satisfied - //~| ERROR the trait bound `Vec: Copy` is not satisfied check_clone(&gen_clone_0); } +fn test3_witness() { + let gen_clone_1 = #[coroutine] + move || { + let v = vec!['a']; + yield; + drop(v); + }; + check_copy(&gen_clone_1); + //~^ ERROR the trait bound `Vec: Copy` is not satisfied + check_clone(&gen_clone_1); +} + fn test4() { let clonable_1: Vec = Vec::new(); let gen_clone_1 = #[coroutine] move || { - let v = vec!['a']; - /* - let n = NonClone; - drop(n); - */ yield; let n = NonClone; drop(n); - drop(v); drop(clonable_1); }; check_copy(&gen_clone_1); //~^ ERROR the trait bound `Vec: Copy` is not satisfied - //~| ERROR the trait bound `Vec: Copy` is not satisfied check_clone(&gen_clone_1); } diff --git a/tests/ui/coroutine/clone-impl.stderr b/tests/ui/coroutine/clone-impl.stderr index ed933fe784ed..714e5aa3d9e3 100644 --- a/tests/ui/coroutine/clone-impl.stderr +++ b/tests/ui/coroutine/clone-impl.stderr @@ -1,104 +1,59 @@ error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}` - --> $DIR/clone-impl.rs:50:5 + --> $DIR/clone-impl.rs:47:16 | LL | move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}` ... LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec` + | ^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:48:14 + --> $DIR/clone-impl.rs:45:14 | LL | drop(clonable_0); | ^^^^^^^^^^ has type `Vec` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:90:18 + --> $DIR/clone-impl.rs:91:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}` - --> $DIR/clone-impl.rs:50:5 +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}` + --> $DIR/clone-impl.rs:73:16 | LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}` -... -LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec` - | -note: coroutine does not implement `Copy` as this value is used across a yield - --> $DIR/clone-impl.rs:46:9 - | -LL | let v = vec!['a']; - | - has type `Vec` which does not implement `Copy` -LL | yield; - | ^^^^^ yield occurs here, with `v` maybe used later -note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:90:18 - | -LL | fn check_copy(_x: &T) {} - | ^^^^ required by this bound in `check_copy` - -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}` - --> $DIR/clone-impl.rs:71:5 - | -LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}` + | ------- within this `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}` ... LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`, the trait `Copy` is not implemented for `Vec` + | ^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}`, the trait `Copy` is not implemented for `Vec` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:69:14 + --> $DIR/clone-impl.rs:71:14 | LL | drop(clonable_1); | ^^^^^^^^^^ has type `Vec` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:90:18 + --> $DIR/clone-impl.rs:91:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}` - --> $DIR/clone-impl.rs:71:5 +error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` + --> $DIR/clone-impl.rs:85:16 | LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}` -... -LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`, the trait `Copy` is not implemented for `Vec` - | -note: coroutine does not implement `Copy` as this value is used across a yield - --> $DIR/clone-impl.rs:65:9 - | -LL | let v = vec!['a']; - | - has type `Vec` which does not implement `Copy` -... -LL | yield; - | ^^^^^ yield occurs here, with `v` maybe used later -note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:90:18 - | -LL | fn check_copy(_x: &T) {} - | ^^^^ required by this bound in `check_copy` - -error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}` - --> $DIR/clone-impl.rs:84:5 - | -LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}` + | ------- within this `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` ... LL | check_copy(&gen_non_clone); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`, the trait `Copy` is not implemented for `NonClone` + | ^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`, the trait `Copy` is not implemented for `NonClone` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:82:14 + --> $DIR/clone-impl.rs:83:14 | LL | drop(non_clonable); | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:90:18 + --> $DIR/clone-impl.rs:91:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` @@ -108,22 +63,22 @@ LL + #[derive(Copy)] LL | struct NonClone; | -error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}` - --> $DIR/clone-impl.rs:86:5 +error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` + --> $DIR/clone-impl.rs:87:17 | LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}` + | ------- within this `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` ... LL | check_clone(&gen_non_clone); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`, the trait `Clone` is not implemented for `NonClone` + | ^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`, the trait `Clone` is not implemented for `NonClone` | note: captured value does not implement `Clone` - --> $DIR/clone-impl.rs:82:14 + --> $DIR/clone-impl.rs:83:14 | LL | drop(non_clonable); | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Clone` note: required by a bound in `check_clone` - --> $DIR/clone-impl.rs:91:19 + --> $DIR/clone-impl.rs:92:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` @@ -133,6 +88,28 @@ LL + #[derive(Clone)] LL | struct NonClone; | -error: aborting due to 6 previous errors +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}` + --> $DIR/clone-impl.rs:59:5 + | +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}` +... +LL | check_copy(&gen_clone_1); + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}`, the trait `Copy` is not implemented for `Vec` + | +note: coroutine does not implement `Copy` as this value is used across a yield + --> $DIR/clone-impl.rs:56:9 + | +LL | let v = vec!['a']; + | - has type `Vec` which does not implement `Copy` +LL | yield; + | ^^^^^ yield occurs here, with `v` maybe used later +note: required by a bound in `check_copy` + --> $DIR/clone-impl.rs:91:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr index 2f9f20cf1ffb..4a1e5b078a80 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr @@ -11,7 +11,7 @@ LL | | }; | |_____^ expected `()`, found coroutine | = note: expected unit type `()` - found coroutine `{main::{closure#0} upvar_tys=?4t resume_ty=() yield_ty=i32 return_ty=&'?1 str witness=?6t}` + found coroutine `{main::{closure#0} upvar_tys=?4t resume_ty=() yield_ty=i32 return_ty=&'?1 str witness={main::{closure#0}}}` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-55872-3.rs b/tests/ui/impl-trait/issues/issue-55872-3.rs index 698e7f362341..763b4b9fd32d 100644 --- a/tests/ui/impl-trait/issues/issue-55872-3.rs +++ b/tests/ui/impl-trait/issues/issue-55872-3.rs @@ -14,6 +14,7 @@ impl Bar for S { fn foo() -> Self::E { //~^ ERROR : Copy` is not satisfied [E0277] //~| ERROR type parameter `T` is part of concrete type + //~| ERROR type parameter `T` is part of concrete type async {} } } diff --git a/tests/ui/impl-trait/issues/issue-55872-3.stderr b/tests/ui/impl-trait/issues/issue-55872-3.stderr index 3281dcc3501d..ce2dd7f02b4c 100644 --- a/tests/ui/impl-trait/issues/issue-55872-3.stderr +++ b/tests/ui/impl-trait/issues/issue-55872-3.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}: Copy` is not satisfied +error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}: Copy` is not satisfied --> $DIR/issue-55872-3.rs:14:20 | LL | fn foo() -> Self::E { - | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}` + | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}` ... LL | async {} - | -------- return type was inferred to be `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}` here + | -------- return type was inferred to be `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}` here error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias --> $DIR/issue-55872-3.rs:14:20 @@ -13,6 +13,14 @@ error: type parameter `T` is part of concrete type but not used in parameter lis LL | fn foo() -> Self::E { | ^^^^^^^ -error: aborting due to 2 previous errors +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/issue-55872-3.rs:14:20 + | +LL | fn foo() -> Self::E { + | ^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. From 68b415a0c4cfa054f275424db770d08227c09099 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Jul 2025 10:20:25 +0000 Subject: [PATCH 275/363] Make slices `[const] PartialEq` --- library/core/src/cmp.rs | 3 ++- library/core/src/cmp/bytewise.rs | 8 +++++-- library/core/src/intrinsics/mod.rs | 1 + library/core/src/lib.rs | 2 ++ library/core/src/slice/cmp.rs | 22 +++++++++++++------ library/core/src/str/traits.rs | 3 ++- tests/ui/consts/const-compare-bytes-ub.rs | 2 +- tests/ui/consts/const-compare-bytes.rs | 2 +- .../traits/const-traits/const-impl-trait.rs | 2 +- .../match-non-const-eq.gated.stderr | 12 ---------- .../traits/const-traits/match-non-const-eq.rs | 9 ++++---- .../match-non-const-eq.stock.stderr | 22 +++++++++++++++---- 12 files changed, 54 insertions(+), 34 deletions(-) delete mode 100644 tests/ui/traits/const-traits/match-non-const-eq.gated.stderr diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 03b120fbf0c3..6419ae991135 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -381,7 +381,8 @@ pub struct AssertParamIsEq { /// /// assert_eq!(2.cmp(&1), Ordering::Greater); /// ``` -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +#[derive(Clone, Copy, Eq, PartialOrd, Ord, Debug, Hash)] +#[derive_const(PartialEq)] #[stable(feature = "rust1", since = "1.0.0")] // This is a lang item only so that `BinOp::Cmp` in MIR can return it. // It has no special behavior, but does require that the three variants diff --git a/library/core/src/cmp/bytewise.rs b/library/core/src/cmp/bytewise.rs index a06a5227fe28..7d61c9345ecf 100644 --- a/library/core/src/cmp/bytewise.rs +++ b/library/core/src/cmp/bytewise.rs @@ -17,11 +17,15 @@ use crate::num::NonZero; /// - Neither `Self` nor `Rhs` have provenance, so integer comparisons are correct. /// - `>::{eq,ne}` are equivalent to comparing the bytes. #[rustc_specialization_trait] -pub(crate) unsafe trait BytewiseEq: PartialEq + Sized {} +#[const_trait] +pub(crate) unsafe trait BytewiseEq: + ~const PartialEq + Sized +{ +} macro_rules! is_bytewise_comparable { ($($t:ty),+ $(,)?) => {$( - unsafe impl BytewiseEq for $t {} + unsafe impl const BytewiseEq for $t {} )+}; } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 1ece3d9bd5e4..b11972600fa4 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2208,6 +2208,7 @@ pub const unsafe fn raw_eq(a: &T, b: &T) -> bool; /// [valid]: crate::ptr#safety #[rustc_nounwind] #[rustc_intrinsic] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] pub const unsafe fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32; /// See documentation of [`std::hint::black_box`] for details. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 2f701171505c..fedc4dada203 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -103,6 +103,7 @@ #![feature(cfg_select)] #![feature(cfg_target_has_reliable_f16_f128)] #![feature(const_carrying_mul_add)] +#![feature(const_cmp)] #![feature(const_destruct)] #![feature(const_eval_select)] #![feature(core_intrinsics)] @@ -146,6 +147,7 @@ #![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] +#![feature(derive_const)] #![feature(doc_cfg)] #![feature(doc_cfg_hide)] #![feature(doc_notable_trait)] diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 5ce72b46eee3..1eda8bc1bec4 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -8,9 +8,10 @@ use crate::num::NonZero; use crate::ops::ControlFlow; #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<[U]> for [T] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialEq<[U]> for [T] where - T: PartialEq, + T: ~const PartialEq, { fn eq(&self, other: &[U]) -> bool { SlicePartialEq::equal(self, other) @@ -94,6 +95,8 @@ impl PartialOrd for [T] { #[doc(hidden)] // intermediate trait for specialization of slice's PartialEq +#[const_trait] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] trait SlicePartialEq { fn equal(&self, other: &[B]) -> bool; @@ -103,9 +106,10 @@ trait SlicePartialEq { } // Generic slice equality -impl SlicePartialEq for [A] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const SlicePartialEq for [A] where - A: PartialEq, + A: ~const PartialEq, { default fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { @@ -115,11 +119,14 @@ where // Implemented as explicit indexing rather // than zipped iterators for performance reasons. // See PR https://github.com/rust-lang/rust/pull/116846 - for idx in 0..self.len() { + // FIXME(const_hack): make this a `for idx in 0..self.len()` loop. + let mut idx = 0; + while idx < self.len() { // bound checks are optimized away if self[idx] != other[idx] { return false; } + idx += 1; } true @@ -128,9 +135,10 @@ where // When each element can be compared byte-wise, we can compare all the bytes // from the whole size in one call to the intrinsics. -impl SlicePartialEq for [A] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const SlicePartialEq for [A] where - A: BytewiseEq, + A: ~const BytewiseEq, { fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 42ffc591b5bb..d0f2b9226bf6 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -23,7 +23,8 @@ impl Ord for str { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for str { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialEq for str { #[inline] fn eq(&self, other: &str) -> bool { self.as_bytes() == other.as_bytes() diff --git a/tests/ui/consts/const-compare-bytes-ub.rs b/tests/ui/consts/const-compare-bytes-ub.rs index 0bc8585a4eed..7e3df92a2bf5 100644 --- a/tests/ui/consts/const-compare-bytes-ub.rs +++ b/tests/ui/consts/const-compare-bytes-ub.rs @@ -1,6 +1,6 @@ //@ check-fail -#![feature(core_intrinsics)] +#![feature(core_intrinsics, const_cmp)] use std::intrinsics::compare_bytes; use std::mem::MaybeUninit; diff --git a/tests/ui/consts/const-compare-bytes.rs b/tests/ui/consts/const-compare-bytes.rs index cd5cdfd0400e..9563375555cf 100644 --- a/tests/ui/consts/const-compare-bytes.rs +++ b/tests/ui/consts/const-compare-bytes.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(core_intrinsics)] +#![feature(core_intrinsics, const_cmp)] use std::intrinsics::compare_bytes; fn main() { diff --git a/tests/ui/traits/const-traits/const-impl-trait.rs b/tests/ui/traits/const-traits/const-impl-trait.rs index dc960422a4a4..da28d9a47c31 100644 --- a/tests/ui/traits/const-traits/const-impl-trait.rs +++ b/tests/ui/traits/const-traits/const-impl-trait.rs @@ -1,7 +1,7 @@ //@ compile-flags: -Znext-solver //@ known-bug: #110395 -// Broken until we have `const PartialEq` impl in stdlib +// Broken until `(): const PartialEq` #![allow(incomplete_features)] #![feature(const_trait_impl, const_cmp, const_destruct)] diff --git a/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr b/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr deleted file mode 100644 index 89e59e5db6ed..000000000000 --- a/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0015]: cannot match on `str` in constant functions - --> $DIR/match-non-const-eq.rs:7:9 - | -LL | "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in const contexts - | ^^^ - | - = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/match-non-const-eq.rs b/tests/ui/traits/const-traits/match-non-const-eq.rs index 73f8af86bd05..03adb8dc5a4e 100644 --- a/tests/ui/traits/const-traits/match-non-const-eq.rs +++ b/tests/ui/traits/const-traits/match-non-const-eq.rs @@ -1,11 +1,12 @@ -//@ known-bug: #110395 //@ revisions: stock gated -#![cfg_attr(gated, feature(const_trait_impl))] +#![cfg_attr(gated, feature(const_trait_impl, const_cmp))] +//@[gated] check-pass const fn foo(input: &'static str) { match input { - "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in const contexts - //FIXME ~^ ERROR cannot match on `str` in constant functions + "a" => (), + //[stock]~^ ERROR cannot match on `str` in constant functions + //[stock]~| ERROR `PartialEq` is not yet stable as a const trait _ => (), } } diff --git a/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr index 89e59e5db6ed..5b662447bde1 100644 --- a/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr +++ b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr @@ -1,12 +1,26 @@ -error[E0015]: cannot match on `str` in constant functions +error[E0658]: cannot match on `str` in constant functions --> $DIR/match-non-const-eq.rs:7:9 | -LL | "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in const contexts +LL | "a" => (), | ^^^ | = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: see issue #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 -error: aborting due to 1 previous error +error: `PartialEq` is not yet stable as a const trait + --> $DIR/match-non-const-eq.rs:7:9 + | +LL | "a" => (), + | ^^^ + | +help: add `#![feature(const_cmp)]` to the crate attributes to enable + | +LL + #![feature(const_cmp)] + | -For more information about this error, try `rustc --explain E0015`. +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. From c37524403827525ed3d7a359b62d7231a80a5992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 8 Jul 2025 18:45:11 +0000 Subject: [PATCH 276/363] Add test for `default_field_values` and `const_default` Add a test showing `#![feature(default_field_values)]` using `#[const_trait] trait Default` (`#![feature(const_default)]` + `#![feature(const_trait_impl)]`). --- .../const-trait-default-field-value.rs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tests/ui/structs/default-field-values/const-trait-default-field-value.rs diff --git a/tests/ui/structs/default-field-values/const-trait-default-field-value.rs b/tests/ui/structs/default-field-values/const-trait-default-field-value.rs new file mode 100644 index 000000000000..60c22efabc4d --- /dev/null +++ b/tests/ui/structs/default-field-values/const-trait-default-field-value.rs @@ -0,0 +1,37 @@ +//@ check-pass + +// Ensure that `default_field_values` and `const_default` interact properly. + +#![feature(const_default)] +#![feature(const_trait_impl)] +#![feature(default_field_values)] +#![feature(derive_const)] + +#[derive(PartialEq, Eq, Debug)] +#[derive_const(Default)] +struct S { + r: Option = as Default>::default(), + s: String = String::default(), + o: Option = Option::::default(), + p: std::marker::PhantomData<()> = std::marker::PhantomData::default(), + q: Option = as Default>::default(), + t: Option = Option::default(), + v: Option = const { Option::default() }, +} + +const _: S = S { .. }; +const _: S = const { S { .. } }; +const _: S = S::default(); +const _: S = const { S::default() }; + +fn main() { + let s = S { .. }; + assert_eq!(s.r, None); + assert_eq!(&s.s, ""); + assert_eq!(s.o, None); + assert_eq!(s.p, std::marker::PhantomData); + assert_eq!(s.q, None); + assert_eq!(s.t, None); + assert_eq!(s.v, None); + assert_eq!(s, S::default()); +} From 12eedafc38b1d3af02c9c15333d0ba2f1aee1253 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 18 Jun 2025 12:51:47 +0000 Subject: [PATCH 277/363] Report the range of uninit bytes in CTFE errors --- .../rustc_const_eval/src/interpret/validity.rs | 2 +- .../rustc_middle/src/mir/interpret/allocation.rs | 7 +++++-- .../libc_pthread_cond_double_destroy.rs | 2 +- .../libc_pthread_cond_double_destroy.stderr | 9 ++++++++- .../libc_pthread_condattr_double_destroy.rs | 2 +- .../libc_pthread_condattr_double_destroy.stderr | 7 ++++++- .../libc_pthread_mutex_double_destroy.rs | 2 +- .../libc_pthread_mutex_double_destroy.stderr | 9 ++++++++- .../libc_pthread_mutexattr_double_destroy.rs | 2 +- .../libc_pthread_mutexattr_double_destroy.stderr | 7 ++++++- .../libc_pthread_rwlock_double_destroy.rs | 2 +- .../libc_pthread_rwlock_double_destroy.stderr | 10 +++++++++- .../arg_inplace_observe_after.stderr | 7 ++++++- .../arg_inplace_observe_during.none.stderr | 7 ++++++- .../return_pointer_aliasing_read.none.stderr | 7 ++++++- .../return_pointer_on_unwind.stderr | 15 ++++++++++++++- .../intrinsics/ptr_metadata_uninit_slice_data.rs | 2 +- .../ptr_metadata_uninit_slice_data.stderr | 7 ++++++- .../intrinsics/ptr_metadata_uninit_slice_len.rs | 2 +- .../ptr_metadata_uninit_slice_len.stderr | 7 ++++++- .../fail/intrinsics/ptr_metadata_uninit_thin.rs | 2 +- .../intrinsics/ptr_metadata_uninit_thin.stderr | 7 ++++++- .../miri/tests/fail/read_from_trivial_switch.rs | 2 +- .../tests/fail/read_from_trivial_switch.stderr | 7 ++++++- .../miri/tests/fail/uninit/padding-enum.stderr | 8 +++++++- .../miri/tests/fail/uninit/padding-pair.stderr | 7 ++++++- .../miri/tests/fail/uninit/padding-struct.stderr | 7 ++++++- .../tests/fail/uninit/padding-wide-ptr.stderr | 7 ++++++- .../fail/uninit/transmute-pair-uninit.stderr | 7 ++++++- .../tests/fail/uninit/uninit_byte_read.stderr | 7 ++++++- .../tests/fail/validity/invalid_int_op.stderr | 7 ++++++- .../invalid-patterns.32bit.stderr | 4 ++-- .../invalid-patterns.64bit.stderr | 4 ++-- .../ui/consts/const-err-enum-discriminant.stderr | 2 +- ...t-pointer-values-in-various-types.64bit.stderr | 4 ++-- .../ui/consts/const-eval/ub-enum-overwrite.stderr | 2 +- tests/ui/consts/const-eval/ub-enum.stderr | 2 +- tests/ui/consts/const-eval/ub-nonnull.stderr | 2 +- tests/ui/consts/const-eval/ub-ref-ptr.stderr | 4 ++-- tests/ui/consts/const-eval/ub-wide-ptr.stderr | 4 ++-- .../const-eval/union-const-eval-field.stderr | 2 +- tests/ui/consts/const-eval/union-ice.stderr | 6 +++--- tests/ui/consts/const-eval/union-ub.32bit.stderr | 2 +- tests/ui/consts/const-eval/union-ub.64bit.stderr | 2 +- tests/ui/type/pattern_types/validity.rs | 4 ++-- tests/ui/type/pattern_types/validity.stderr | 4 ++-- 46 files changed, 175 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 62f591ceaa91..693b37829600 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -394,7 +394,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { interp_ok(try_validation!( self.ecx.read_immediate(val), self.path, - Ub(InvalidUninitBytes(None)) => + Ub(InvalidUninitBytes(_)) => Uninit { expected }, // The `Unsup` cases can only occur during CTFE Unsup(ReadPointerAsInt(_)) => diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 133111ff15de..27ead5145319 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -702,8 +702,11 @@ impl Allocation read_provenance: bool, ) -> AllocResult> { // First and foremost, if anything is uninit, bail. - if self.init_mask.is_range_initialized(range).is_err() { - return Err(AllocError::InvalidUninitBytes(None)); + if let Err(bad) = self.init_mask.is_range_initialized(range) { + return Err(AllocError::InvalidUninitBytes(Some(BadBytesAccess { + access: range, + bad, + }))); } // Get the integer part of the result. We HAVE TO check provenance before returning this! diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs index 047fe07df14b..8624e4d28fbe 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs @@ -15,6 +15,6 @@ fn main() { libc::pthread_cond_destroy(cond.as_mut_ptr()); libc::pthread_cond_destroy(cond.as_mut_ptr()); - //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/ } } diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr index 7abdfa87f75d..3318ac7fca59 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs:LL:CC | LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); @@ -9,6 +9,13 @@ LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 48, align: 8) { + 0x00 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x10 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x20 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs index 90e33d58673a..a510ee77cfb2 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs @@ -13,6 +13,6 @@ fn main() { libc::pthread_condattr_destroy(attr.as_mut_ptr()); libc::pthread_condattr_destroy(attr.as_mut_ptr()); - //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/ } } diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr index 28a66253ae80..1971bbc72103 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs:LL:CC | LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); @@ -9,6 +9,11 @@ LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs index 1792c227e132..71a802920329 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs @@ -16,6 +16,6 @@ fn main() { libc::pthread_mutex_destroy(mutex.as_mut_ptr()); libc::pthread_mutex_destroy(mutex.as_mut_ptr()); - //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/ } } diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr index e7a6dee02033..251f8036e383 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs:LL:CC | LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); @@ -9,6 +9,13 @@ LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 40, align: 8) { + 0x00 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x10 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x20 │ __ __ __ __ __ __ __ __ │ ░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs index 3711c1f8dc10..28dacc9931a4 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs @@ -12,6 +12,6 @@ fn main() { libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/ } } diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr index 0c9ee71de452..b341efb7770c 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs:LL:CC | LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); @@ -9,6 +9,11 @@ LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs index 6a31e972e68b..a46a124bf2ec 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs @@ -9,6 +9,6 @@ fn main() { libc::pthread_rwlock_destroy(&mut lock); libc::pthread_rwlock_destroy(&mut lock); - //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/ } } diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr index 836f0d060bd0..8f388577a27d 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs:LL:CC | LL | libc::pthread_rwlock_destroy(&mut lock); @@ -9,6 +9,14 @@ LL | libc::pthread_rwlock_destroy(&mut lock); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 56, align: 8) { + 0x00 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x10 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x20 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x30 │ __ __ __ __ __ __ __ __ │ ░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr index 6a7d9a495f97..3252368ea6de 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail/function_calls/arg_inplace_observe_after.rs:LL:CC | LL | _observe = non_copy.0; @@ -9,6 +9,11 @@ LL | _observe = non_copy.0; = note: BACKTRACE: = note: inside `main` at tests/fail/function_calls/arg_inplace_observe_after.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr index 0fc634bb7fce..09a5b9a64961 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | unsafe { ptr.read() }; @@ -14,6 +14,11 @@ note: inside `main` LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr index 746ab2e59ca0..240915472584 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; @@ -14,6 +14,11 @@ note: inside `main` LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr index 7747a75d1cfe..93720ca7d277 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr @@ -3,7 +3,7 @@ thread 'main' panicked at tests/fail/function_calls/return_pointer_on_unwind.rs: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail/function_calls/return_pointer_on_unwind.rs:LL:CC | LL | dbg!(x.0); @@ -15,6 +15,19 @@ LL | dbg!(x.0); = note: inside `main` at RUSTLIB/std/src/macros.rs:LL:CC = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 132, align: 4) { + 0x00 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x10 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x20 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x30 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x40 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x50 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x60 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x70 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x80 │ __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs index 0c305eed6e18..16f07c7ee994 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs @@ -9,7 +9,7 @@ use std::intrinsics::mir::*; pub unsafe fn deref_meta(p: *const *const [i32]) -> usize { mir! { { - RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + RET = PtrMetadata(*p); //~ ERROR: /Undefined Behavior: .*, but memory is uninitialized/ Return() } } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr index 1c22876ba435..9bacd80f7d52 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory --> tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs:LL:CC | LL | RET = PtrMetadata(*p); @@ -14,6 +14,11 @@ note: inside `main` LL | let _meta = deref_meta(p.as_ptr().cast()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Uninitialized memory occurred at ALLOC[0x0..0x8], in this allocation: +ALLOC (stack variable, size: 16, align: 8) { + __ __ __ __ __ __ __ __ 04 00 00 00 00 00 00 00 │ ░░░░░░░░........ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs index a2ffdc92c4e2..38db894537b7 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs @@ -9,7 +9,7 @@ use std::intrinsics::mir::*; pub unsafe fn deref_meta(p: *const *const [i32]) -> usize { mir! { { - RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + RET = PtrMetadata(*p); //~ ERROR: /Undefined Behavior: .*, but memory is uninitialized/ Return() } } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr index 00e63b1275f7..621325d72ff7 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr @@ -12,7 +12,7 @@ LL | (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32; = note: BACKTRACE: = note: inside `main` at tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x8..0x10], but memory is uninitialized at [0x8..0x10], and this operation requires initialized memory --> tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC | LL | RET = PtrMetadata(*p); @@ -28,6 +28,11 @@ note: inside `main` LL | let _meta = deref_meta(p.as_ptr().cast()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Uninitialized memory occurred at ALLOC[0x8..0x10], in this allocation: +ALLOC (stack variable, size: 16, align: 8) { + ╾────0x4[wildcard]────╼ __ __ __ __ __ __ __ __ │ ╾──────╼░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error; 1 warning emitted diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs index e5a51289a8ae..179fd33ed7c4 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs @@ -9,7 +9,7 @@ use std::intrinsics::mir::*; pub unsafe fn deref_meta(p: *const *const i32) -> () { mir! { { - RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + RET = PtrMetadata(*p); //~ ERROR: /Undefined Behavior: .*, but memory is uninitialized/ Return() } } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr index 24066953d79f..b0e452420570 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory --> tests/fail/intrinsics/ptr_metadata_uninit_thin.rs:LL:CC | LL | RET = PtrMetadata(*p); @@ -14,6 +14,11 @@ note: inside `main` LL | let _meta = deref_meta(p.as_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^ +Uninitialized memory occurred at ALLOC[0x0..0x8], in this allocation: +ALLOC (stack variable, size: 8, align: 8) { + __ __ __ __ __ __ __ __ │ ░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/read_from_trivial_switch.rs b/src/tools/miri/tests/fail/read_from_trivial_switch.rs index d34b1cd58200..35117c80b738 100644 --- a/src/tools/miri/tests/fail/read_from_trivial_switch.rs +++ b/src/tools/miri/tests/fail/read_from_trivial_switch.rs @@ -10,5 +10,5 @@ fn main() { let uninit: MaybeUninit = MaybeUninit::uninit(); let bad_ref: &i32 = unsafe { uninit.assume_init_ref() }; let &(0 | _) = bad_ref; - //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: /Undefined Behavior: .*, but memory is uninitialized .* requires initialized memory/ } diff --git a/src/tools/miri/tests/fail/read_from_trivial_switch.stderr b/src/tools/miri/tests/fail/read_from_trivial_switch.stderr index 923d836ee0c9..1d0c76c3c087 100644 --- a/src/tools/miri/tests/fail/read_from_trivial_switch.stderr +++ b/src/tools/miri/tests/fail/read_from_trivial_switch.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail/read_from_trivial_switch.rs:LL:CC | LL | let &(0 | _) = bad_ref; @@ -9,6 +9,11 @@ LL | let &(0 | _) = bad_ref; = note: BACKTRACE: = note: inside `main` at tests/fail/read_from_trivial_switch.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/uninit/padding-enum.stderr b/src/tools/miri/tests/fail/uninit/padding-enum.stderr index a9a5568f4e88..ee3867fc60ba 100644 --- a/src/tools/miri/tests/fail/uninit/padding-enum.stderr +++ b/src/tools/miri/tests/fail/uninit/padding-enum.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x8..0x9], but memory is uninitialized at [0x8..0x9], and this operation requires initialized memory --> tests/fail/uninit/padding-enum.rs:LL:CC | LL | let _val = *c.add(padding_offset); @@ -9,6 +9,12 @@ LL | let _val = *c.add(padding_offset); = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/padding-enum.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x8..0x9], in this allocation: +ALLOC (stack variable, size: 24, align: 8) { + 0x00 │ 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░ + 0x10 │ __ __ __ __ __ __ __ __ │ ░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/uninit/padding-pair.stderr b/src/tools/miri/tests/fail/uninit/padding-pair.stderr index d281a351d415..a9841815de39 100644 --- a/src/tools/miri/tests/fail/uninit/padding-pair.stderr +++ b/src/tools/miri/tests/fail/uninit/padding-pair.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x9..0xa], but memory is uninitialized at [0x9..0xa], and this operation requires initialized memory --> tests/fail/uninit/padding-pair.rs:LL:CC | LL | let v = unsafe { *z.offset(first_undef) }; @@ -9,6 +9,11 @@ LL | let v = unsafe { *z.offset(first_undef) }; = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/padding-pair.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x9..0xa], in this allocation: +ALLOC (stack variable, size: 16, align: 8) { + 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/uninit/padding-struct.stderr b/src/tools/miri/tests/fail/uninit/padding-struct.stderr index 3298f6a45106..05d754625d3f 100644 --- a/src/tools/miri/tests/fail/uninit/padding-struct.stderr +++ b/src/tools/miri/tests/fail/uninit/padding-struct.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x1..0x2], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory --> tests/fail/uninit/padding-struct.rs:LL:CC | LL | let _val = *c.add(1); @@ -9,6 +9,11 @@ LL | let _val = *c.add(1); = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/padding-struct.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x1..0x2], in this allocation: +ALLOC (stack variable, size: 4, align: 2) { + 00 __ 00 00 │ .░.. +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr index d92d05ae6319..f6446a5a95b5 100644 --- a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr +++ b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x8..0x9], but memory is uninitialized at [0x8..0x9], and this operation requires initialized memory --> tests/fail/uninit/padding-wide-ptr.rs:LL:CC | LL | let _val = *c.add(mem::size_of::<*const u8>()); @@ -9,6 +9,11 @@ LL | let _val = *c.add(mem::size_of::<*const u8>()); = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/padding-wide-ptr.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x8..0x9], in this allocation: +ALLOC (stack variable, size: 16, align: 8) { + 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr index 0ae0ce5de9ca..385d877e2ee2 100644 --- a/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr +++ b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x9..0xa], but memory is uninitialized at [0x9..0xa], and this operation requires initialized memory --> tests/fail/uninit/transmute-pair-uninit.rs:LL:CC | LL | let v = unsafe { *z.offset(first_undef) }; @@ -9,6 +9,11 @@ LL | let v = unsafe { *z.offset(first_undef) }; = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/transmute-pair-uninit.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x9..0xa], in this allocation: +ALLOC (stack variable, size: 16, align: 8) { + 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr b/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr index d2a5a2d38312..5a5aa12987c5 100644 --- a/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x5..0x6], but memory is uninitialized at [0x5..0x6], and this operation requires initialized memory --> tests/fail/uninit/uninit_byte_read.rs:LL:CC | LL | let undef = unsafe { *v.as_ptr().add(5) }; @@ -9,6 +9,11 @@ LL | let undef = unsafe { *v.as_ptr().add(5) }; = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/uninit_byte_read.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x5..0x6], in this allocation: +ALLOC (Rust heap, size: 10, align: 1) { + __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/validity/invalid_int_op.stderr b/src/tools/miri/tests/fail/validity/invalid_int_op.stderr index 6e24cadfc205..0b1915621b24 100644 --- a/src/tools/miri/tests/fail/validity/invalid_int_op.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_int_op.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail/validity/invalid_int_op.rs:LL:CC | LL | let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; @@ -9,6 +9,11 @@ LL | let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() } = note: BACKTRACE: = note: inside `main` at tests/fail/validity/invalid_int_op.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr index 92b226fe0f71..107179516bc3 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:40:32 | LL | get_flag::(); @@ -26,7 +26,7 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character 42 │ B } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:44:58 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr index 92b226fe0f71..107179516bc3 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:40:32 | LL | get_flag::(); @@ -26,7 +26,7 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character 42 │ B } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:44:58 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); diff --git a/tests/ui/consts/const-err-enum-discriminant.stderr b/tests/ui/consts/const-err-enum-discriminant.stderr index 8724333ad7a5..f935d1054de6 100644 --- a/tests/ui/consts/const-err-enum-discriminant.stderr +++ b/tests/ui/consts/const-err-enum-discriminant.stderr @@ -1,4 +1,4 @@ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory --> $DIR/const-err-enum-discriminant.rs:8:21 | LL | Boo = [unsafe { Foo { b: () }.a }; 4][3], diff --git a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr index d28d6841ca9d..65e846b5741e 100644 --- a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr +++ b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr @@ -43,7 +43,7 @@ LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uin = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x10], but memory is uninitialized at [0x8..0x10], and this operation requires initialized memory --> $DIR/const-pointer-values-in-various-types.rs:42:47 | LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 }; @@ -85,7 +85,7 @@ LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC1[0x0..0x10], but memory is uninitialized at [0x8..0x10], and this operation requires initialized memory --> $DIR/const-pointer-values-in-various-types.rs:57:47 | LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 }; diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr index 52af52d32366..14f369eace47 100644 --- a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr +++ b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr @@ -1,4 +1,4 @@ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x1..0x2], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory --> $DIR/ub-enum-overwrite.rs:11:14 | LL | unsafe { *p } diff --git a/tests/ui/consts/const-eval/ub-enum.stderr b/tests/ui/consts/const-eval/ub-enum.stderr index 29f7a1f051a7..6665830e2502 100644 --- a/tests/ui/consts/const-eval/ub-enum.stderr +++ b/tests/ui/consts/const-eval/ub-enum.stderr @@ -56,7 +56,7 @@ LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory --> $DIR/ub-enum.rs:61:41 | LL | const BAD_ENUM2_UNDEF: Enum2 = unsafe { MaybeUninit { uninit: () }.init }; diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index 314141e48370..c92797f330af 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -37,7 +37,7 @@ LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; HEX_DUMP } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/ub-nonnull.rs:36:38 | LL | const UNINIT: NonZero = unsafe { MaybeUninit { uninit: () }.init }; diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index d5ccc396b903..beb54e435341 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -103,7 +103,7 @@ LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; HEX_DUMP } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC3[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory --> $DIR/ub-ref-ptr.rs:48:41 | LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; @@ -120,7 +120,7 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; HEX_DUMP } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC4[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory --> $DIR/ub-ref-ptr.rs:53:38 | LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index 8724dd9a3c0d..a3eb5c720319 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -71,7 +71,7 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni HEX_DUMP } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC32[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/ub-wide-ptr.rs:63:1 | LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { @@ -179,7 +179,7 @@ note: erroneous constant encountered LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC33[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/ub-wide-ptr.rs:101:1 | LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { diff --git a/tests/ui/consts/const-eval/union-const-eval-field.stderr b/tests/ui/consts/const-eval/union-const-eval-field.stderr index 07ff4c3ca364..deddf9e0b6d3 100644 --- a/tests/ui/consts/const-eval/union-const-eval-field.stderr +++ b/tests/ui/consts/const-eval/union-const-eval-field.stderr @@ -1,4 +1,4 @@ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/union-const-eval-field.rs:28:37 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; diff --git a/tests/ui/consts/const-eval/union-ice.stderr b/tests/ui/consts/const-eval/union-ice.stderr index b00fcc91d68a..826d7440a808 100644 --- a/tests/ui/consts/const-eval/union-ice.stderr +++ b/tests/ui/consts/const-eval/union-ice.stderr @@ -1,16 +1,16 @@ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/union-ice.rs:14:33 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; | ^^^^^^^^^^^^ evaluation of `FIELD3` failed here -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC1[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/union-ice.rs:19:17 | LL | b: unsafe { UNION.field3 }, | ^^^^^^^^^^^^ evaluation of `FIELD_PATH` failed here -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC2[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/union-ice.rs:31:18 | LL | unsafe { UNION.field3 }, diff --git a/tests/ui/consts/const-eval/union-ub.32bit.stderr b/tests/ui/consts/const-eval/union-ub.32bit.stderr index 9f0697984e4c..70bf2cf53908 100644 --- a/tests/ui/consts/const-eval/union-ub.32bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.32bit.stderr @@ -9,7 +9,7 @@ LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool }; 2a │ * } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/union-ub.rs:35:36 | LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; diff --git a/tests/ui/consts/const-eval/union-ub.64bit.stderr b/tests/ui/consts/const-eval/union-ub.64bit.stderr index 9f0697984e4c..70bf2cf53908 100644 --- a/tests/ui/consts/const-eval/union-ub.64bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.64bit.stderr @@ -9,7 +9,7 @@ LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool }; 2a │ * } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/union-ub.rs:35:36 | LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; diff --git a/tests/ui/type/pattern_types/validity.rs b/tests/ui/type/pattern_types/validity.rs index a4e49692c98c..432aacb9be3f 100644 --- a/tests/ui/type/pattern_types/validity.rs +++ b/tests/ui/type/pattern_types/validity.rs @@ -11,7 +11,7 @@ const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) }; //~^ ERROR: constructing invalid value: encountered 0 const BAD_UNINIT: pattern_type!(u32 is 1..) = - //~^ ERROR: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: this operation requires initialized memory unsafe { std::mem::transmute(std::mem::MaybeUninit::::uninit()) }; const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(&42) }; @@ -27,7 +27,7 @@ const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) })); //~^ ERROR: constructing invalid value at .0.0: encountered 0 const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = - //~^ ERROR: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: this operation requires initialized memory unsafe { std::mem::transmute(std::mem::MaybeUninit::::uninit()) }; const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') }; diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr index 4f4c16028f6b..76824055d8a1 100644 --- a/tests/ui/type/pattern_types/validity.stderr +++ b/tests/ui/type/pattern_types/validity.stderr @@ -9,7 +9,7 @@ LL | const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) }; HEX_DUMP } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> $DIR/validity.rs:13:1 | LL | const BAD_UNINIT: pattern_type!(u32 is 1..) = @@ -46,7 +46,7 @@ LL | const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) })); HEX_DUMP } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> $DIR/validity.rs:29:1 | LL | const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = From bf24c0dfa581bffed5e3627c2881e46cc76d4d93 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Jul 2025 22:12:26 +0200 Subject: [PATCH 278/363] miri sleep tests: increase slack --- src/tools/miri/tests/pass-dep/libc/libc-time.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs index e8957846ad51..9e9fadfca9e7 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-time.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs @@ -336,7 +336,7 @@ fn test_nanosleep() { let remainder = ptr::null_mut::(); let is_error = unsafe { libc::nanosleep(&duration_zero, remainder) }; assert_eq!(is_error, 0); - assert!(start_test_sleep.elapsed() < Duration::from_millis(10)); + assert!(start_test_sleep.elapsed() < Duration::from_millis(100)); let start_test_sleep = Instant::now(); let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 }; @@ -390,7 +390,7 @@ mod test_clock_nanosleep { ) }; assert_eq!(error, 0); - assert!(start_test_sleep.elapsed() < Duration::from_millis(10)); + assert!(start_test_sleep.elapsed() < Duration::from_millis(100)); let start_test_sleep = Instant::now(); let hunderd_millis_after_start = add_100_millis(timespec_now(libc::CLOCK_MONOTONIC)); @@ -417,7 +417,7 @@ mod test_clock_nanosleep { libc::clock_nanosleep(libc::CLOCK_MONOTONIC, NO_FLAGS, &duration_zero, remainder) }; assert_eq!(error, 0); - assert!(start_test_sleep.elapsed() < Duration::from_millis(10)); + assert!(start_test_sleep.elapsed() < Duration::from_millis(100)); let start_test_sleep = Instant::now(); let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 }; From 87a27f94b095793a1833a9dacec1493cc6cdcd6b Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 14:53:14 +0000 Subject: [PATCH 279/363] Specify of_trait in Target::Impl. --- compiler/rustc_hir/src/target.rs | 11 +- compiler/rustc_passes/messages.ftl | 3 +- compiler/rustc_passes/src/check_attr.rs | 18 +- compiler/rustc_passes/src/lang_items.rs | 2 +- .../check-doc-alias-attr-location.stderr | 4 +- tests/ui/attributes/positions/used.stderr | 2 +- .../issue-43106-gating-of-builtin-attrs.rs | 6 + ...issue-43106-gating-of-builtin-attrs.stderr | 258 +++++++++--------- tests/ui/lint/unused/unused-attr-duplicate.rs | 4 +- .../lint/unused/unused-attr-duplicate.stderr | 36 +-- .../unused/unused_attributes-must_use.stderr | 4 +- .../check-doc-alias-attr-location.stderr | 4 +- 12 files changed, 187 insertions(+), 165 deletions(-) diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 601898023fc3..5e13c8ec11ff 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -41,7 +41,7 @@ pub enum Target { Union, Trait, TraitAlias, - Impl, + Impl { of_trait: bool }, Expression, Statement, Arm, @@ -86,7 +86,7 @@ impl Target { | Target::Union | Target::Trait | Target::TraitAlias - | Target::Impl + | Target::Impl { .. } | Target::Expression | Target::Statement | Target::Arm @@ -119,7 +119,7 @@ impl Target { ItemKind::Union(..) => Target::Union, ItemKind::Trait(..) => Target::Trait, ItemKind::TraitAlias(..) => Target::TraitAlias, - ItemKind::Impl { .. } => Target::Impl, + ItemKind::Impl(imp_) => Target::Impl { of_trait: imp_.of_trait.is_some() }, } } @@ -141,7 +141,7 @@ impl Target { DefKind::Union => Target::Union, DefKind::Trait => Target::Trait, DefKind::TraitAlias => Target::TraitAlias, - DefKind::Impl { .. } => Target::Impl, + DefKind::Impl { of_trait } => Target::Impl { of_trait }, _ => panic!("impossible case reached"), } } @@ -196,7 +196,8 @@ impl Target { Target::Union => "union", Target::Trait => "trait", Target::TraitAlias => "trait alias", - Target::Impl => "implementation block", + Target::Impl { of_trait: false } => "inherent implementation block", + Target::Impl { of_trait: true } => "trait implementation block", Target::Expression => "expression", Target::Statement => "statement", Target::Arm => "match arm", diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index d1b856ca4157..51e23edb9bbf 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -560,7 +560,8 @@ passes_only_has_effect_on = `#[{$attr_name}]` only has an effect on {$target_name -> [function] functions [module] modules - [implementation_block] implementation blocks + [trait_implementation_block] trait implementation blocks + [inherent_implementation_block] inherent implementation blocks *[unspecified] (unspecified--this is a compiler bug) } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d8ffcedeb88a..ffa6081d7125 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -161,7 +161,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sym::automatically_derived, *attr_span, target, - Target::Impl, + Target::Impl { of_trait: true }, ), Attribute::Parsed( AttributeKind::Stability { span, .. } @@ -492,7 +492,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { attr: &Attribute, item: Option>, ) { - if !matches!(target, Target::Impl) + if !matches!(target, Target::Impl { .. }) || matches!( item, Some(ItemLike::Item(hir::Item { kind: hir::ItemKind::Impl(_impl),.. })) @@ -596,7 +596,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::Fn | Target::Closure | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) - | Target::Impl + | Target::Impl { .. } | Target::Mod => return, // These are "functions", but they aren't allowed because they don't @@ -985,9 +985,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let span = meta.span(); if let Some(location) = match target { Target::AssocTy => { - let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id; - let containing_item = self.tcx.hir_expect_item(parent_def_id); - if Target::from_item(containing_item) == Target::Impl { + if let DefKind::Impl { .. } = + self.tcx.def_kind(self.tcx.local_parent(hir_id.owner.def_id)) + { Some("type alias in implementation block") } else { None @@ -1010,7 +1010,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::Arm | Target::ForeignMod | Target::Closure - | Target::Impl + | Target::Impl { .. } | Target::WherePredicate => Some(target.name()), Target::ExternCrate | Target::Use @@ -1588,7 +1588,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let article = match target { Target::ExternCrate | Target::Enum - | Target::Impl + | Target::Impl { .. } | Target::Expression | Target::Arm | Target::AssocConst @@ -2272,7 +2272,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { // FIXME(staged_api): There's no reason we can't support more targets here. We're just // being conservative to begin with. - Target::Fn | Target::Impl => {} + Target::Fn | Target::Impl { .. } => {} Target::ExternCrate | Target::Use | Target::Static diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 3afed9784de5..6fac01827a49 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -287,7 +287,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { ast::ItemKind::Union(..) => Target::Union, ast::ItemKind::Trait(_) => Target::Trait, ast::ItemKind::TraitAlias(..) => Target::TraitAlias, - ast::ItemKind::Impl(_) => Target::Impl, + ast::ItemKind::Impl(imp_) => Target::Impl { of_trait: imp_.of_trait.is_some() }, ast::ItemKind::MacroDef(..) => Target::MacroDef, ast::ItemKind::MacCall(_) | ast::ItemKind::DelegationMac(_) => { unreachable!("macros should have been expanded") diff --git a/tests/rustdoc-ui/check-doc-alias-attr-location.stderr b/tests/rustdoc-ui/check-doc-alias-attr-location.stderr index 85c9516236c9..9d3ce5e63ef7 100644 --- a/tests/rustdoc-ui/check-doc-alias-attr-location.stderr +++ b/tests/rustdoc-ui/check-doc-alias-attr-location.stderr @@ -4,13 +4,13 @@ error: `#[doc(alias = "...")]` isn't allowed on foreign module LL | #[doc(alias = "foo")] | ^^^^^^^^^^^^^ -error: `#[doc(alias = "...")]` isn't allowed on implementation block +error: `#[doc(alias = "...")]` isn't allowed on inherent implementation block --> $DIR/check-doc-alias-attr-location.rs:10:7 | LL | #[doc(alias = "bar")] | ^^^^^^^^^^^^^ -error: `#[doc(alias = "...")]` isn't allowed on implementation block +error: `#[doc(alias = "...")]` isn't allowed on trait implementation block --> $DIR/check-doc-alias-attr-location.rs:16:7 | LL | #[doc(alias = "foobar")] diff --git a/tests/ui/attributes/positions/used.stderr b/tests/ui/attributes/positions/used.stderr index 96dd43a3a937..64460c178cb0 100644 --- a/tests/ui/attributes/positions/used.stderr +++ b/tests/ui/attributes/positions/used.stderr @@ -28,7 +28,7 @@ error: attribute must be applied to a `static` variable LL | #[used] | ^^^^^^^ LL | impl Bar for Foo {} - | ------------------- but this is a implementation block + | ------------------- but this is a trait implementation block error: attribute must be applied to a `static` variable --> $DIR/used.rs:21:5 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 d07201ebbd1a..9740eaaf1e93 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 @@ -269,7 +269,13 @@ mod automatically_derived { #[automatically_derived] type T = S; //~^ WARN `#[automatically_derived] + #[automatically_derived] trait W { } + //~^ WARN `#[automatically_derived] + #[automatically_derived] impl S { } + //~^ WARN `#[automatically_derived] + + #[automatically_derived] impl W for S { } } #[no_mangle] 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 5d7d1caeeab0..3271aa0620b9 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 @@ -1,5 +1,5 @@ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:391:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:397:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | mod inner { #![macro_escape] } = help: try an outer attribute: `#[macro_use]` warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:388:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:394:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ @@ -198,14 +198,14 @@ note: the lint level is defined here LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on implementation blocks +warning: `#[automatically_derived]` only has an effect on trait implementation blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:257:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:281:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ @@ -220,31 +220,31 @@ LL | | } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:315:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:321:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:333:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:339:1 | LL | #[ignore] | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:368:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:1 | LL | #[no_std] | ^^^^^^^^^ warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:444:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:1 | LL | #[cold] | ^^^^^^^ @@ -260,7 +260,7 @@ LL | | } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:473:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:1 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -276,7 +276,7 @@ LL | | } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:518:1 | LL | #[link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -292,7 +292,7 @@ LL | | } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:550:1 | LL | #[link()] | ^^^^^^^^^ @@ -308,55 +308,55 @@ LL | | } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[must_use]` has no effect when applied to a module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:595:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:601:1 | LL | #[must_use] | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:608:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:1 | LL | #[windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:629:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:648:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:1 | LL | #[no_main] | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:1 | LL | #[no_builtins] | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -495,32 +495,44 @@ warning: `#[path]` only has an effect on modules LL | #[path = "3800"] impl S { } | ^^^^^^^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on implementation blocks +warning: `#[automatically_derived]` only has an effect on trait implementation blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:17 | LL | mod inner { #![automatically_derived] } | ^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on implementation blocks +warning: `#[automatically_derived]` only has an effect on trait implementation blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:263:5 | LL | #[automatically_derived] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on implementation blocks +warning: `#[automatically_derived]` only has an effect on trait implementation blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:5 | LL | #[automatically_derived] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on implementation blocks +warning: `#[automatically_derived]` only has an effect on trait implementation blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:5 | LL | #[automatically_derived] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ +warning: `#[automatically_derived]` only has an effect on trait implementation blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5 + | +LL | #[automatically_derived] trait W { } + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: `#[automatically_derived]` only has an effect on trait implementation blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:5 + | +LL | #[automatically_derived] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^ + warning: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:280:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:286:17 | LL | mod inner { #![no_mangle] } | ------------^^^^^^^^^^^^^-- not a free function, impl method or static @@ -528,7 +540,7 @@ LL | mod inner { #![no_mangle] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:287:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:293:5 | LL | #[no_mangle] struct S; | ^^^^^^^^^^^^ --------- not a free function, impl method or static @@ -536,7 +548,7 @@ LL | #[no_mangle] struct S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:292:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:298:5 | LL | #[no_mangle] type T = S; | ^^^^^^^^^^^^ ----------- not a free function, impl method or static @@ -544,7 +556,7 @@ LL | #[no_mangle] type T = S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:297:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:303:5 | LL | #[no_mangle] impl S { } | ^^^^^^^^^^^^ ---------- not a free function, impl method or static @@ -552,7 +564,7 @@ LL | #[no_mangle] impl S { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:303:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:309:9 | LL | #[no_mangle] fn foo(); | ^^^^^^^^^^^^ --------- not a free function, impl method or static @@ -560,7 +572,7 @@ LL | #[no_mangle] fn foo(); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:308:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:314:9 | LL | #[no_mangle] fn bar() {} | ^^^^^^^^^^^^ ----------- not a free function, impl method or static @@ -568,163 +580,163 @@ LL | #[no_mangle] fn bar() {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:318:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:324:17 | LL | mod inner { #![should_panic] } | ^^^^^^^^^^^^^^^^ warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:323:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:329:5 | LL | #[should_panic] struct S; | ^^^^^^^^^^^^^^^ warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:326:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:5 | LL | #[should_panic] type T = S; | ^^^^^^^^^^^^^^^ warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:329:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:5 | LL | #[should_panic] impl S { } | ^^^^^^^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:336:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:342:17 | LL | mod inner { #![ignore] } | ^^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5 | LL | #[ignore] struct S; | ^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5 | LL | #[ignore] type T = S; | ^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:353:5 | LL | #[ignore] impl S { } | ^^^^^^^^^ warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5 | LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:358:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5 | LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5 | LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5 | LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:371:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:377:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:377:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:407:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:410:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:429:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:456:17 | LL | mod inner { #![cold] } | ------------^^^^^^^^-- not a function definition @@ -732,7 +744,7 @@ LL | mod inner { #![cold] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:457:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:463:5 | LL | #[cold] struct S; | ^^^^^^^ --------- not a function definition @@ -740,7 +752,7 @@ LL | #[cold] struct S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:468:5 | LL | #[cold] type T = S; | ^^^^^^^ ----------- not a function definition @@ -748,7 +760,7 @@ LL | #[cold] type T = S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:467:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:473:5 | LL | #[cold] impl S { } | ^^^^^^^ ---------- not a function definition @@ -756,7 +768,7 @@ LL | #[cold] impl S { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:5 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -766,13 +778,13 @@ LL | extern "C" { } | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! help: try `#[link(name = "1900")]` instead - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:5 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:17 | LL | mod inner { #![link_name="1900"] } | ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static @@ -780,7 +792,7 @@ LL | mod inner { #![link_name="1900"] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:491:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:5 | LL | #[link_name = "1900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static @@ -788,7 +800,7 @@ LL | #[link_name = "1900"] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:5 | LL | #[link_name = "1900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static @@ -796,7 +808,7 @@ LL | #[link_name = "1900"] struct S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5 | LL | #[link_name = "1900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static @@ -804,7 +816,7 @@ LL | #[link_name = "1900"] type T = S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:506:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:5 | LL | #[link_name = "1900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static @@ -812,7 +824,7 @@ LL | #[link_name = "1900"] impl S { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:518:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:524:17 | LL | mod inner { #![link_section="1800"] } | ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static @@ -820,7 +832,7 @@ LL | mod inner { #![link_section="1800"] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:525:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:531:5 | LL | #[link_section = "1800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static @@ -828,7 +840,7 @@ LL | #[link_section = "1800"] struct S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:530:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:5 | LL | #[link_section = "1800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static @@ -836,7 +848,7 @@ LL | #[link_section = "1800"] type T = S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:535:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:5 | LL | #[link_section = "1800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static @@ -844,7 +856,7 @@ LL | #[link_section = "1800"] impl S { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:550:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:556:17 | LL | mod inner { #![link()] } | ------------^^^^^^^^^^-- not an `extern` block @@ -852,7 +864,7 @@ LL | mod inner { #![link()] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:561:5 | LL | #[link()] fn f() { } | ^^^^^^^^^ ---------- not an `extern` block @@ -860,7 +872,7 @@ LL | #[link()] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:560:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:566:5 | LL | #[link()] struct S; | ^^^^^^^^^ --------- not an `extern` block @@ -868,7 +880,7 @@ LL | #[link()] struct S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:565:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:571:5 | LL | #[link()] type T = S; | ^^^^^^^^^ ----------- not an `extern` block @@ -876,7 +888,7 @@ LL | #[link()] type T = S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:570:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:576:5 | LL | #[link()] impl S { } | ^^^^^^^^^ ---------- not an `extern` block @@ -884,7 +896,7 @@ LL | #[link()] impl S { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:575:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:5 | LL | #[link()] extern "Rust" {} | ^^^^^^^^^ @@ -892,259 +904,259 @@ LL | #[link()] extern "Rust" {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[must_use]` has no effect when applied to a module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:597:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:17 | LL | mod inner { #![must_use] } | ^^^^^^^^^^^^ warning: `#[must_use]` has no effect when applied to a type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:609:5 | LL | #[must_use] type T = S; | ^^^^^^^^^^^ -warning: `#[must_use]` has no effect when applied to an implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:605:5 +warning: `#[must_use]` has no effect when applied to an inherent implementation block + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:5 | LL | #[must_use] impl S { } | ^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:17 | LL | mod inner { #![windows_subsystem="windows"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5 | LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:5 | LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:5 | LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:629:5 | LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:632:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:647:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:666:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:670:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:682:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:682:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:17 | LL | mod inner { #![no_builtins] } | ^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 | LL | #[no_builtins] fn f() { } | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 | LL | #[no_builtins] struct S; | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 | LL | #[no_builtins] type T = S; | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5 | LL | #[no_builtins] impl S { } | ^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:740:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:740:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1157,5 +1169,5 @@ LL | #![feature(rust1)] | = note: `#[warn(stable_features)]` on by default -warning: 171 warnings emitted +warning: 173 warnings emitted diff --git a/tests/ui/lint/unused/unused-attr-duplicate.rs b/tests/ui/lint/unused/unused-attr-duplicate.rs index bf94a42f6e0c..cfa6c2b4228c 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.rs +++ b/tests/ui/lint/unused/unused-attr-duplicate.rs @@ -66,9 +66,11 @@ fn t1() {} #[non_exhaustive] //~ ERROR unused attribute pub struct X; +trait Trait {} + #[automatically_derived] #[automatically_derived] //~ ERROR unused attribute -impl X {} +impl Trait for X {} #[inline(always)] #[inline(never)] //~ ERROR unused attribute diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 6db6af823f41..ecc1b7ff5a46 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -179,112 +179,112 @@ LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:70:1 + --> $DIR/unused-attr-duplicate.rs:72:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:69:1 + --> $DIR/unused-attr-duplicate.rs:71:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:74:1 + --> $DIR/unused-attr-duplicate.rs:76:1 | LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:73:1 + --> $DIR/unused-attr-duplicate.rs:75:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:77:1 + --> $DIR/unused-attr-duplicate.rs:79:1 | LL | #[cold] | ^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:76:1 + --> $DIR/unused-attr-duplicate.rs:78:1 | LL | #[cold] | ^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:79:1 + --> $DIR/unused-attr-duplicate.rs:81:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:78:1 + --> $DIR/unused-attr-duplicate.rs:80:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:86:5 + --> $DIR/unused-attr-duplicate.rs:88:5 | LL | #[link_name = "this_does_not_exist"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:88:5 + --> $DIR/unused-attr-duplicate.rs:90:5 | LL | #[link_name = "rust_dbg_extern_identity_u32"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:92:1 + --> $DIR/unused-attr-duplicate.rs:94:1 | LL | #[export_name = "exported_symbol_name"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:94:1 + --> $DIR/unused-attr-duplicate.rs:96:1 | LL | #[export_name = "exported_symbol_name2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:98:1 + --> $DIR/unused-attr-duplicate.rs:100:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:97:1 + --> $DIR/unused-attr-duplicate.rs:99:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:102:1 + --> $DIR/unused-attr-duplicate.rs:104:1 | LL | #[used] | ^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:101:1 + --> $DIR/unused-attr-duplicate.rs:103:1 | LL | #[used] | ^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:105:1 + --> $DIR/unused-attr-duplicate.rs:107:1 | LL | #[link_section = ".text"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:108:1 + --> $DIR/unused-attr-duplicate.rs:110:1 | LL | #[link_section = ".bss"] | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr index 28fd8eeb8cbd..862ffa42d808 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.stderr +++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr @@ -45,7 +45,7 @@ error: `#[must_use]` has no effect when applied to a static item LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to an implementation block +error: `#[must_use]` has no effect when applied to an inherent implementation block --> $DIR/unused_attributes-must_use.rs:33:1 | LL | #[must_use] @@ -69,7 +69,7 @@ error: `#[must_use]` has no effect when applied to a type parameter LL | fn qux<#[must_use] T>(_: T) {} | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to an implementation block +error: `#[must_use]` has no effect when applied to an trait implementation block --> $DIR/unused_attributes-must_use.rs:79:1 | LL | #[must_use] diff --git a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr index 23c93a4ed8bd..4244c11eb3eb 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr +++ b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr @@ -10,13 +10,13 @@ error: `#[doc(alias = "...")]` isn't allowed on foreign module LL | #[doc(alias = "foo")] | ^^^^^^^^^^^^^ -error: `#[doc(alias = "...")]` isn't allowed on implementation block +error: `#[doc(alias = "...")]` isn't allowed on inherent implementation block --> $DIR/check-doc-alias-attr-location.rs:12:7 | LL | #[doc(alias = "bar")] | ^^^^^^^^^^^^^ -error: `#[doc(alias = "...")]` isn't allowed on implementation block +error: `#[doc(alias = "...")]` isn't allowed on trait implementation block --> $DIR/check-doc-alias-attr-location.rs:18:7 | LL | #[doc(alias = "foobar")] From 0d1aefafa81c98392c4d79d12c246d94552ae7d8 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 14:24:30 +0000 Subject: [PATCH 280/363] Warn useless deprecation in check_attr. --- compiler/rustc_hir/src/target.rs | 18 +++++++++++------ compiler/rustc_passes/src/check_attr.rs | 27 +++++++++++++++++++++++-- compiler/rustc_passes/src/stability.rs | 16 ++------------- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 5e13c8ec11ff..d617f44f8d8e 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -51,7 +51,7 @@ pub enum Target { ForeignFn, ForeignStatic, ForeignTy, - GenericParam(GenericParamKind), + GenericParam { kind: GenericParamKind, has_default: bool }, MacroDef, Param, PatField, @@ -93,7 +93,7 @@ impl Target { | Target::ForeignFn | Target::ForeignStatic | Target::ForeignTy - | Target::GenericParam(_) + | Target::GenericParam { .. } | Target::MacroDef | Target::Param | Target::PatField @@ -169,11 +169,17 @@ impl Target { pub fn from_generic_param(generic_param: &hir::GenericParam<'_>) -> Target { match generic_param.kind { - hir::GenericParamKind::Type { .. } => Target::GenericParam(GenericParamKind::Type), + hir::GenericParamKind::Type { default, .. } => Target::GenericParam { + kind: GenericParamKind::Type, + has_default: default.is_some(), + }, hir::GenericParamKind::Lifetime { .. } => { - Target::GenericParam(GenericParamKind::Lifetime) + Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: false } } - hir::GenericParamKind::Const { .. } => Target::GenericParam(GenericParamKind::Const), + hir::GenericParamKind::Const { default, .. } => Target::GenericParam { + kind: GenericParamKind::Const, + has_default: default.is_some(), + }, } } @@ -211,7 +217,7 @@ impl Target { Target::ForeignFn => "foreign function", Target::ForeignStatic => "foreign static item", Target::ForeignTy => "foreign type", - Target::GenericParam(kind) => match kind { + Target::GenericParam { kind, has_default: _ } => match kind { GenericParamKind::Type => "type parameter", GenericParamKind::Lifetime => "lifetime parameter", GenericParamKind::Const => "const parameter", diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ffa6081d7125..44b7afc88ec0 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -36,6 +36,7 @@ use rustc_session::lint; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, MALFORMED_DIAGNOSTIC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, + USELESS_DEPRECATED, }; use rustc_session::parse::feature_err; use rustc_span::edition::Edition; @@ -1031,7 +1032,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::ForeignFn | Target::ForeignStatic | Target::ForeignTy - | Target::GenericParam(..) + | Target::GenericParam { .. } | Target::MacroDef | Target::PatField | Target::ExprField => None, @@ -2298,7 +2299,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::ForeignFn | Target::ForeignStatic | Target::ForeignTy - | Target::GenericParam(_) + | Target::GenericParam { .. } | Target::MacroDef | Target::Param | Target::PatField @@ -2352,6 +2353,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> { errors::Deprecated, ); } + Target::Impl { of_trait: true } + | Target::GenericParam { has_default: false, kind: _ } => { + self.tcx.emit_node_span_lint( + USELESS_DEPRECATED, + hir_id, + attr.span(), + errors::DeprecatedAnnotationHasNoEffect { span: attr.span() }, + ); + } + Target::AssocConst | Target::Method(..) | Target::AssocTy + if matches!( + self.tcx.def_kind(self.tcx.local_parent(hir_id.owner.def_id)), + DefKind::Impl { of_trait: true } + ) => + { + self.tcx.emit_node_span_lint( + USELESS_DEPRECATED, + hir_id, + attr.span(), + errors::DeprecatedAnnotationHasNoEffect { span: attr.span() }, + ); + } _ => {} } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index e5530d526866..0308acc98477 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -27,9 +27,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint; -use rustc_session::lint::builtin::{ - DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED, -}; +use rustc_session::lint::builtin::{DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL}; use rustc_span::{Span, Symbol, sym}; use tracing::{debug, info}; @@ -125,19 +123,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); let mut is_deprecated = false; - if let Some((depr, span)) = &depr { + if let Some((depr, _)) = &depr { is_deprecated = true; - if matches!(kind, AnnotationKind::Prohibited | AnnotationKind::DeprecationProhibited) { - let hir_id = self.tcx.local_def_id_to_hir_id(def_id); - self.tcx.emit_node_span_lint( - USELESS_DEPRECATED, - hir_id, - *span, - errors::DeprecatedAnnotationHasNoEffect { span: *span }, - ); - } - // `Deprecation` is just two pointers, no need to intern it let depr_entry = DeprecationEntry::local(*depr, def_id); self.index.depr_map.insert(def_id, depr_entry); From ce664c57adfed89ab7ebde65cf7c5dd327533725 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 18 Jan 2022 21:01:07 +0100 Subject: [PATCH 281/363] Querify lookup_deprecation_entry. --- compiler/rustc_middle/src/middle/stability.rs | 5 -- compiler/rustc_passes/src/stability.rs | 79 +++++++++---------- 2 files changed, 39 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 99faba7b2c0a..9c2528ca4103 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -73,7 +73,6 @@ pub struct Index { pub stab_map: LocalDefIdMap, pub const_stab_map: LocalDefIdMap, pub default_body_stab_map: LocalDefIdMap, - pub depr_map: LocalDefIdMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute /// exists, then this map will have a `impliee -> implier` entry. @@ -101,10 +100,6 @@ impl Index { pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option { self.default_body_stab_map.get(&def_id).copied() } - - pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option { - self.depr_map.get(&def_id).cloned() - } } pub fn report_unstable( diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 0308acc98477..35332e6e7247 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -89,13 +89,40 @@ impl InheritStability { } } +fn inherit_deprecation(def_kind: DefKind) -> InheritDeprecation { + match def_kind { + DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => InheritDeprecation::No, + _ => InheritDeprecation::Yes, + } +} + +fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + let depr = attrs::find_attr!(attrs, + AttributeKind::Deprecation { deprecation, span: _ } => *deprecation + ); + + let Some(depr) = depr else { + if inherit_deprecation(tcx.def_kind(def_id)).yes() { + let parent_id = tcx.opt_local_parent(def_id)?; + let parent_depr = tcx.lookup_deprecation_entry(parent_id)?; + info!("tagging child {:?} as deprecated from parent", def_id); + return Some(parent_depr); + } + + return None; + }; + + // `Deprecation` is just two pointers, no need to intern it + Some(DeprecationEntry::local(depr, def_id)) +} + /// A private tree-walker for producing an `Index`. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, index: &'a mut Index, parent_stab: Option, parent_const_stab: Option, - parent_depr: Option, in_trait_impl: bool, } @@ -119,24 +146,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); - let depr = attrs::find_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span)); + let depr = self.tcx.lookup_deprecation_entry(def_id); let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); - let mut is_deprecated = false; - if let Some((depr, _)) = &depr { - is_deprecated = true; - - // `Deprecation` is just two pointers, no need to intern it - let depr_entry = DeprecationEntry::local(*depr, def_id); - self.index.depr_map.insert(def_id, depr_entry); - } else if let Some(parent_depr) = self.parent_depr { - if inherit_deprecation.yes() { - is_deprecated = true; - info!("tagging child {:?} as deprecated from parent", def_id); - self.index.depr_map.insert(def_id, parent_depr); - } - } - if !self.tcx.features().staged_api() { // Propagate unstability. This can happen even for non-staged-api crates in case // -Zforce-unstable-if-unmarked is set. @@ -152,12 +164,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - self.recurse_with_stability_attrs( - depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), - None, - None, - visit_children, - ); + self.recurse_with_stability_attrs(None, None, visit_children); return; } @@ -166,11 +173,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let body_stab = attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability); - if let Some((depr, span)) = &depr - && depr.is_since_rustc_version() + if let Some(depr) = &depr + && depr.attr.is_since_rustc_version() && stab.is_none() + && let Some(depr_span) = attrs::find_attr!(attrs, + AttributeKind::Deprecation { span, .. } => *span + ) { - self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: *span }); + self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: depr_span }); } if let Some(body_stab) = body_stab { @@ -183,7 +193,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let stab = stab.map(|(stab, span)| { // Error if prohibited, or can't inherit anything from a container. if kind == AnnotationKind::Prohibited - || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated) + || (kind == AnnotationKind::Container && stab.level.is_stable() && depr.is_some()) { self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp }); } @@ -195,7 +205,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let ( &Some(DeprecatedSince::RustcVersion(dep_since)), &attrs::StabilityLevel::Stable { since: stab_since, .. }, - ) = (&depr.as_ref().map(|(d, _)| d.since), &stab.level) + ) = (&depr.as_ref().map(|d| d.attr.since), &stab.level) { match stab_since { StableSince::Current => { @@ -343,7 +353,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } self.recurse_with_stability_attrs( - depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), stab, inherit_const_stability.yes().then_some(const_stab).flatten(), visit_children, @@ -352,19 +361,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { fn recurse_with_stability_attrs( &mut self, - depr: Option, stab: Option, const_stab: Option, f: impl FnOnce(&mut Self), ) { // These will be `Some` if this item changes the corresponding stability attribute. - let mut replaced_parent_depr = None; let mut replaced_parent_stab = None; let mut replaced_parent_const_stab = None; - if let Some(depr) = depr { - replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr))); - } if let Some(stab) = stab { replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab))); } @@ -375,9 +379,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { f(self); - if let Some(orig_parent_depr) = replaced_parent_depr { - self.parent_depr = orig_parent_depr; - } if let Some(orig_parent_stab) = replaced_parent_stab { self.parent_stab = orig_parent_stab; } @@ -679,7 +680,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { stab_map: Default::default(), const_stab_map: Default::default(), default_body_stab_map: Default::default(), - depr_map: Default::default(), implications: Default::default(), }; @@ -689,7 +689,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { index: &mut index, parent_stab: None, parent_const_stab: None, - parent_depr: None, in_trait_impl: false, }; @@ -741,7 +740,7 @@ pub(crate) fn provide(providers: &mut Providers) { lookup_stability: |tcx, id| tcx.stability().local_stability(id), lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id), - lookup_deprecation_entry: |tcx, id| tcx.stability().local_deprecation_entry(id), + lookup_deprecation_entry, ..*providers }; } From 408d8162a1ed66d4ea2d48ed83fed73349cc295b Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 14:33:04 +0000 Subject: [PATCH 282/363] Check stability attributes are compatible in `check_unused_or_stable_features`. --- compiler/rustc_passes/src/stability.rs | 342 +++++++++--------- ...rustc-const-stability-require-const.stderr | 48 +-- 2 files changed, 203 insertions(+), 187 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 35332e6e7247..cd29800cce5f 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -6,8 +6,8 @@ use std::num::NonZero; use rustc_ast_lowering::stability::extern_abi_stability; use rustc_attr_data_structures::{ - self as attrs, AttributeKind, ConstStability, DeprecatedSince, PartialConstStability, - Stability, StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, + self as attrs, AttributeKind, ConstStability, DeprecatedSince, Stability, StabilityLevel, + StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; @@ -29,7 +29,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint; use rustc_session::lint::builtin::{DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL}; use rustc_span::{Span, Symbol, sym}; -use tracing::{debug, info}; +use tracing::{debug, info, instrument}; use crate::errors; @@ -96,6 +96,39 @@ fn inherit_deprecation(def_kind: DefKind) -> InheritDeprecation { } } +fn annotation_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> AnnotationKind { + let def_kind = tcx.def_kind(def_id); + match def_kind { + // Inherent impls and foreign modules serve only as containers for other items, + // they don't have their own stability. They still can be annotated as unstable + // and propagate this unstability to children, but this annotation is completely + // optional. They inherit stability from their parents when unannotated. + DefKind::Impl { of_trait: false } | DefKind::ForeignMod => AnnotationKind::Container, + DefKind::Impl { of_trait: true } => AnnotationKind::DeprecationProhibited, + + // Allow stability attributes on default generic arguments. + DefKind::TyParam | DefKind::ConstParam => { + match &tcx.hir_node_by_def_id(def_id).expect_generic_param().kind { + hir::GenericParamKind::Type { default: Some(_), .. } + | hir::GenericParamKind::Const { default: Some(_), .. } => { + AnnotationKind::Container + } + _ => AnnotationKind::Prohibited, + } + } + + // Impl items in trait impls cannot have stability. + DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst => { + match tcx.def_kind(tcx.local_parent(def_id)) { + DefKind::Impl { of_trait: true } => AnnotationKind::Prohibited, + _ => AnnotationKind::Required, + } + } + + _ => AnnotationKind::Required, + } +} + fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); let depr = attrs::find_attr!(attrs, @@ -123,7 +156,6 @@ struct Annotator<'a, 'tcx> { index: &'a mut Index, parent_stab: Option, parent_const_stab: Option, - in_trait_impl: bool, } impl<'a, 'tcx> Annotator<'a, 'tcx> { @@ -133,9 +165,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { fn annotate( &mut self, def_id: LocalDefId, - item_sp: Span, fn_sig: Option<&'tcx hir::FnSig<'tcx>>, - kind: AnnotationKind, inherit_deprecation: InheritDeprecation, inherit_const_stability: InheritConstStability, inherit_from_parent: InheritStability, @@ -146,7 +176,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); - let depr = self.tcx.lookup_deprecation_entry(def_id); let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); if !self.tcx.features().staged_api() { @@ -169,20 +198,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } // # Regular and body stability - let stab = attrs::find_attr!(attrs, AttributeKind::Stability { stability, span } => (*stability, *span)); + let stab = + attrs::find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability); let body_stab = attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability); - if let Some(depr) = &depr - && depr.attr.is_since_rustc_version() - && stab.is_none() - && let Some(depr_span) = attrs::find_attr!(attrs, - AttributeKind::Deprecation { span, .. } => *span - ) - { - self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: depr_span }); - } - if let Some(body_stab) = body_stab { // FIXME: check that this item can have body stability @@ -190,52 +210,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { debug!(?self.index.default_body_stab_map); } - let stab = stab.map(|(stab, span)| { - // Error if prohibited, or can't inherit anything from a container. - if kind == AnnotationKind::Prohibited - || (kind == AnnotationKind::Container && stab.level.is_stable() && depr.is_some()) - { - self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp }); - } - + if let Some(stab) = stab { debug!("annotate: found {:?}", stab); - // Check if deprecated_since < stable_since. If it is, - // this is *almost surely* an accident. - if let ( - &Some(DeprecatedSince::RustcVersion(dep_since)), - &attrs::StabilityLevel::Stable { since: stab_since, .. }, - ) = (&depr.as_ref().map(|d| d.attr.since), &stab.level) - { - match stab_since { - StableSince::Current => { - self.tcx - .dcx() - .emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); - } - StableSince::Version(stab_since) => { - if dep_since < stab_since { - self.tcx - .dcx() - .emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); - } - } - StableSince::Err => { - // An error already reported. Assume the unparseable stabilization - // version is older than the deprecation version. - } - } - } - - // Stable *language* features shouldn't be used as unstable library features. - // (Not doing this for stable library features is checked by tidy.) - if let Stability { level: StabilityLevel::Unstable { .. }, feature } = stab { - if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { - self.tcx - .dcx() - .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp }); - } - } if let Stability { level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, feature, @@ -245,8 +222,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } self.index.stab_map.insert(def_id, stab); - stab - }); + } if stab.is_none() { debug!("annotate: stab not found, parent = {:?}", self.parent_stab); @@ -261,54 +237,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // # Const stability - let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span } => (*stability, *span)); - - // If the current node is a function with const stability attributes (directly given or - // implied), check if the function/method is const or the parent impl block is const. - if let Some(fn_sig) = fn_sig - && !fn_sig.header.is_const() - && const_stab.is_some() - { - self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span }); - } - - // If this is marked const *stable*, it must also be regular-stable. - if let Some((const_stab, const_span)) = const_stab - && let Some(fn_sig) = fn_sig - && const_stab.is_const_stable() - && !stab.is_some_and(|s| s.is_stable()) - { - self.tcx - .dcx() - .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span }); - } - - // Stable *language* features shouldn't be used as unstable library features. - // (Not doing this for stable library features is checked by tidy.) - if let Some(( - PartialConstStability { level: StabilityLevel::Unstable { .. }, feature, .. }, - const_span, - )) = const_stab - { - if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { - self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { - span: const_span, - item_sp, - }); - } - } - - if let Some((stab, span)) = &const_stab - && stab.is_const_stable() - && const_stability_indirect - { - self.tcx.dcx().emit_err(errors::RustcConstStableIndirectPairing { span: *span }); - } + let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability); // After checking the immediate attributes, get rid of the span and compute implied // const stability: inherit feature gate from regular stability. - let mut const_stab = const_stab - .map(|(stab, _span)| ConstStability::from_partial(stab, const_stability_indirect)); + let mut const_stab = + const_stab.map(|stab| ConstStability::from_partial(stab, const_stability_indirect)); // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability. if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() && @@ -399,33 +333,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { - let orig_in_trait_impl = self.in_trait_impl; - let mut kind = AnnotationKind::Required; let mut const_stab_inherit = InheritConstStability::No; let mut fn_sig = None; match i.kind { - // Inherent impls and foreign modules serve only as containers for other items, - // they don't have their own stability. They still can be annotated as unstable - // and propagate this instability to children, but this annotation is completely - // optional. They inherit stability from their parents when unannotated. - hir::ItemKind::Impl(hir::Impl { of_trait: None, .. }) - | hir::ItemKind::ForeignMod { .. } => { - self.in_trait_impl = false; - kind = AnnotationKind::Container; - } hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => { - self.in_trait_impl = true; - kind = AnnotationKind::DeprecationProhibited; const_stab_inherit = InheritConstStability::Yes; } hir::ItemKind::Struct(_, _, ref sd) => { if let Some(ctor_def_id) = sd.ctor_def_id() { self.annotate( ctor_def_id, - i.span, None, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::Yes, @@ -441,15 +360,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { self.annotate( i.owner_id.def_id, - i.span, fn_sig, - kind, InheritDeprecation::Yes, const_stab_inherit, InheritStability::No, |v| intravisit::walk_item(v, i), ); - self.in_trait_impl = orig_in_trait_impl; } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { @@ -460,9 +376,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { self.annotate( ti.owner_id.def_id, - ti.span, fn_sig, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::No, @@ -473,9 +387,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { - let kind = - if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required }; - let fn_sig = match ii.kind { hir::ImplItemKind::Fn(ref fn_sig, _) => Some(fn_sig), _ => None, @@ -483,9 +394,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { self.annotate( ii.owner_id.def_id, - ii.span, fn_sig, - kind, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::No, @@ -498,9 +407,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { self.annotate( var.def_id, - var.span, None, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::Yes, @@ -508,9 +415,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { if let Some(ctor_def_id) = var.data.ctor_def_id() { v.annotate( ctor_def_id, - var.span, None, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::Yes, @@ -526,9 +431,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { self.annotate( s.def_id, - s.span, None, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::Yes, @@ -545,9 +448,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { }; self.annotate( i.owner_id.def_id, - i.span, fn_sig, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::No, @@ -558,18 +459,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - let kind = match &p.kind { - // Allow stability attributes on default generic arguments. - hir::GenericParamKind::Type { default: Some(_), .. } - | hir::GenericParamKind::Const { default: Some(_), .. } => AnnotationKind::Container, - _ => AnnotationKind::Prohibited, - }; - self.annotate( p.def_id, - p.span, None, - kind, InheritDeprecation::No, InheritConstStability::No, InheritStability::No, @@ -586,6 +478,125 @@ struct MissingStabilityAnnotations<'tcx> { } impl<'tcx> MissingStabilityAnnotations<'tcx> { + #[instrument(level = "trace", skip(self))] + fn check_compatible_stability(&self, def_id: LocalDefId, item_sp: Span) { + if !self.tcx.features().staged_api() { + return; + } + + let depr = self.tcx.lookup_deprecation_entry(def_id); + let stab = self.tcx.lookup_stability(def_id); + let const_stab = self.tcx.lookup_const_stability(def_id); + + macro_rules! find_attr_span { + ($name:ident) => {{ + let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); + attrs::find_attr!(attrs, AttributeKind::$name { span, .. } => *span) + }} + } + + if stab.is_none() + && depr.map_or(false, |d| d.attr.is_since_rustc_version()) + && let Some(span) = find_attr_span!(Deprecation) + { + self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span }); + } + + if let Some(stab) = stab { + // Error if prohibited, or can't inherit anything from a container. + let kind = annotation_kind(self.tcx, def_id); + if kind == AnnotationKind::Prohibited + || (kind == AnnotationKind::Container && stab.level.is_stable() && depr.is_some()) + { + if let Some(span) = find_attr_span!(Stability) { + self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp }); + } + } + + // Check if deprecated_since < stable_since. If it is, + // this is *almost surely* an accident. + if let Some(depr) = depr + && let DeprecatedSince::RustcVersion(dep_since) = depr.attr.since + && let attrs::StabilityLevel::Stable { since: stab_since, .. } = stab.level + && let Some(span) = find_attr_span!(Stability) + { + match stab_since { + StableSince::Current => { + self.tcx + .dcx() + .emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); + } + StableSince::Version(stab_since) => { + if dep_since < stab_since { + self.tcx + .dcx() + .emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); + } + } + StableSince::Err => { + // An error already reported. Assume the unparseable stabilization + // version is older than the deprecation version. + } + } + } + + // Stable *language* features shouldn't be used as unstable library features. + // (Not doing this for stable library features is checked by tidy.) + if let Stability { level: StabilityLevel::Unstable { .. }, feature } = stab + && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() + && let Some(span) = find_attr_span!(Stability) + { + self.tcx + .dcx() + .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp }); + } + } + + // If the current node is a function with const stability attributes (directly given or + // implied), check if the function/method is const or the parent impl block is const. + let fn_sig = self.tcx.hir_node_by_def_id(def_id).fn_sig(); + if let Some(fn_sig) = fn_sig + && !fn_sig.header.is_const() + && const_stab.is_some() + && find_attr_span!(ConstStability).is_some() + { + self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span }); + } + + // If this is marked const *stable*, it must also be regular-stable. + if let Some(const_stab) = const_stab + && let Some(fn_sig) = fn_sig + && const_stab.is_const_stable() + && !stab.is_some_and(|s| s.is_stable()) + && let Some(const_span) = find_attr_span!(ConstStability) + { + self.tcx + .dcx() + .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span }); + } + + // Stable *language* features shouldn't be used as unstable library features. + // (Not doing this for stable library features is checked by tidy.) + if let Some(ConstStability { level: StabilityLevel::Unstable { .. }, feature, .. }) = + const_stab + && let Some(const_span) = find_attr_span!(ConstStability) + && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() + { + self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { + span: const_span, + item_sp, + }); + } + + if let Some(stab) = &const_stab + && stab.is_const_stable() + && stab.const_stable_indirect + && let Some(span) = find_attr_span!(ConstStability) + { + self.tcx.dcx().emit_err(errors::RustcConstStableIndirectPairing { span }); + } + } + fn check_missing_stability(&self, def_id: LocalDefId, span: Span) { let stab = self.tcx.stability().local_stability(def_id); if !self.tcx.sess.is_test_crate() @@ -621,6 +632,8 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { + self.check_compatible_stability(i.owner_id.def_id, i.span); + // Inherent impls and foreign modules serve only as containers for other items, // they don't have their own stability. They still can be annotated as unstable // and propagate this instability to children, but this annotation is completely @@ -640,11 +653,13 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { + self.check_compatible_stability(ti.owner_id.def_id, ti.span); self.check_missing_stability(ti.owner_id.def_id, ti.span); intravisit::walk_trait_item(self, ti); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { + self.check_compatible_stability(ii.owner_id.def_id, ii.span); let impl_def_id = self.tcx.hir_get_parent_item(ii.hir_id()); if self.tcx.impl_trait_ref(impl_def_id).is_none() { self.check_missing_stability(ii.owner_id.def_id, ii.span); @@ -654,6 +669,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { + self.check_compatible_stability(var.def_id, var.span); self.check_missing_stability(var.def_id, var.span); if let Some(ctor_def_id) = var.data.ctor_def_id() { self.check_missing_stability(ctor_def_id, var.span); @@ -662,17 +678,24 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { + self.check_compatible_stability(s.def_id, s.span); self.check_missing_stability(s.def_id, s.span); intravisit::walk_field_def(self, s); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { + self.check_compatible_stability(i.owner_id.def_id, i.span); self.check_missing_stability(i.owner_id.def_id, i.span); intravisit::walk_foreign_item(self, i); } - // Note that we don't need to `check_missing_stability` for default generic parameters, - // as we assume that any default generic parameters without attributes are automatically - // stable (assuming they have not inherited instability from their parent). + + fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { + self.check_compatible_stability(p.def_id, p.span); + // Note that we don't need to `check_missing_stability` for default generic parameters, + // as we assume that any default generic parameters without attributes are automatically + // stable (assuming they have not inherited instability from their parent). + intravisit::walk_generic_param(self, p); + } } fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { @@ -684,13 +707,8 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { }; { - let mut annotator = Annotator { - tcx, - index: &mut index, - parent_stab: None, - parent_const_stab: None, - in_trait_impl: false, - }; + let mut annotator = + Annotator { tcx, index: &mut index, parent_stab: None, parent_const_stab: None }; // If the `-Z force-unstable-if-unmarked` flag is passed then we provide // a parent stability annotation which indicates that this is private @@ -714,9 +732,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { annotator.annotate( CRATE_DEF_ID, - tcx.hir_span(CRATE_HIR_ID), None, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::No, diff --git a/tests/ui/consts/rustc-const-stability-require-const.stderr b/tests/ui/consts/rustc-const-stability-require-const.stderr index 4b13826584dc..8d10bddaa45f 100644 --- a/tests/ui/consts/rustc-const-stability-require-const.stderr +++ b/tests/ui/consts/rustc-const-stability-require-const.stderr @@ -22,30 +22,6 @@ help: make the function or method const LL | pub fn bar() {} | ^^^^^^^^^^^^ -error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` - --> $DIR/rustc-const-stability-require-const.rs:21:5 - | -LL | pub fn salad(&self) -> &'static str { "mmmmmm" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: make the function or method const - --> $DIR/rustc-const-stability-require-const.rs:21:5 - | -LL | pub fn salad(&self) -> &'static str { "mmmmmm" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` - --> $DIR/rustc-const-stability-require-const.rs:26:5 - | -LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: make the function or method const - --> $DIR/rustc-const-stability-require-const.rs:26:5 - | -LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` --> $DIR/rustc-const-stability-require-const.rs:32:1 | @@ -86,5 +62,29 @@ LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] LL | pub const fn barfoo_unstable() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` + --> $DIR/rustc-const-stability-require-const.rs:21:5 + | +LL | pub fn salad(&self) -> &'static str { "mmmmmm" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function or method const + --> $DIR/rustc-const-stability-require-const.rs:21:5 + | +LL | pub fn salad(&self) -> &'static str { "mmmmmm" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` + --> $DIR/rustc-const-stability-require-const.rs:26:5 + | +LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function or method const + --> $DIR/rustc-const-stability-require-const.rs:26:5 + | +LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 8 previous errors From 4f38864661720311cb0371f2254fa30e300b47c8 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 13 Jul 2025 11:30:30 +0000 Subject: [PATCH 283/363] Check for already stable features in check_attr. --- compiler/rustc_passes/src/check_attr.rs | 43 ++++++++++++++++--- compiler/rustc_passes/src/errors.rs | 4 +- compiler/rustc_passes/src/stability.rs | 27 +----------- ...ute-rejects-already-stable-features.stderr | 28 ++++++------ 4 files changed, 54 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 44b7afc88ec0..7df008133dee 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -11,11 +11,17 @@ use std::slice; use rustc_abi::{Align, ExternAbi, Size}; use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast, join_path_syms}; -use rustc_attr_data_structures::{AttributeKind, InlineAttr, ReprAttr, find_attr}; +use rustc_attr_data_structures::{ + AttributeKind, InlineAttr, PartialConstStability, ReprAttr, Stability, StabilityLevel, + find_attr, +}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; -use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; +use rustc_feature::{ + ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, + BuiltinAttribute, +}; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; @@ -165,9 +171,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::Impl { of_trait: true }, ), Attribute::Parsed( - AttributeKind::Stability { span, .. } - | AttributeKind::ConstStability { span, .. }, - ) => self.check_stability_promotable(*span, target), + AttributeKind::Stability { + span: attr_span, + stability: Stability { level, feature }, + } + | AttributeKind::ConstStability { + span: attr_span, + stability: PartialConstStability { level, feature, .. }, + }, + ) => self.check_stability(*attr_span, span, level, *feature, target), Attribute::Parsed(AttributeKind::Inline(InlineAttr::Force { .. }, ..)) => {} // handled separately below Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => { self.check_inline(hir_id, *attr_span, span, kind, target) @@ -2319,13 +2331,30 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_stability_promotable(&self, span: Span, target: Target) { + fn check_stability( + &self, + attr_span: Span, + item_span: Span, + level: &StabilityLevel, + feature: Symbol, + target: Target, + ) { match target { Target::Expression => { - self.dcx().emit_err(errors::StabilityPromotable { attr_span: span }); + self.dcx().emit_err(errors::StabilityPromotable { attr_span }); } _ => {} } + + // Stable *language* features shouldn't be used as unstable library features. + // (Not doing this for stable library features is checked by tidy.) + if level.is_unstable() + && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() + { + self.tcx + .dcx() + .emit_err(errors::UnstableAttrForAlreadyStableFeature { attr_span, item_span }); + } } fn check_link_ordinal(&self, attr_span: Span, _span: Span, target: Target) { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 37330c0ed6eb..c6ab6b0d6017 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1373,9 +1373,9 @@ pub(crate) struct UnstableAttrForAlreadyStableFeature { #[primary_span] #[label] #[help] - pub span: Span, + pub attr_span: Span, #[label(passes_item)] - pub item_sp: Span, + pub item_span: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index cd29800cce5f..6fa1c81e569c 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -11,7 +11,7 @@ use rustc_attr_data_structures::{ }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; -use rustc_feature::{ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature}; +use rustc_feature::{EnabledLangFeature, EnabledLibFeature}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::hir_id::CRATE_HIR_ID; @@ -478,6 +478,7 @@ struct MissingStabilityAnnotations<'tcx> { } impl<'tcx> MissingStabilityAnnotations<'tcx> { + /// Verify that deprecation and stability attributes make sense with one another. #[instrument(level = "trace", skip(self))] fn check_compatible_stability(&self, def_id: LocalDefId, item_sp: Span) { if !self.tcx.features().staged_api() { @@ -539,17 +540,6 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } } } - - // Stable *language* features shouldn't be used as unstable library features. - // (Not doing this for stable library features is checked by tidy.) - if let Stability { level: StabilityLevel::Unstable { .. }, feature } = stab - && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() - && let Some(span) = find_attr_span!(Stability) - { - self.tcx - .dcx() - .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp }); - } } // If the current node is a function with const stability attributes (directly given or @@ -575,19 +565,6 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span }); } - // Stable *language* features shouldn't be used as unstable library features. - // (Not doing this for stable library features is checked by tidy.) - if let Some(ConstStability { level: StabilityLevel::Unstable { .. }, feature, .. }) = - const_stab - && let Some(const_span) = find_attr_span!(ConstStability) - && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() - { - self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { - span: const_span, - item_sp, - }); - } - if let Some(stab) = &const_stab && stab.is_const_stable() && stab.const_stable_indirect diff --git a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr index 319056a9c889..d599523c7274 100644 --- a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr +++ b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr @@ -1,3 +1,17 @@ +error: can't mark as unstable using an already stable feature + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 + | +LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable +LL | const fn my_fun() {} + | -------------------- the stability attribute annotates this item + | +help: consider removing the attribute + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 + | +LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: can't mark as unstable using an already stable feature --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 | @@ -13,19 +27,5 @@ help: consider removing the attribute LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: can't mark as unstable using an already stable feature - --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 - | -LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable -LL | const fn my_fun() {} - | -------------------- the stability attribute annotates this item - | -help: consider removing the attribute - --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 - | -LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: aborting due to 2 previous errors From f6ef440816235b5737b5d5d6692328395611767c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 30 Jan 2023 20:47:11 +0000 Subject: [PATCH 284/363] Querify lookup_default_body_stability. --- compiler/rustc_middle/src/middle/stability.rs | 5 --- compiler/rustc_passes/src/stability.rs | 32 +++++++++++-------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 9c2528ca4103..1c90fa66423b 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -72,7 +72,6 @@ pub struct Index { /// are filled by the annotator. pub stab_map: LocalDefIdMap, pub const_stab_map: LocalDefIdMap, - pub default_body_stab_map: LocalDefIdMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute /// exists, then this map will have a `impliee -> implier` entry. @@ -96,10 +95,6 @@ impl Index { pub fn local_const_stability(&self, def_id: LocalDefId) -> Option { self.const_stab_map.get(&def_id).copied() } - - pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option { - self.default_body_stab_map.get(&def_id).copied() - } } pub fn report_unstable( diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 6fa1c81e569c..5445b9305401 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -6,8 +6,8 @@ use std::num::NonZero; use rustc_ast_lowering::stability::extern_abi_stability; use rustc_attr_data_structures::{ - self as attrs, AttributeKind, ConstStability, DeprecatedSince, Stability, StabilityLevel, - StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, + self as attrs, AttributeKind, ConstStability, DefaultBodyStability, DeprecatedSince, Stability, + StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; @@ -150,6 +150,20 @@ fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option, + def_id: LocalDefId, +) -> Option { + if !tcx.features().staged_api() { + return None; + } + + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + // FIXME: check that this item can have body stability + attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability) +} + /// A private tree-walker for producing an `Index`. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -197,18 +211,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { return; } - // # Regular and body stability + // # Regular stability let stab = attrs::find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability); - let body_stab = - attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability); - - if let Some(body_stab) = body_stab { - // FIXME: check that this item can have body stability - - self.index.default_body_stab_map.insert(def_id, body_stab); - debug!(?self.index.default_body_stab_map); - } if let Some(stab) = stab { debug!("annotate: found {:?}", stab); @@ -679,7 +684,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { let mut index = Index { stab_map: Default::default(), const_stab_map: Default::default(), - default_body_stab_map: Default::default(), implications: Default::default(), }; @@ -732,7 +736,7 @@ pub(crate) fn provide(providers: &mut Providers) { stability_implications: |tcx, _| tcx.stability().implications.clone(), lookup_stability: |tcx, id| tcx.stability().local_stability(id), lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), - lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id), + lookup_default_body_stability, lookup_deprecation_entry, ..*providers }; From 1eeb990e190298fb0b2197d52b7337def6f9215e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 10:15:25 +0000 Subject: [PATCH 285/363] Querify lookup_stability. --- compiler/rustc_middle/src/middle/stability.rs | 5 - compiler/rustc_passes/src/stability.rs | 225 +++++++++--------- 2 files changed, 107 insertions(+), 123 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 1c90fa66423b..9ac7ab644747 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -70,7 +70,6 @@ impl DeprecationEntry { pub struct Index { /// This is mostly a cache, except the stabilities of local items /// are filled by the annotator. - pub stab_map: LocalDefIdMap, pub const_stab_map: LocalDefIdMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute @@ -88,10 +87,6 @@ pub struct Index { } impl Index { - pub fn local_stability(&self, def_id: LocalDefId) -> Option { - self.stab_map.get(&def_id).copied() - } - pub fn local_const_stability(&self, def_id: LocalDefId) -> Option { self.const_stab_map.get(&def_id).copied() } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 5445b9305401..3f6414fe962b 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -150,6 +150,78 @@ fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option InheritStability { + match def_kind { + DefKind::Field | DefKind::Variant | DefKind::Ctor(..) => InheritStability::Yes, + _ => InheritStability::No, + } +} + +/// If the `-Z force-unstable-if-unmarked` flag is passed then we provide +/// a parent stability annotation which indicates that this is private +/// with the `rustc_private` feature. This is intended for use when +/// compiling `librustc_*` crates themselves so we can leverage crates.io +/// while maintaining the invariant that all sysroot crates are unstable +/// by default and are unable to be used. +const FORCE_UNSTABLE: Stability = Stability { + level: attrs::StabilityLevel::Unstable { + reason: UnstableReason::Default, + issue: NonZero::new(27812), + is_soft: false, + implied_by: None, + old_name: None, + }, + feature: sym::rustc_private, +}; + +#[instrument(level = "debug", skip(tcx))] +fn lookup_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { + // Propagate unstability. This can happen even for non-staged-api crates in case + // -Zforce-unstable-if-unmarked is set. + if !tcx.features().staged_api() { + if !tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { + return None; + } + + let Some(parent) = tcx.opt_local_parent(def_id) else { return Some(FORCE_UNSTABLE) }; + + if inherit_deprecation(tcx.def_kind(def_id)).yes() { + let parent = tcx.lookup_stability(parent)?; + if parent.is_unstable() { + return Some(parent); + } + } + + return None; + } + + // # Regular stability + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + let stab = + attrs::find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability); + + if let Some(stab) = stab { + return Some(stab); + } + + if inherit_deprecation(tcx.def_kind(def_id)).yes() { + let Some(parent) = tcx.opt_local_parent(def_id) else { + return tcx + .sess + .opts + .unstable_opts + .force_unstable_if_unmarked + .then_some(FORCE_UNSTABLE); + }; + let parent = tcx.lookup_stability(parent)?; + if parent.is_unstable() || inherit_stability(tcx.def_kind(def_id)).yes() { + return Some(parent); + } + } + + None +} + #[instrument(level = "debug", skip(tcx))] fn lookup_default_body_stability( tcx: TyCtxt<'_>, @@ -168,7 +240,6 @@ fn lookup_default_body_stability( struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, index: &'a mut Index, - parent_stab: Option, parent_const_stab: Option, } @@ -182,7 +253,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { fn_sig: Option<&'tcx hir::FnSig<'tcx>>, inherit_deprecation: InheritDeprecation, inherit_const_stability: InheritConstStability, - inherit_from_parent: InheritStability, visit_children: F, ) where F: FnOnce(&mut Self), @@ -190,14 +260,16 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); + let stab = self.tcx.lookup_stability(def_id); let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); if !self.tcx.features().staged_api() { // Propagate unstability. This can happen even for non-staged-api crates in case // -Zforce-unstable-if-unmarked is set. - if let Some(stab) = self.parent_stab { + if let Some(parent_def_id) = self.tcx.opt_local_parent(def_id) + && let Some(stab) = self.tcx.lookup_stability(parent_def_id) + { if inherit_deprecation.yes() && stab.is_unstable() { - self.index.stab_map.insert(def_id, stab); if fn_sig.is_some_and(|s| s.header.is_const()) { self.index.const_stab_map.insert( def_id, @@ -207,39 +279,18 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - self.recurse_with_stability_attrs(None, None, visit_children); + self.recurse_with_stability_attrs(None, visit_children); return; } - // # Regular stability - let stab = - attrs::find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability); - - if let Some(stab) = stab { - debug!("annotate: found {:?}", stab); - - if let Stability { - level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, - feature, - } = stab - { - self.index.implications.insert(implied_by, feature); - } - - self.index.stab_map.insert(def_id, stab); + if let Some(Stability { + level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, + feature, + }) = stab + { + self.index.implications.insert(implied_by, feature); } - if stab.is_none() { - debug!("annotate: stab not found, parent = {:?}", self.parent_stab); - if let Some(stab) = self.parent_stab { - if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() { - self.index.stab_map.insert(def_id, stab); - } - } - } - - let final_stab = self.index.stab_map.get(&def_id); - // # Const stability let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability); @@ -253,7 +304,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() && // We only ever inherit unstable features. let Some(inherit_regular_stab) = - final_stab.filter(|s| s.is_unstable()) + stab.filter(|s| s.is_unstable()) { const_stab = Some(ConstStability { // We subject these implicitly-const functions to recursive const stability. @@ -292,7 +343,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } self.recurse_with_stability_attrs( - stab, inherit_const_stability.yes().then_some(const_stab).flatten(), visit_children, ); @@ -300,17 +350,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { fn recurse_with_stability_attrs( &mut self, - stab: Option, const_stab: Option, f: impl FnOnce(&mut Self), ) { // These will be `Some` if this item changes the corresponding stability attribute. - let mut replaced_parent_stab = None; let mut replaced_parent_const_stab = None; - if let Some(stab) = stab { - replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab))); - } if let Some(const_stab) = const_stab { replaced_parent_const_stab = Some(replace(&mut self.parent_const_stab, Some(const_stab))); @@ -318,9 +363,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { f(self); - if let Some(orig_parent_stab) = replaced_parent_stab { - self.parent_stab = orig_parent_stab; - } if let Some(orig_parent_const_stab) = replaced_parent_const_stab { self.parent_const_stab = orig_parent_const_stab; } @@ -352,7 +394,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { None, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::Yes, |_| {}, ) } @@ -368,7 +409,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn_sig, InheritDeprecation::Yes, const_stab_inherit, - InheritStability::No, |v| intravisit::walk_item(v, i), ); } @@ -384,7 +424,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn_sig, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::No, |v| { intravisit::walk_trait_item(v, ti); }, @@ -402,7 +441,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn_sig, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::No, |v| { intravisit::walk_impl_item(v, ii); }, @@ -410,40 +448,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { - self.annotate( - var.def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - InheritStability::Yes, - |v| { - if let Some(ctor_def_id) = var.data.ctor_def_id() { - v.annotate( - ctor_def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - InheritStability::Yes, - |_| {}, - ); - } + self.annotate(var.def_id, None, InheritDeprecation::Yes, InheritConstStability::No, |v| { + if let Some(ctor_def_id) = var.data.ctor_def_id() { + v.annotate( + ctor_def_id, + None, + InheritDeprecation::Yes, + InheritConstStability::No, + |_| {}, + ); + } - intravisit::walk_variant(v, var) - }, - ) + intravisit::walk_variant(v, var) + }) } fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { - self.annotate( - s.def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - InheritStability::Yes, - |v| { - intravisit::walk_field_def(v, s); - }, - ); + self.annotate(s.def_id, None, InheritDeprecation::Yes, InheritConstStability::No, |v| { + intravisit::walk_field_def(v, s); + }); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { @@ -456,7 +479,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn_sig, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::No, |v| { intravisit::walk_foreign_item(v, i); }, @@ -464,16 +486,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - self.annotate( - p.def_id, - None, - InheritDeprecation::No, - InheritConstStability::No, - InheritStability::No, - |v| { - intravisit::walk_generic_param(v, p); - }, - ); + self.annotate(p.def_id, None, InheritDeprecation::No, InheritConstStability::No, |v| { + intravisit::walk_generic_param(v, p); + }); } } @@ -580,7 +595,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } fn check_missing_stability(&self, def_id: LocalDefId, span: Span) { - let stab = self.tcx.stability().local_stability(def_id); + let stab = self.tcx.lookup_stability(def_id); if !self.tcx.sess.is_test_crate() && stab.is_none() && self.effective_visibilities.is_reachable(def_id) @@ -681,42 +696,16 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { - let mut index = Index { - stab_map: Default::default(), - const_stab_map: Default::default(), - implications: Default::default(), - }; + let mut index = Index { const_stab_map: Default::default(), implications: Default::default() }; { - let mut annotator = - Annotator { tcx, index: &mut index, parent_stab: None, parent_const_stab: None }; - - // If the `-Z force-unstable-if-unmarked` flag is passed then we provide - // a parent stability annotation which indicates that this is private - // with the `rustc_private` feature. This is intended for use when - // compiling `librustc_*` crates themselves so we can leverage crates.io - // while maintaining the invariant that all sysroot crates are unstable - // by default and are unable to be used. - if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { - let stability = Stability { - level: attrs::StabilityLevel::Unstable { - reason: UnstableReason::Default, - issue: NonZero::new(27812), - is_soft: false, - implied_by: None, - old_name: None, - }, - feature: sym::rustc_private, - }; - annotator.parent_stab = Some(stability); - } + let mut annotator = Annotator { tcx, index: &mut index, parent_const_stab: None }; annotator.annotate( CRATE_DEF_ID, None, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::No, |v| tcx.hir_walk_toplevel_module(v), ); } @@ -734,7 +723,7 @@ pub(crate) fn provide(providers: &mut Providers) { check_mod_unstable_api_usage, stability_index, stability_implications: |tcx, _| tcx.stability().implications.clone(), - lookup_stability: |tcx, id| tcx.stability().local_stability(id), + lookup_stability, lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), lookup_default_body_stability, lookup_deprecation_entry, @@ -1042,7 +1031,7 @@ fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { }; let def_id = owner.def_id; - let Some(stab) = tcx.stability().local_stability(def_id) else { + let Some(stab) = tcx.lookup_stability(def_id) else { return false; }; From 62bd3c465fcde0b8cd6f0160785ba558548d3951 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 10:41:16 +0000 Subject: [PATCH 286/363] Querify lookup_const_stability. --- compiler/rustc_middle/src/middle/stability.rs | 11 +- compiler/rustc_passes/src/stability.rs | 282 +++++++----------- 2 files changed, 109 insertions(+), 184 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 9ac7ab644747..2dcf10deb54c 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -10,7 +10,7 @@ use rustc_attr_data_structures::{ use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_feature::GateIssue; -use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, HirId}; use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic}; use rustc_session::Session; @@ -68,9 +68,6 @@ impl DeprecationEntry { /// A stability index, giving the stability level for items and methods. #[derive(HashStable, Debug)] pub struct Index { - /// This is mostly a cache, except the stabilities of local items - /// are filled by the annotator. - pub const_stab_map: LocalDefIdMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute /// exists, then this map will have a `impliee -> implier` entry. @@ -86,12 +83,6 @@ pub struct Index { pub implications: UnordMap, } -impl Index { - pub fn local_const_stability(&self, def_id: LocalDefId) -> Option { - self.const_stab_map.get(&def_id).copied() - } -} - pub fn report_unstable( sess: &Session, feature: Symbol, diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 3f6414fe962b..b47742df12be 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -1,7 +1,6 @@ //! A pass that annotates every item and method with its stability level, //! propagating default levels lexically from parent to children ast nodes. -use std::mem::replace; use std::num::NonZero; use rustc_ast_lowering::stability::extern_abi_stability; @@ -96,6 +95,19 @@ fn inherit_deprecation(def_kind: DefKind) -> InheritDeprecation { } } +fn inherit_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> InheritConstStability { + let def_kind = tcx.def_kind(def_id); + match def_kind { + DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { + match tcx.def_kind(tcx.local_parent(def_id)) { + DefKind::Impl { of_trait: true } => InheritConstStability::Yes, + _ => InheritConstStability::No, + } + } + _ => InheritConstStability::No, + } +} + fn annotation_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> AnnotationKind { let def_kind = tcx.def_kind(def_id); match def_kind { @@ -236,50 +248,96 @@ fn lookup_default_body_stability( attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability) } +#[instrument(level = "debug", skip(tcx))] +fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { + if !tcx.features().staged_api() { + // Propagate unstability. This can happen even for non-staged-api crates in case + // -Zforce-unstable-if-unmarked is set. + if inherit_deprecation(tcx.def_kind(def_id)).yes() { + let parent = tcx.opt_local_parent(def_id)?; + let parent_stab = tcx.lookup_stability(parent)?; + if parent_stab.is_unstable() + && let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig() + && fn_sig.header.is_const() + { + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + let const_stability_indirect = + find_attr!(attrs, AttributeKind::ConstStabilityIndirect); + return Some(ConstStability::unmarked(const_stability_indirect, parent_stab)); + } + } + + return None; + } + + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); + let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability); + + // After checking the immediate attributes, get rid of the span and compute implied + // const stability: inherit feature gate from regular stability. + let mut const_stab = const_stab + .map(|const_stab| ConstStability::from_partial(const_stab, const_stability_indirect)); + + // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability. + if let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig() + && fn_sig.header.is_const() + && const_stab.is_none() + // We only ever inherit unstable features. + && let Some(inherit_regular_stab) = tcx.lookup_stability(def_id) + && inherit_regular_stab.is_unstable() + { + const_stab = Some(ConstStability { + // We subject these implicitly-const functions to recursive const stability. + const_stable_indirect: true, + promotable: false, + level: inherit_regular_stab.level, + feature: inherit_regular_stab.feature, + }); + } + + // Now that everything is computed, insert it into the table. + if let Some(const_stab) = const_stab { + return Some(const_stab); + } + + // `impl const Trait for Type` items forward their const stability to their + // immediate children. + // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`? + // Currently, once that is set, we do not inherit anything from the parent any more. + if inherit_const_stability(tcx, def_id).yes() { + let parent = tcx.opt_local_parent(def_id)?; + let parent = tcx.lookup_const_stability(parent)?; + if parent.is_const_unstable() { + return Some(parent); + } + } + + None +} + /// A private tree-walker for producing an `Index`. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, index: &'a mut Index, - parent_const_stab: Option, } impl<'a, 'tcx> Annotator<'a, 'tcx> { /// Determine the stability for a node based on its attributes and inherited stability. The /// stability is recorded in the index and used as the parent. If the node is a function, /// `fn_sig` is its signature. - fn annotate( - &mut self, - def_id: LocalDefId, - fn_sig: Option<&'tcx hir::FnSig<'tcx>>, - inherit_deprecation: InheritDeprecation, - inherit_const_stability: InheritConstStability, - visit_children: F, - ) where + #[instrument(level = "trace", skip(self, visit_children))] + fn annotate(&mut self, def_id: LocalDefId, visit_children: F) + where F: FnOnce(&mut Self), { let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); let stab = self.tcx.lookup_stability(def_id); - let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); if !self.tcx.features().staged_api() { - // Propagate unstability. This can happen even for non-staged-api crates in case - // -Zforce-unstable-if-unmarked is set. - if let Some(parent_def_id) = self.tcx.opt_local_parent(def_id) - && let Some(stab) = self.tcx.lookup_stability(parent_def_id) - { - if inherit_deprecation.yes() && stab.is_unstable() { - if fn_sig.is_some_and(|s| s.header.is_const()) { - self.index.const_stab_map.insert( - def_id, - ConstStability::unmarked(const_stability_indirect, stab), - ); - } - } - } - - self.recurse_with_stability_attrs(None, visit_children); + visit_children(self); return; } @@ -293,32 +351,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // # Const stability - let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability); - - // After checking the immediate attributes, get rid of the span and compute implied - // const stability: inherit feature gate from regular stability. - let mut const_stab = - const_stab.map(|stab| ConstStability::from_partial(stab, const_stability_indirect)); - - // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability. - if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() && - // We only ever inherit unstable features. - let Some(inherit_regular_stab) = - stab.filter(|s| s.is_unstable()) - { - const_stab = Some(ConstStability { - // We subject these implicitly-const functions to recursive const stability. - const_stable_indirect: true, - promotable: false, - level: inherit_regular_stab.level, - feature: inherit_regular_stab.feature, - }); - } - - // Now that everything is computed, insert it into the table. - const_stab.inspect(|const_stab| { - self.index.const_stab_map.insert(def_id, *const_stab); - }); + let const_stab = self.tcx.lookup_const_stability(def_id); if let Some(ConstStability { level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, @@ -329,43 +362,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { self.index.implications.insert(implied_by, feature); } - // `impl const Trait for Type` items forward their const stability to their - // immediate children. - // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`? - // Currently, once that is set, we do not inherit anything from the parent any more. - if const_stab.is_none() { - debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab); - if let Some(parent) = self.parent_const_stab { - if parent.is_const_unstable() { - self.index.const_stab_map.insert(def_id, parent); - } - } - } - - self.recurse_with_stability_attrs( - inherit_const_stability.yes().then_some(const_stab).flatten(), - visit_children, - ); - } - - fn recurse_with_stability_attrs( - &mut self, - const_stab: Option, - f: impl FnOnce(&mut Self), - ) { - // These will be `Some` if this item changes the corresponding stability attribute. - let mut replaced_parent_const_stab = None; - - if let Some(const_stab) = const_stab { - replaced_parent_const_stab = - Some(replace(&mut self.parent_const_stab, Some(const_stab))); - } - - f(self); - - if let Some(orig_parent_const_stab) = replaced_parent_const_stab { - self.parent_const_stab = orig_parent_const_stab; - } + visit_children(self) } } @@ -380,83 +377,34 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { - let mut const_stab_inherit = InheritConstStability::No; - let mut fn_sig = None; - match i.kind { - hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => { - const_stab_inherit = InheritConstStability::Yes; - } hir::ItemKind::Struct(_, _, ref sd) => { if let Some(ctor_def_id) = sd.ctor_def_id() { - self.annotate( - ctor_def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - |_| {}, - ) + self.annotate(ctor_def_id, |_| {}) } } - hir::ItemKind::Fn { sig: ref item_fn_sig, .. } => { - fn_sig = Some(item_fn_sig); - } _ => {} } - self.annotate( - i.owner_id.def_id, - fn_sig, - InheritDeprecation::Yes, - const_stab_inherit, - |v| intravisit::walk_item(v, i), - ); + self.annotate(i.owner_id.def_id, |v| intravisit::walk_item(v, i)); } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { - let fn_sig = match ti.kind { - hir::TraitItemKind::Fn(ref fn_sig, _) => Some(fn_sig), - _ => None, - }; - - self.annotate( - ti.owner_id.def_id, - fn_sig, - InheritDeprecation::Yes, - InheritConstStability::No, - |v| { - intravisit::walk_trait_item(v, ti); - }, - ); + self.annotate(ti.owner_id.def_id, |v| { + intravisit::walk_trait_item(v, ti); + }); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { - let fn_sig = match ii.kind { - hir::ImplItemKind::Fn(ref fn_sig, _) => Some(fn_sig), - _ => None, - }; - - self.annotate( - ii.owner_id.def_id, - fn_sig, - InheritDeprecation::Yes, - InheritConstStability::No, - |v| { - intravisit::walk_impl_item(v, ii); - }, - ); + self.annotate(ii.owner_id.def_id, |v| { + intravisit::walk_impl_item(v, ii); + }); } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { - self.annotate(var.def_id, None, InheritDeprecation::Yes, InheritConstStability::No, |v| { + self.annotate(var.def_id, |v| { if let Some(ctor_def_id) = var.data.ctor_def_id() { - v.annotate( - ctor_def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - |_| {}, - ); + v.annotate(ctor_def_id, |_| {}); } intravisit::walk_variant(v, var) @@ -464,29 +412,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { - self.annotate(s.def_id, None, InheritDeprecation::Yes, InheritConstStability::No, |v| { + self.annotate(s.def_id, |v| { intravisit::walk_field_def(v, s); }); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { - let fn_sig = match &i.kind { - rustc_hir::ForeignItemKind::Fn(fn_sig, ..) => Some(fn_sig), - _ => None, - }; - self.annotate( - i.owner_id.def_id, - fn_sig, - InheritDeprecation::Yes, - InheritConstStability::No, - |v| { - intravisit::walk_foreign_item(v, i); - }, - ); + self.annotate(i.owner_id.def_id, |v| { + intravisit::walk_foreign_item(v, i); + }); } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - self.annotate(p.def_id, None, InheritDeprecation::No, InheritConstStability::No, |v| { + self.annotate(p.def_id, |v| { intravisit::walk_generic_param(v, p); }); } @@ -594,8 +532,10 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } } + #[instrument(level = "debug", skip(self))] fn check_missing_stability(&self, def_id: LocalDefId, span: Span) { let stab = self.tcx.lookup_stability(def_id); + self.tcx.ensure_ok().lookup_const_stability(def_id); if !self.tcx.sess.is_test_crate() && stab.is_none() && self.effective_visibilities.is_reachable(def_id) @@ -696,18 +636,12 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { - let mut index = Index { const_stab_map: Default::default(), implications: Default::default() }; + let mut index = Index { implications: Default::default() }; { - let mut annotator = Annotator { tcx, index: &mut index, parent_const_stab: None }; + let mut annotator = Annotator { tcx, index: &mut index }; - annotator.annotate( - CRATE_DEF_ID, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - |v| tcx.hir_walk_toplevel_module(v), - ); + annotator.annotate(CRATE_DEF_ID, |v| tcx.hir_walk_toplevel_module(v)); } index } @@ -724,7 +658,7 @@ pub(crate) fn provide(providers: &mut Providers) { stability_index, stability_implications: |tcx, _| tcx.stability().implications.clone(), lookup_stability, - lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), + lookup_const_stability, lookup_default_body_stability, lookup_deprecation_entry, ..*providers From 06f104fd7760eb28b6722f9509adaf6a63226567 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 10:57:57 +0000 Subject: [PATCH 287/363] Simplify annotator. --- compiler/rustc_passes/src/stability.rs | 88 +++++++++----------------- 1 file changed, 30 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index b47742df12be..c11c3d10451c 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -28,7 +28,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint; use rustc_session::lint::builtin::{DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL}; use rustc_span::{Span, Symbol, sym}; -use tracing::{debug, info, instrument}; +use tracing::{info, instrument}; use crate::errors; @@ -326,43 +326,23 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { /// Determine the stability for a node based on its attributes and inherited stability. The /// stability is recorded in the index and used as the parent. If the node is a function, /// `fn_sig` is its signature. - #[instrument(level = "trace", skip(self, visit_children))] - fn annotate(&mut self, def_id: LocalDefId, visit_children: F) - where - F: FnOnce(&mut Self), - { - let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); - debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); - - let stab = self.tcx.lookup_stability(def_id); - + #[instrument(level = "trace", skip(self))] + fn annotate(&mut self, def_id: LocalDefId) { if !self.tcx.features().staged_api() { - visit_children(self); return; } - if let Some(Stability { - level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, - feature, - }) = stab + if let Some(stability) = self.tcx.lookup_stability(def_id) + && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level { - self.index.implications.insert(implied_by, feature); + self.index.implications.insert(implied_by, stability.feature); } - // # Const stability - - let const_stab = self.tcx.lookup_const_stability(def_id); - - if let Some(ConstStability { - level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, - feature, - .. - }) = const_stab + if let Some(stability) = self.tcx.lookup_const_stability(def_id) + && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level { - self.index.implications.insert(implied_by, feature); + self.index.implications.insert(implied_by, stability.feature); } - - visit_children(self) } } @@ -380,53 +360,48 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { match i.kind { hir::ItemKind::Struct(_, _, ref sd) => { if let Some(ctor_def_id) = sd.ctor_def_id() { - self.annotate(ctor_def_id, |_| {}) + self.annotate(ctor_def_id); } } _ => {} } - self.annotate(i.owner_id.def_id, |v| intravisit::walk_item(v, i)); + self.annotate(i.owner_id.def_id); + intravisit::walk_item(self, i) } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { - self.annotate(ti.owner_id.def_id, |v| { - intravisit::walk_trait_item(v, ti); - }); + self.annotate(ti.owner_id.def_id); + intravisit::walk_trait_item(self, ti); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { - self.annotate(ii.owner_id.def_id, |v| { - intravisit::walk_impl_item(v, ii); - }); + self.annotate(ii.owner_id.def_id); + intravisit::walk_impl_item(self, ii); } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { - self.annotate(var.def_id, |v| { - if let Some(ctor_def_id) = var.data.ctor_def_id() { - v.annotate(ctor_def_id, |_| {}); - } + self.annotate(var.def_id); + if let Some(ctor_def_id) = var.data.ctor_def_id() { + self.annotate(ctor_def_id); + } - intravisit::walk_variant(v, var) - }) + intravisit::walk_variant(self, var) } fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { - self.annotate(s.def_id, |v| { - intravisit::walk_field_def(v, s); - }); + self.annotate(s.def_id); + intravisit::walk_field_def(self, s); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { - self.annotate(i.owner_id.def_id, |v| { - intravisit::walk_foreign_item(v, i); - }); + self.annotate(i.owner_id.def_id); + intravisit::walk_foreign_item(self, i); } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - self.annotate(p.def_id, |v| { - intravisit::walk_generic_param(v, p); - }); + self.annotate(p.def_id); + intravisit::walk_generic_param(self, p); } } @@ -637,12 +612,9 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { let mut index = Index { implications: Default::default() }; - - { - let mut annotator = Annotator { tcx, index: &mut index }; - - annotator.annotate(CRATE_DEF_ID, |v| tcx.hir_walk_toplevel_module(v)); - } + let mut annotator = Annotator { tcx, index: &mut index }; + annotator.annotate(CRATE_DEF_ID); + tcx.hir_walk_toplevel_module(&mut annotator); index } From f7e0891423cff18731e9c4616d0e99d404e914de Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 10:58:33 +0000 Subject: [PATCH 288/363] Retire stability_index query. --- compiler/rustc_interface/src/passes.rs | 1 - compiler/rustc_middle/src/middle/stability.rs | 19 ------------- compiler/rustc_middle/src/query/mod.rs | 19 +++++++++---- compiler/rustc_middle/src/ty/context.rs | 6 +--- compiler/rustc_passes/src/stability.rs | 28 ++++++++----------- 5 files changed, 26 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index a438cde018c6..998661d635a4 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1065,7 +1065,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { // This marks the corresponding crate-level attributes // as used, and ensures that their values are valid. tcx.ensure_ok().limits(()); - tcx.ensure_ok().stability_index(()); } ); }); diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 2dcf10deb54c..dc9311188e80 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -7,7 +7,6 @@ use rustc_ast::NodeId; use rustc_attr_data_structures::{ self as attrs, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, }; -use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_feature::GateIssue; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -65,24 +64,6 @@ impl DeprecationEntry { } } -/// A stability index, giving the stability level for items and methods. -#[derive(HashStable, Debug)] -pub struct Index { - /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` - /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute - /// exists, then this map will have a `impliee -> implier` entry. - /// - /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should - /// specify their implications (both `implies` and `implied_by`). If only one of the two - /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this - /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is - /// reported, only the `#[stable]` attribute information is available, so the map is necessary - /// to know that the feature implies another feature. If it were reversed, and the `#[stable]` - /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of - /// unstable feature" error for a feature that was implied. - pub implications: UnordMap, -} - pub fn report_unstable( sess: &Session, feature: Symbol, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 935cc8895740..855b2e0cfecd 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -112,7 +112,7 @@ use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::EffectiveVisibilities; use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg}; -use crate::middle::stability::{self, DeprecationEntry}; +use crate::middle::stability::DeprecationEntry; use crate::mir::interpret::{ EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId, LitToConstInput, @@ -2162,6 +2162,18 @@ rustc_queries! { separate_provide_extern arena_cache } + /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` + /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute + /// exists, then this map will have a `impliee -> implier` entry. + /// + /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should + /// specify their implications (both `implies` and `implied_by`). If only one of the two + /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this + /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is + /// reported, only the `#[stable]` attribute information is available, so the map is necessary + /// to know that the feature implies another feature. If it were reversed, and the `#[stable]` + /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of + /// unstable feature" error for a feature that was implied. query stability_implications(_: CrateNum) -> &'tcx UnordMap { arena_cache desc { "calculating the implications between `#[unstable]` features defined in a crate" } @@ -2268,11 +2280,6 @@ rustc_queries! { desc { "fetching potentially unused trait imports" } } - query stability_index(_: ()) -> &'tcx stability::Index { - arena_cache - eval_always - desc { "calculating the stability index for the local crate" } - } /// All available crates in the graph, including those that should not be user-facing /// (such as private crates). query crates(_: ()) -> &'tcx [CrateNum] { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 915b062417f2..0979d04e4bf2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -65,7 +65,7 @@ use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind, Canonica use crate::lint::lint_level; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature}; -use crate::middle::{resolve_bound_vars, stability}; +use crate::middle::resolve_bound_vars; use crate::mir::interpret::{self, Allocation, ConstAllocation}; use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted}; use crate::query::plumbing::QuerySystem; @@ -1807,10 +1807,6 @@ impl<'tcx> TyCtxt<'tcx> { ) } - pub fn stability(self) -> &'tcx stability::Index { - self.stability_index(()) - } - pub fn features(self) -> &'tcx rustc_feature::Features { self.features_query(()) } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index c11c3d10451c..489fa09faec8 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -19,10 +19,8 @@ use rustc_hir::{self as hir, AmbigArg, FieldDef, Item, ItemKind, TraitRef, Ty, T use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; use rustc_middle::middle::privacy::EffectiveVisibilities; -use rustc_middle::middle::stability::{ - AllowUnstable, Deprecated, DeprecationEntry, EvalResult, Index, -}; -use rustc_middle::query::Providers; +use rustc_middle::middle::stability::{AllowUnstable, Deprecated, DeprecationEntry, EvalResult}; +use rustc_middle::query::{LocalCrate, Providers}; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint; @@ -317,12 +315,12 @@ fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { +struct Annotator<'tcx> { tcx: TyCtxt<'tcx>, - index: &'a mut Index, + implications: UnordMap, } -impl<'a, 'tcx> Annotator<'a, 'tcx> { +impl<'tcx> Annotator<'tcx> { /// Determine the stability for a node based on its attributes and inherited stability. The /// stability is recorded in the index and used as the parent. If the node is a function, /// `fn_sig` is its signature. @@ -335,18 +333,18 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let Some(stability) = self.tcx.lookup_stability(def_id) && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level { - self.index.implications.insert(implied_by, stability.feature); + self.implications.insert(implied_by, stability.feature); } if let Some(stability) = self.tcx.lookup_const_stability(def_id) && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level { - self.index.implications.insert(implied_by, stability.feature); + self.implications.insert(implied_by, stability.feature); } } } -impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for Annotator<'tcx> { /// Because stability levels are scoped lexically, we want to walk /// nested items in the context of the outer item, so enable /// deep-walking. @@ -610,12 +608,11 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } } -fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { - let mut index = Index { implications: Default::default() }; - let mut annotator = Annotator { tcx, index: &mut index }; +fn stability_implications(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> UnordMap { + let mut annotator = Annotator { tcx, implications: Default::default() }; annotator.annotate(CRATE_DEF_ID); tcx.hir_walk_toplevel_module(&mut annotator); - index + annotator.implications } /// Cross-references the feature names of unstable APIs with enabled @@ -627,8 +624,7 @@ fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { check_mod_unstable_api_usage, - stability_index, - stability_implications: |tcx, _| tcx.stability().implications.clone(), + stability_implications, lookup_stability, lookup_const_stability, lookup_default_body_stability, From 3301ac5f7ba902d445e9484e1e73d80763de4a7e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 30 Jan 2022 15:41:35 +0100 Subject: [PATCH 289/363] Integrate stable feature checking into a query. --- compiler/rustc_interface/src/passes.rs | 5 -- compiler/rustc_passes/src/stability.rs | 69 +++++++++++-------- ...issue-43106-gating-of-builtin-attrs.stderr | 16 ++--- .../ui/lint/lint-stability-deprecated.stderr | 20 +++--- tests/ui/lint/lint-stability.stderr | 18 ++--- tests/ui/missing/missing-stability.stderr | 9 +-- .../effective_visibilities_invariants.stderr | 2 +- tests/ui/privacy/issue-113860-1.stderr | 18 ++--- tests/ui/privacy/issue-113860-2.stderr | 18 ++--- tests/ui/privacy/issue-113860.stderr | 18 ++--- .../missing-const-stability.stderr | 14 ++-- .../stability-attribute-sanity-3.stderr | 6 +- 12 files changed, 93 insertions(+), 120 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 998661d635a4..fb6897c7d895 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1054,11 +1054,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { tcx.ensure_ok().check_mod_unstable_api_usage(module); }); }, - { - sess.time("unused_lib_feature_checking", || { - rustc_passes::stability::check_unused_or_stable_features(tcx) - }); - }, { // We force these queries to run, // since they might not otherwise get called. diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 489fa09faec8..61827dde64f1 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -13,7 +13,6 @@ use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; use rustc_feature::{EnabledLangFeature, EnabledLibFeature}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; -use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{self, Visitor, VisitorExt}; use rustc_hir::{self as hir, AmbigArg, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::nested_filter; @@ -411,7 +410,7 @@ struct MissingStabilityAnnotations<'tcx> { impl<'tcx> MissingStabilityAnnotations<'tcx> { /// Verify that deprecation and stability attributes make sense with one another. #[instrument(level = "trace", skip(self))] - fn check_compatible_stability(&self, def_id: LocalDefId, item_sp: Span) { + fn check_compatible_stability(&self, def_id: LocalDefId) { if !self.tcx.features().staged_api() { return; } @@ -441,6 +440,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { || (kind == AnnotationKind::Container && stab.level.is_stable() && depr.is_some()) { if let Some(span) = find_attr_span!(Stability) { + let item_sp = self.tcx.def_span(def_id); self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp }); } } @@ -452,6 +452,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { && let attrs::StabilityLevel::Stable { since: stab_since, .. } = stab.level && let Some(span) = find_attr_span!(Stability) { + let item_sp = self.tcx.def_span(def_id); match stab_since { StableSince::Current => { self.tcx @@ -506,7 +507,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } #[instrument(level = "debug", skip(self))] - fn check_missing_stability(&self, def_id: LocalDefId, span: Span) { + fn check_missing_stability(&self, def_id: LocalDefId) { let stab = self.tcx.lookup_stability(def_id); self.tcx.ensure_ok().lookup_const_stability(def_id); if !self.tcx.sess.is_test_crate() @@ -514,11 +515,12 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { && self.effective_visibilities.is_reachable(def_id) { let descr = self.tcx.def_descr(def_id.to_def_id()); + let span = self.tcx.def_span(def_id); self.tcx.dcx().emit_err(errors::MissingStabilityAttr { span, descr }); } } - fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) { + fn check_missing_const_stability(&self, def_id: LocalDefId) { let is_const = self.tcx.is_const_fn(def_id.to_def_id()) || (self.tcx.def_kind(def_id.to_def_id()) == DefKind::Trait && self.tcx.is_const_trait(def_id.to_def_id())); @@ -528,6 +530,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { && self.effective_visibilities.is_reachable(def_id) && self.tcx.lookup_const_stability(def_id).is_none() { + let span = self.tcx.def_span(def_id); let descr = self.tcx.def_descr(def_id.to_def_id()); self.tcx.dcx().emit_err(errors::MissingConstStabAttr { span, descr }); } @@ -542,7 +545,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { - self.check_compatible_stability(i.owner_id.def_id, i.span); + self.check_compatible_stability(i.owner_id.def_id); // Inherent impls and foreign modules serve only as containers for other items, // they don't have their own stability. They still can be annotated as unstable @@ -553,54 +556,54 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { hir::ItemKind::Impl(hir::Impl { of_trait: None, .. }) | hir::ItemKind::ForeignMod { .. } ) { - self.check_missing_stability(i.owner_id.def_id, i.span); + self.check_missing_stability(i.owner_id.def_id); } // Ensure stable `const fn` have a const stability attribute. - self.check_missing_const_stability(i.owner_id.def_id, i.span); + self.check_missing_const_stability(i.owner_id.def_id); intravisit::walk_item(self, i) } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { - self.check_compatible_stability(ti.owner_id.def_id, ti.span); - self.check_missing_stability(ti.owner_id.def_id, ti.span); + self.check_compatible_stability(ti.owner_id.def_id); + self.check_missing_stability(ti.owner_id.def_id); intravisit::walk_trait_item(self, ti); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { - self.check_compatible_stability(ii.owner_id.def_id, ii.span); + self.check_compatible_stability(ii.owner_id.def_id); let impl_def_id = self.tcx.hir_get_parent_item(ii.hir_id()); if self.tcx.impl_trait_ref(impl_def_id).is_none() { - self.check_missing_stability(ii.owner_id.def_id, ii.span); - self.check_missing_const_stability(ii.owner_id.def_id, ii.span); + self.check_missing_stability(ii.owner_id.def_id); + self.check_missing_const_stability(ii.owner_id.def_id); } intravisit::walk_impl_item(self, ii); } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { - self.check_compatible_stability(var.def_id, var.span); - self.check_missing_stability(var.def_id, var.span); + self.check_compatible_stability(var.def_id); + self.check_missing_stability(var.def_id); if let Some(ctor_def_id) = var.data.ctor_def_id() { - self.check_missing_stability(ctor_def_id, var.span); + self.check_missing_stability(ctor_def_id); } intravisit::walk_variant(self, var); } fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { - self.check_compatible_stability(s.def_id, s.span); - self.check_missing_stability(s.def_id, s.span); + self.check_compatible_stability(s.def_id); + self.check_missing_stability(s.def_id); intravisit::walk_field_def(self, s); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { - self.check_compatible_stability(i.owner_id.def_id, i.span); - self.check_missing_stability(i.owner_id.def_id, i.span); + self.check_compatible_stability(i.owner_id.def_id); + self.check_missing_stability(i.owner_id.def_id); intravisit::walk_foreign_item(self, i); } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - self.check_compatible_stability(p.def_id, p.span); + self.check_compatible_stability(p.def_id); // Note that we don't need to `check_missing_stability` for default generic parameters, // as we assume that any default generic parameters without attributes are automatically // stable (assuming they have not inherited instability from their parent). @@ -619,6 +622,21 @@ fn stability_implications(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> UnordMap, module_def_id: LocalModDefId) { tcx.hir_visit_item_likes_in_module(module_def_id, &mut Checker { tcx }); + + let is_staged_api = + tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api(); + if is_staged_api { + let effective_visibilities = &tcx.effective_visibilities(()); + let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities }; + if module_def_id.is_top_level_module() { + missing.check_missing_stability(CRATE_DEF_ID); + } + tcx.hir_visit_item_likes_in_module(module_def_id, &mut missing); + } + + if module_def_id.is_top_level_module() { + check_unused_or_stable_features(tcx) + } } pub(crate) fn provide(providers: &mut Providers) { @@ -1002,16 +1020,9 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> { /// Given the list of enabled features that were not language features (i.e., that /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. +// This is `pub` for rustdoc. rustc should call it through `check_mod_unstable_api_usage`. pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { - let is_staged_api = - tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api(); - if is_staged_api { - let effective_visibilities = &tcx.effective_visibilities(()); - let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities }; - missing.check_missing_stability(CRATE_DEF_ID, tcx.hir_span(CRATE_HIR_ID)); - tcx.hir_walk_toplevel_module(&mut missing); - tcx.hir_visit_all_item_likes_in_crate(&mut missing); - } + let _prof_timer = tcx.sess.timer("unused_lib_feature_checking"); let enabled_lang_features = tcx.features().enabled_lang_features(); let mut lang_features = UnordSet::default(); 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 3271aa0620b9..9016ca1efa76 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 @@ -417,6 +417,14 @@ LL | #![cold] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:85:12 + | +LL | #![feature(rust1)] + | ^^^^^ + | + = note: `#[warn(stable_features)]` on by default + warning: `#[macro_use]` only has an effect on `extern crate` and modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:5 | @@ -1161,13 +1169,5 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:85:12 - | -LL | #![feature(rust1)] - | ^^^^^ - | - = note: `#[warn(stable_features)]` on by default - warning: 173 warnings emitted diff --git a/tests/ui/lint/lint-stability-deprecated.stderr b/tests/ui/lint/lint-stability-deprecated.stderr index 51205ff43406..0399fab746ec 100644 --- a/tests/ui/lint/lint-stability-deprecated.stderr +++ b/tests/ui/lint/lint-stability-deprecated.stderr @@ -1,8 +1,8 @@ -warning: use of deprecated function `lint_stability::deprecated`: text - --> $DIR/lint-stability-deprecated.rs:24:9 +warning: use of deprecated associated type `lint_stability::TraitWithAssociatedTypes::TypeDeprecated`: text + --> $DIR/lint-stability-deprecated.rs:97:48 | -LL | deprecated(); - | ^^^^^^^^^^ +LL | struct S2(T::TypeDeprecated); + | ^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/lint-stability-deprecated.rs:6:9 @@ -10,6 +10,12 @@ note: the lint level is defined here LL | #![warn(deprecated)] | ^^^^^^^^^^ +warning: use of deprecated function `lint_stability::deprecated`: text + --> $DIR/lint-stability-deprecated.rs:24:9 + | +LL | deprecated(); + | ^^^^^^^^^^ + warning: use of deprecated method `lint_stability::Trait::trait_deprecated`: text --> $DIR/lint-stability-deprecated.rs:29:16 | @@ -316,12 +322,6 @@ warning: use of deprecated function `this_crate::MethodTester::test_method_body: LL | fn_in_body(); | ^^^^^^^^^^ -warning: use of deprecated associated type `lint_stability::TraitWithAssociatedTypes::TypeDeprecated`: text - --> $DIR/lint-stability-deprecated.rs:97:48 - | -LL | struct S2(T::TypeDeprecated); - | ^^^^^^^^^^^^^^^^^ - warning: use of deprecated associated type `lint_stability::TraitWithAssociatedTypes::TypeDeprecated`: text --> $DIR/lint-stability-deprecated.rs:101:13 | diff --git a/tests/ui/lint/lint-stability.stderr b/tests/ui/lint/lint-stability.stderr index fd57908a77b5..249f3ccaa542 100644 --- a/tests/ui/lint/lint-stability.stderr +++ b/tests/ui/lint/lint-stability.stderr @@ -1,3 +1,12 @@ +error[E0658]: use of unstable library feature `unstable_test_feature` + --> $DIR/lint-stability.rs:88:48 + | +LL | struct S1(T::TypeUnstable); + | ^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: use of unstable library feature `unstable_test_feature` --> $DIR/lint-stability.rs:17:5 | @@ -367,15 +376,6 @@ LL | let _ = Unstable::StableVariant; = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: use of unstable library feature `unstable_test_feature` - --> $DIR/lint-stability.rs:88:48 - | -LL | struct S1(T::TypeUnstable); - | ^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: use of unstable library feature `unstable_test_feature` --> $DIR/lint-stability.rs:92:13 | diff --git a/tests/ui/missing/missing-stability.stderr b/tests/ui/missing/missing-stability.stderr index 659f8c78cae6..bf8046c4e122 100644 --- a/tests/ui/missing/missing-stability.stderr +++ b/tests/ui/missing/missing-stability.stderr @@ -1,17 +1,14 @@ error: function has missing stability attribute --> $DIR/missing-stability.rs:8:1 | -LL | / pub fn unmarked() { -LL | | -LL | | () -LL | | } - | |_^ +LL | pub fn unmarked() { + | ^^^^^^^^^^^^^^^^^ error: function has missing stability attribute --> $DIR/missing-stability.rs:22:5 | LL | pub fn unmarked() {} - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/privacy/effective_visibilities_invariants.stderr b/tests/ui/privacy/effective_visibilities_invariants.stderr index 64d0402f84e6..97bee1e2d8d3 100644 --- a/tests/ui/privacy/effective_visibilities_invariants.stderr +++ b/tests/ui/privacy/effective_visibilities_invariants.stderr @@ -23,7 +23,7 @@ error: module has missing stability attribute --> $DIR/effective_visibilities_invariants.rs:5:1 | LL | pub mod m {} - | ^^^^^^^^^^^^ + | ^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/privacy/issue-113860-1.stderr b/tests/ui/privacy/issue-113860-1.stderr index dad9ebadf045..764c9f4925be 100644 --- a/tests/ui/privacy/issue-113860-1.stderr +++ b/tests/ui/privacy/issue-113860-1.stderr @@ -20,28 +20,20 @@ LL | | fn main() {} error: trait has missing stability attribute --> $DIR/issue-113860-1.rs:4:1 | -LL | / pub trait Trait { -LL | | -LL | | fn fun() {} -LL | | -LL | | } - | |_^ +LL | pub trait Trait { + | ^^^^^^^^^^^^^^^ error: implementation has missing stability attribute --> $DIR/issue-113860-1.rs:10:1 | -LL | / impl Trait for u8 { -LL | | -LL | | pub(self) fn fun() {} -LL | | -LL | | } - | |_^ +LL | impl Trait for u8 { + | ^^^^^^^^^^^^^^^^^ error: associated function has missing stability attribute --> $DIR/issue-113860-1.rs:6:5 | LL | fn fun() {} - | ^^^^^^^^^^^ + | ^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/privacy/issue-113860-2.stderr b/tests/ui/privacy/issue-113860-2.stderr index 9805c22dbdf5..d0847aa2b49d 100644 --- a/tests/ui/privacy/issue-113860-2.stderr +++ b/tests/ui/privacy/issue-113860-2.stderr @@ -20,28 +20,20 @@ LL | | fn main() {} error: trait has missing stability attribute --> $DIR/issue-113860-2.rs:4:1 | -LL | / pub trait Trait { -LL | | -LL | | type X; -LL | | -LL | | } - | |_^ +LL | pub trait Trait { + | ^^^^^^^^^^^^^^^ error: implementation has missing stability attribute --> $DIR/issue-113860-2.rs:10:1 | -LL | / impl Trait for u8 { -LL | | -LL | | pub(self) type X = Self; -LL | | -LL | | } - | |_^ +LL | impl Trait for u8 { + | ^^^^^^^^^^^^^^^^^ error: associated type has missing stability attribute --> $DIR/issue-113860-2.rs:6:5 | LL | type X; - | ^^^^^^^ + | ^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/privacy/issue-113860.stderr b/tests/ui/privacy/issue-113860.stderr index 88efcae4a857..d7a15255b157 100644 --- a/tests/ui/privacy/issue-113860.stderr +++ b/tests/ui/privacy/issue-113860.stderr @@ -20,28 +20,20 @@ LL | | fn main() {} error: trait has missing stability attribute --> $DIR/issue-113860.rs:4:1 | -LL | / pub trait Trait { -LL | | -LL | | const X: u32; -LL | | -LL | | } - | |_^ +LL | pub trait Trait { + | ^^^^^^^^^^^^^^^ error: implementation has missing stability attribute --> $DIR/issue-113860.rs:10:1 | -LL | / impl Trait for u8 { -LL | | -LL | | pub(self) const X: u32 = 3; -LL | | -LL | | } - | |_^ +LL | impl Trait for u8 { + | ^^^^^^^^^^^^^^^^^ error: associated constant has missing stability attribute --> $DIR/issue-113860.rs:6:5 | LL | const X: u32; - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/stability-attribute/missing-const-stability.stderr b/tests/ui/stability-attribute/missing-const-stability.stderr index 70a2450c53a0..5748e20cd2bd 100644 --- a/tests/ui/stability-attribute/missing-const-stability.stderr +++ b/tests/ui/stability-attribute/missing-const-stability.stderr @@ -2,29 +2,25 @@ error: function has missing const stability attribute --> $DIR/missing-const-stability.rs:7:1 | LL | pub const fn foo() {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: trait has missing const stability attribute --> $DIR/missing-const-stability.rs:23:1 | -LL | / pub const trait Bar { -LL | | -LL | | #[stable(feature = "stable", since = "1.0.0")] -LL | | fn fun(); -LL | | } - | |_^ +LL | pub const trait Bar { + | ^^^^^^^^^^^^^^^^^^^ error: function has missing const stability attribute --> $DIR/missing-const-stability.rs:36:1 | LL | pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: associated function has missing const stability attribute --> $DIR/missing-const-stability.rs:16:5 | LL | pub const fn foo() {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-3.stderr b/tests/ui/stability-attribute/stability-attribute-sanity-3.stderr index a6d1ebf29458..d33bb53360bc 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-3.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity-3.stderr @@ -1,10 +1,8 @@ error: macro has missing stability attribute --> $DIR/stability-attribute-sanity-3.rs:8:1 | -LL | / macro_rules! mac { -LL | | () => () -LL | | } - | |_^ +LL | macro_rules! mac { + | ^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error From d716dc9a7a1525402adfdeaa497a063d69a97aac Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 16 Jul 2025 22:32:05 +0000 Subject: [PATCH 290/363] Remove useless debugging. --- compiler/rustc_passes/src/stability.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 61827dde64f1..b23dc5c1fa26 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -25,7 +25,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint; use rustc_session::lint::builtin::{DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL}; use rustc_span::{Span, Symbol, sym}; -use tracing::{info, instrument}; +use tracing::instrument; use crate::errors; @@ -148,7 +148,6 @@ fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option Date: Wed, 16 Jul 2025 22:34:00 +0000 Subject: [PATCH 291/363] Remove unuseful enums. --- compiler/rustc_passes/src/stability.rs | 76 ++++++-------------------- 1 file changed, 16 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index b23dc5c1fa26..fd0ca1274913 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -41,67 +41,23 @@ enum AnnotationKind { Container, } -/// Whether to inherit deprecation flags for nested items. In most cases, we do want to inherit -/// deprecation, because nested items rarely have individual deprecation attributes, and so -/// should be treated as deprecated if their parent is. However, default generic parameters -/// have separate deprecation attributes from their parents, so we do not wish to inherit -/// deprecation in this case. For example, inheriting deprecation for `T` in `Foo` -/// would cause a duplicate warning arising from both `Foo` and `T` being deprecated. -#[derive(Clone)] -enum InheritDeprecation { - Yes, - No, -} - -impl InheritDeprecation { - fn yes(&self) -> bool { - matches!(self, InheritDeprecation::Yes) - } -} - -/// Whether to inherit const stability flags for nested items. In most cases, we do not want to -/// inherit const stability: just because an enclosing `fn` is const-stable does not mean -/// all `extern` imports declared in it should be const-stable! However, trait methods -/// inherit const stability attributes from their parent and do not have their own. -enum InheritConstStability { - Yes, - No, -} - -impl InheritConstStability { - fn yes(&self) -> bool { - matches!(self, InheritConstStability::Yes) - } -} - -enum InheritStability { - Yes, - No, -} - -impl InheritStability { - fn yes(&self) -> bool { - matches!(self, InheritStability::Yes) - } -} - -fn inherit_deprecation(def_kind: DefKind) -> InheritDeprecation { +fn inherit_deprecation(def_kind: DefKind) -> bool { match def_kind { - DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => InheritDeprecation::No, - _ => InheritDeprecation::Yes, + DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => false, + _ => true, } } -fn inherit_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> InheritConstStability { +fn inherit_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { let def_kind = tcx.def_kind(def_id); match def_kind { DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { match tcx.def_kind(tcx.local_parent(def_id)) { - DefKind::Impl { of_trait: true } => InheritConstStability::Yes, - _ => InheritConstStability::No, + DefKind::Impl { of_trait: true } => true, + _ => false, } } - _ => InheritConstStability::No, + _ => false, } } @@ -145,7 +101,7 @@ fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option, def_id: LocalDefId) -> Option InheritStability { +fn inherit_stability(def_kind: DefKind) -> bool { match def_kind { - DefKind::Field | DefKind::Variant | DefKind::Ctor(..) => InheritStability::Yes, - _ => InheritStability::No, + DefKind::Field | DefKind::Variant | DefKind::Ctor(..) => true, + _ => false, } } @@ -193,7 +149,7 @@ fn lookup_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { let Some(parent) = tcx.opt_local_parent(def_id) else { return Some(FORCE_UNSTABLE) }; - if inherit_deprecation(tcx.def_kind(def_id)).yes() { + if inherit_deprecation(tcx.def_kind(def_id)) { let parent = tcx.lookup_stability(parent)?; if parent.is_unstable() { return Some(parent); @@ -212,7 +168,7 @@ fn lookup_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { return Some(stab); } - if inherit_deprecation(tcx.def_kind(def_id)).yes() { + if inherit_deprecation(tcx.def_kind(def_id)) { let Some(parent) = tcx.opt_local_parent(def_id) else { return tcx .sess @@ -222,7 +178,7 @@ fn lookup_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { .then_some(FORCE_UNSTABLE); }; let parent = tcx.lookup_stability(parent)?; - if parent.is_unstable() || inherit_stability(tcx.def_kind(def_id)).yes() { + if parent.is_unstable() || inherit_stability(tcx.def_kind(def_id)) { return Some(parent); } } @@ -249,7 +205,7 @@ fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option, def_id: LocalDefId) -> Option Date: Wed, 16 Jul 2025 22:39:04 +0000 Subject: [PATCH 292/363] Include ErrorGuaranteed in StableSince::Err. --- compiler/rustc_attr_data_structures/src/lib.rs | 4 ++-- compiler/rustc_attr_data_structures/src/stability.rs | 4 ++-- compiler/rustc_attr_parsing/src/attributes/stability.rs | 8 ++++---- compiler/rustc_passes/src/lib_features.rs | 2 +- compiler/rustc_passes/src/stability.rs | 2 +- src/librustdoc/html/render/mod.rs | 2 +- src/tools/clippy/clippy_lints/src/std_instead_of_core.rs | 2 +- src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index 8f8ce575a183..ecca0e390638 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -24,7 +24,7 @@ use rustc_ast::token::CommentKind; use rustc_ast::{AttrStyle, IntTy, UintTy}; use rustc_ast_pretty::pp::Printer; use rustc_span::hygiene::Transparency; -use rustc_span::{Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Span, Symbol}; pub use stability::*; use thin_vec::ThinVec; pub use version::*; @@ -170,7 +170,7 @@ macro_rules! print_tup { } print_tup!(A B C D E F G H); -print_skip!(Span, ()); +print_skip!(Span, (), ErrorGuaranteed); print_disp!(u16, bool, NonZero); print_debug!(Symbol, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); diff --git a/compiler/rustc_attr_data_structures/src/stability.rs b/compiler/rustc_attr_data_structures/src/stability.rs index 218e771c745a..bd31c0621176 100644 --- a/compiler/rustc_attr_data_structures/src/stability.rs +++ b/compiler/rustc_attr_data_structures/src/stability.rs @@ -1,7 +1,7 @@ use std::num::NonZero; use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; -use rustc_span::{Symbol, sym}; +use rustc_span::{ErrorGuaranteed, Symbol, sym}; use crate::{PrintAttribute, RustcVersion}; @@ -153,7 +153,7 @@ pub enum StableSince { /// Stabilized in the upcoming version, whatever number that is. Current, /// Failed to parse a stabilization version. - Err, + Err(ErrorGuaranteed), } impl StabilityLevel { diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 8f405e5aad97..59337749c877 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -292,12 +292,12 @@ pub(crate) fn parse_stability( } else if let Some(version) = parse_version(since) { StableSince::Version(version) } else { - cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span }); - StableSince::Err + let err = cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span }); + StableSince::Err(err) } } else { - cx.emit_err(session_diagnostics::MissingSince { span: cx.attr_span }); - StableSince::Err + let err = cx.emit_err(session_diagnostics::MissingSince { span: cx.attr_span }); + StableSince::Err(err) }; match feature { diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 127e0df13321..35d2a655991e 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -44,7 +44,7 @@ impl<'tcx> LibFeatureCollector<'tcx> { StabilityLevel::Stable { since, .. } => FeatureStability::AcceptedSince(match since { StableSince::Version(v) => Symbol::intern(&v.to_string()), StableSince::Current => sym::env_CFG_RELEASE, - StableSince::Err => return None, + StableSince::Err(_) => return None, }), }; diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index fd0ca1274913..988025db58be 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -421,7 +421,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { .emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); } } - StableSince::Err => { + StableSince::Err(_) => { // An error already reported. Assume the unparseable stabilization // version is older than the deprecation version. } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index d8c37137bbc7..2cfc9af39e47 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1110,7 +1110,7 @@ fn since_to_string(since: &StableSince) -> Option { match since { StableSince::Version(since) => Some(since.to_string()), StableSince::Current => Some(RustcVersion::CURRENT.to_string()), - StableSince::Err => None, + StableSince::Err(_) => None, } } diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index cf70e883bd09..216f168471e6 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -249,7 +249,7 @@ fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: Msrv) -> bool { let stable = match since { StableSince::Version(v) => msrv.meets(cx, v), StableSince::Current => msrv.current(cx).is_none(), - StableSince::Err => false, + StableSince::Err(_) => false, }; if !stable { 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 942c71ac33b8..b3356450d387 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 @@ -432,7 +432,7 @@ pub fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bo let const_stab_rust_version = match since { StableSince::Version(version) => version, StableSince::Current => RustcVersion::CURRENT, - StableSince::Err => return false, + StableSince::Err(_) => return false, }; msrv.meets(cx, const_stab_rust_version) From ee430346fe2265fc320c098efe8e1bbcbe0dd54c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 16 Jul 2025 22:42:55 +0000 Subject: [PATCH 293/363] Correct comments. --- compiler/rustc_passes/src/stability.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 988025db58be..a1a900d54b93 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -124,7 +124,7 @@ fn inherit_stability(def_kind: DefKind) -> bool { /// If the `-Z force-unstable-if-unmarked` flag is passed then we provide /// a parent stability annotation which indicates that this is private /// with the `rustc_private` feature. This is intended for use when -/// compiling `librustc_*` crates themselves so we can leverage crates.io +/// compiling library and `rustc_*` crates themselves so we can leverage crates.io /// while maintaining the invariant that all sysroot crates are unstable /// by default and are unable to be used. const FORCE_UNSTABLE: Stability = Stability { @@ -248,13 +248,11 @@ fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option Date: Wed, 16 Jul 2025 22:43:26 +0000 Subject: [PATCH 294/363] Fix formatting. --- compiler/rustc_passes/src/stability.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index a1a900d54b93..40999d622dc0 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -231,13 +231,14 @@ fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option Date: Thu, 17 Jul 2025 23:43:25 +0000 Subject: [PATCH 295/363] Add test. --- tests/ui/privacy/private-in-public-warn.rs | 21 ++- .../ui/privacy/private-in-public-warn.stderr | 175 ++++++++++++++---- .../pub-priv-dep/auxiliary/priv_dep.rs | 1 + tests/ui/privacy/pub-priv-dep/pub-priv1.rs | 9 +- .../ui/privacy/pub-priv-dep/pub-priv1.stderr | 52 ++++-- 5 files changed, 202 insertions(+), 56 deletions(-) diff --git a/tests/ui/privacy/private-in-public-warn.rs b/tests/ui/privacy/private-in-public-warn.rs index 746b98fbd078..1794fa956690 100644 --- a/tests/ui/privacy/private-in-public-warn.rs +++ b/tests/ui/privacy/private-in-public-warn.rs @@ -35,6 +35,7 @@ mod types { mod traits { trait PrivTr {} + impl PrivTr for () {} pub struct Pub(T); pub trait PubTr {} @@ -45,7 +46,13 @@ mod traits { pub trait Tr3 { type Alias: PrivTr; //~^ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::Alias` - fn f(arg: T) {} //~ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::f` + fn f(arg: T) {} + //~^ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::f` + fn g() -> impl PrivTr; + //~^ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::g::{anon_assoc#0}` + fn h() -> impl PrivTr {} + //~^ ERROR private trait `traits::PrivTr` in public interface + //~| ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::h::{anon_assoc#0}` } impl Pub {} //~ ERROR trait `traits::PrivTr` is more private than the item `traits::Pub` impl PubTr for Pub {} // OK, trait impl predicates @@ -75,12 +82,24 @@ mod generics { pub struct Pub(T); trait PrivTr {} pub trait PubTr {} + impl PrivTr> for () {} pub trait Tr1: PrivTr {} //~^ ERROR trait `generics::PrivTr` is more private than the item `generics::Tr1` pub trait Tr2: PubTr {} //~ ERROR type `generics::Priv` is more private than the item `generics::Tr2` pub trait Tr3: PubTr<[Priv; 1]> {} //~ ERROR type `generics::Priv` is more private than the item `generics::Tr3` pub trait Tr4: PubTr> {} //~ ERROR type `generics::Priv` is more private than the item `Tr4` + + pub trait Tr5 { + fn required() -> impl PrivTr>; + //~^ ERROR trait `generics::PrivTr>` is more private than the item `Tr5::required::{anon_assoc#0}` + //~| ERROR type `generics::Priv<()>` is more private than the item `Tr5::required::{anon_assoc#0}` + fn provided() -> impl PrivTr> {} + //~^ ERROR private trait `generics::PrivTr>` in public interface + //~| ERROR private type `generics::Priv<()>` in public interface + //~| ERROR trait `generics::PrivTr>` is more private than the item `Tr5::provided::{anon_assoc#0}` + //~| ERROR type `generics::Priv<()>` is more private than the item `Tr5::provided::{anon_assoc#0}` + } } mod impls { diff --git a/tests/ui/privacy/private-in-public-warn.stderr b/tests/ui/privacy/private-in-public-warn.stderr index 3743879ffa61..09dbe4d67e3b 100644 --- a/tests/ui/privacy/private-in-public-warn.stderr +++ b/tests/ui/privacy/private-in-public-warn.stderr @@ -130,7 +130,7 @@ LL | type Alias = Priv; | ^^^^^^^^^^ can't leak private type error: trait `traits::PrivTr` is more private than the item `traits::Alias` - --> $DIR/private-in-public-warn.rs:41:5 + --> $DIR/private-in-public-warn.rs:42:5 | LL | pub type Alias = T; | ^^^^^^^^^^^^^^^^^^^^^^^^^ type alias `traits::Alias` is reachable at visibility `pub(crate)` @@ -147,7 +147,7 @@ LL | #![deny(private_interfaces, private_bounds)] | ^^^^^^^^^^^^^^ error: trait `traits::PrivTr` is more private than the item `traits::Tr1` - --> $DIR/private-in-public-warn.rs:43:5 + --> $DIR/private-in-public-warn.rs:44:5 | LL | pub trait Tr1: PrivTr {} | ^^^^^^^^^^^^^^^^^^^^^ trait `traits::Tr1` is reachable at visibility `pub(crate)` @@ -159,7 +159,7 @@ LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits::PrivTr` is more private than the item `traits::Tr2` - --> $DIR/private-in-public-warn.rs:44:5 + --> $DIR/private-in-public-warn.rs:45:5 | LL | pub trait Tr2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^ trait `traits::Tr2` is reachable at visibility `pub(crate)` @@ -171,7 +171,7 @@ LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits::PrivTr` is more private than the item `traits::Tr3::Alias` - --> $DIR/private-in-public-warn.rs:46:9 + --> $DIR/private-in-public-warn.rs:47:9 | LL | type Alias: PrivTr; | ^^^^^^^^^^^^^^^^^^ associated type `traits::Tr3::Alias` is reachable at visibility `pub(crate)` @@ -183,7 +183,7 @@ LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits::PrivTr` is more private than the item `traits::Tr3::f` - --> $DIR/private-in-public-warn.rs:48:9 + --> $DIR/private-in-public-warn.rs:49:9 | LL | fn f(arg: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^ associated function `traits::Tr3::f` is reachable at visibility `pub(crate)` @@ -194,8 +194,41 @@ note: but trait `traits::PrivTr` is only usable at visibility `pub(self)` LL | trait PrivTr {} | ^^^^^^^^^^^^ +error: trait `traits::PrivTr` is more private than the item `traits::Tr3::g::{anon_assoc#0}` + --> $DIR/private-in-public-warn.rs:51:19 + | +LL | fn g() -> impl PrivTr; + | ^^^^^^^^^^^ opaque type `traits::Tr3::g::{anon_assoc#0}` is reachable at visibility `pub(crate)` + | +note: but trait `traits::PrivTr` is only usable at visibility `pub(self)` + --> $DIR/private-in-public-warn.rs:37:5 + | +LL | trait PrivTr {} + | ^^^^^^^^^^^^ + +error[E0446]: private trait `traits::PrivTr` in public interface + --> $DIR/private-in-public-warn.rs:53:19 + | +LL | trait PrivTr {} + | ------------ `traits::PrivTr` declared as private +... +LL | fn h() -> impl PrivTr {} + | ^^^^^^^^^^^ can't leak private trait + +error: trait `traits::PrivTr` is more private than the item `traits::Tr3::h::{anon_assoc#0}` + --> $DIR/private-in-public-warn.rs:53:19 + | +LL | fn h() -> impl PrivTr {} + | ^^^^^^^^^^^ opaque type `traits::Tr3::h::{anon_assoc#0}` is reachable at visibility `pub(crate)` + | +note: but trait `traits::PrivTr` is only usable at visibility `pub(self)` + --> $DIR/private-in-public-warn.rs:37:5 + | +LL | trait PrivTr {} + | ^^^^^^^^^^^^ + error: trait `traits::PrivTr` is more private than the item `traits::Pub` - --> $DIR/private-in-public-warn.rs:50:5 + --> $DIR/private-in-public-warn.rs:57:5 | LL | impl Pub {} | ^^^^^^^^^^^^^^^^^^^^^^ implementation `traits::Pub` is reachable at visibility `pub(crate)` @@ -207,103 +240,169 @@ LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits_where::PrivTr` is more private than the item `traits_where::Alias` - --> $DIR/private-in-public-warn.rs:59:5 + --> $DIR/private-in-public-warn.rs:66:5 | LL | pub type Alias where T: PrivTr = T; | ^^^^^^^^^^^^^^^^^ type alias `traits_where::Alias` is reachable at visibility `pub(crate)` | note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:55:5 + --> $DIR/private-in-public-warn.rs:62:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits_where::PrivTr` is more private than the item `traits_where::Tr2` - --> $DIR/private-in-public-warn.rs:62:5 + --> $DIR/private-in-public-warn.rs:69:5 | LL | pub trait Tr2 where T: PrivTr {} | ^^^^^^^^^^^^^^^^ trait `traits_where::Tr2` is reachable at visibility `pub(crate)` | note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:55:5 + --> $DIR/private-in-public-warn.rs:62:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits_where::PrivTr` is more private than the item `traits_where::Tr3::f` - --> $DIR/private-in-public-warn.rs:65:9 + --> $DIR/private-in-public-warn.rs:72:9 | LL | fn f(arg: T) where T: PrivTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function `traits_where::Tr3::f` is reachable at visibility `pub(crate)` | note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:55:5 + --> $DIR/private-in-public-warn.rs:62:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits_where::PrivTr` is more private than the item `traits_where::Pub` - --> $DIR/private-in-public-warn.rs:68:5 + --> $DIR/private-in-public-warn.rs:75:5 | LL | impl Pub where T: PrivTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation `traits_where::Pub` is reachable at visibility `pub(crate)` | note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:55:5 + --> $DIR/private-in-public-warn.rs:62:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `generics::PrivTr` is more private than the item `generics::Tr1` - --> $DIR/private-in-public-warn.rs:79:5 + --> $DIR/private-in-public-warn.rs:87:5 | LL | pub trait Tr1: PrivTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `generics::Tr1` is reachable at visibility `pub(crate)` | note: but trait `generics::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:76:5 + --> $DIR/private-in-public-warn.rs:83:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^^^^ error: type `generics::Priv` is more private than the item `generics::Tr2` - --> $DIR/private-in-public-warn.rs:81:5 + --> $DIR/private-in-public-warn.rs:89:5 | LL | pub trait Tr2: PubTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `generics::Tr2` is reachable at visibility `pub(crate)` | note: but type `generics::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:74:5 + --> $DIR/private-in-public-warn.rs:81:5 | LL | struct Priv(T); | ^^^^^^^^^^^^^^^^^^^ error: type `generics::Priv` is more private than the item `generics::Tr3` - --> $DIR/private-in-public-warn.rs:82:5 + --> $DIR/private-in-public-warn.rs:90:5 | LL | pub trait Tr3: PubTr<[Priv; 1]> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `generics::Tr3` is reachable at visibility `pub(crate)` | note: but type `generics::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:74:5 + --> $DIR/private-in-public-warn.rs:81:5 | LL | struct Priv(T); | ^^^^^^^^^^^^^^^^^^^ error: type `generics::Priv` is more private than the item `Tr4` - --> $DIR/private-in-public-warn.rs:83:5 + --> $DIR/private-in-public-warn.rs:91:5 | LL | pub trait Tr4: PubTr> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `Tr4` is reachable at visibility `pub(crate)` | note: but type `generics::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:74:5 + --> $DIR/private-in-public-warn.rs:81:5 + | +LL | struct Priv(T); + | ^^^^^^^^^^^^^^^^^^^ + +error: trait `generics::PrivTr>` is more private than the item `Tr5::required::{anon_assoc#0}` + --> $DIR/private-in-public-warn.rs:94:26 + | +LL | fn required() -> impl PrivTr>; + | ^^^^^^^^^^^^^^^^^^^^^ opaque type `Tr5::required::{anon_assoc#0}` is reachable at visibility `pub(crate)` + | +note: but trait `generics::PrivTr>` is only usable at visibility `pub(self)` + --> $DIR/private-in-public-warn.rs:83:5 + | +LL | trait PrivTr {} + | ^^^^^^^^^^^^^^^ + +error: type `generics::Priv<()>` is more private than the item `Tr5::required::{anon_assoc#0}` + --> $DIR/private-in-public-warn.rs:94:26 + | +LL | fn required() -> impl PrivTr>; + | ^^^^^^^^^^^^^^^^^^^^^ opaque type `Tr5::required::{anon_assoc#0}` is reachable at visibility `pub(crate)` + | +note: but type `generics::Priv<()>` is only usable at visibility `pub(self)` + --> $DIR/private-in-public-warn.rs:81:5 + | +LL | struct Priv(T); + | ^^^^^^^^^^^^^^^^^^^ + +error[E0446]: private trait `generics::PrivTr>` in public interface + --> $DIR/private-in-public-warn.rs:97:26 + | +LL | trait PrivTr {} + | --------------- `generics::PrivTr>` declared as private +... +LL | fn provided() -> impl PrivTr> {} + | ^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + +error[E0446]: private type `generics::Priv<()>` in public interface + --> $DIR/private-in-public-warn.rs:97:26 + | +LL | struct Priv(T); + | ------------------- `generics::Priv<()>` declared as private +... +LL | fn provided() -> impl PrivTr> {} + | ^^^^^^^^^^^^^^^^^^^^^ can't leak private type + +error: trait `generics::PrivTr>` is more private than the item `Tr5::provided::{anon_assoc#0}` + --> $DIR/private-in-public-warn.rs:97:26 + | +LL | fn provided() -> impl PrivTr> {} + | ^^^^^^^^^^^^^^^^^^^^^ opaque type `Tr5::provided::{anon_assoc#0}` is reachable at visibility `pub(crate)` + | +note: but trait `generics::PrivTr>` is only usable at visibility `pub(self)` + --> $DIR/private-in-public-warn.rs:83:5 + | +LL | trait PrivTr {} + | ^^^^^^^^^^^^^^^ + +error: type `generics::Priv<()>` is more private than the item `Tr5::provided::{anon_assoc#0}` + --> $DIR/private-in-public-warn.rs:97:26 + | +LL | fn provided() -> impl PrivTr> {} + | ^^^^^^^^^^^^^^^^^^^^^ opaque type `Tr5::provided::{anon_assoc#0}` is reachable at visibility `pub(crate)` + | +note: but type `generics::Priv<()>` is only usable at visibility `pub(self)` + --> $DIR/private-in-public-warn.rs:81:5 | LL | struct Priv(T); | ^^^^^^^^^^^^^^^^^^^ error[E0446]: private type `impls::Priv` in public interface - --> $DIR/private-in-public-warn.rs:109:9 + --> $DIR/private-in-public-warn.rs:128:9 | LL | struct Priv; | ----------- `impls::Priv` declared as private @@ -312,19 +411,19 @@ LL | type Alias = Priv; | ^^^^^^^^^^ can't leak private type error: type `aliases_pub::Priv` is more private than the item `aliases_pub::::f` - --> $DIR/private-in-public-warn.rs:180:9 + --> $DIR/private-in-public-warn.rs:199:9 | LL | pub fn f(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^ associated function `aliases_pub::::f` is reachable at visibility `pub(crate)` | note: but type `aliases_pub::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:153:5 + --> $DIR/private-in-public-warn.rs:172:5 | LL | struct Priv; | ^^^^^^^^^^^ error[E0446]: private type `aliases_pub::Priv` in public interface - --> $DIR/private-in-public-warn.rs:183:9 + --> $DIR/private-in-public-warn.rs:202:9 | LL | struct Priv; | ----------- `aliases_pub::Priv` declared as private @@ -333,7 +432,7 @@ LL | type Check = Priv; | ^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_pub::Priv` in public interface - --> $DIR/private-in-public-warn.rs:186:9 + --> $DIR/private-in-public-warn.rs:205:9 | LL | struct Priv; | ----------- `aliases_pub::Priv` declared as private @@ -342,7 +441,7 @@ LL | type Check = Priv; | ^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_pub::Priv` in public interface - --> $DIR/private-in-public-warn.rs:189:9 + --> $DIR/private-in-public-warn.rs:208:9 | LL | struct Priv; | ----------- `aliases_pub::Priv` declared as private @@ -351,7 +450,7 @@ LL | type Check = Priv; | ^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_pub::Priv` in public interface - --> $DIR/private-in-public-warn.rs:192:9 + --> $DIR/private-in-public-warn.rs:211:9 | LL | struct Priv; | ----------- `aliases_pub::Priv` declared as private @@ -360,43 +459,43 @@ LL | type Check = Priv; | ^^^^^^^^^^ can't leak private type error: trait `PrivTr1` is more private than the item `aliases_priv::Tr1` - --> $DIR/private-in-public-warn.rs:222:5 + --> $DIR/private-in-public-warn.rs:241:5 | LL | pub trait Tr1: PrivUseAliasTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `aliases_priv::Tr1` is reachable at visibility `pub(crate)` | note: but trait `PrivTr1` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:208:5 + --> $DIR/private-in-public-warn.rs:227:5 | LL | trait PrivTr1 { | ^^^^^^^^^^^^^^^^^^^^^ error: trait `PrivTr1` is more private than the item `aliases_priv::Tr2` - --> $DIR/private-in-public-warn.rs:224:5 + --> $DIR/private-in-public-warn.rs:243:5 | LL | pub trait Tr2: PrivUseAliasTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `aliases_priv::Tr2` is reachable at visibility `pub(crate)` | note: but trait `PrivTr1` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:208:5 + --> $DIR/private-in-public-warn.rs:227:5 | LL | trait PrivTr1 { | ^^^^^^^^^^^^^^^^^^^^^ error: type `Priv2` is more private than the item `aliases_priv::Tr2` - --> $DIR/private-in-public-warn.rs:224:5 + --> $DIR/private-in-public-warn.rs:243:5 | LL | pub trait Tr2: PrivUseAliasTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `aliases_priv::Tr2` is reachable at visibility `pub(crate)` | note: but type `Priv2` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:206:5 + --> $DIR/private-in-public-warn.rs:225:5 | LL | struct Priv2; | ^^^^^^^^^^^^ warning: bounds on generic parameters in type aliases are not enforced - --> $DIR/private-in-public-warn.rs:41:23 + --> $DIR/private-in-public-warn.rs:42:23 | LL | pub type Alias = T; | --^^^^^^ @@ -410,7 +509,7 @@ LL | pub type Alias = T; = note: `#[warn(type_alias_bounds)]` on by default warning: where clauses on type aliases are not enforced - --> $DIR/private-in-public-warn.rs:59:29 + --> $DIR/private-in-public-warn.rs:66:29 | LL | pub type Alias where T: PrivTr = T; | ------^^^^^^^^^ @@ -422,6 +521,6 @@ LL | pub type Alias where T: PrivTr = T; see issue #112792 for more information = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -error: aborting due to 34 previous errors; 2 warnings emitted +error: aborting due to 43 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0446`. diff --git a/tests/ui/privacy/pub-priv-dep/auxiliary/priv_dep.rs b/tests/ui/privacy/pub-priv-dep/auxiliary/priv_dep.rs index 4eeecdc05697..756401470262 100644 --- a/tests/ui/privacy/pub-priv-dep/auxiliary/priv_dep.rs +++ b/tests/ui/privacy/pub-priv-dep/auxiliary/priv_dep.rs @@ -1,5 +1,6 @@ pub struct OtherType; pub trait OtherTrait {} +impl OtherTrait for OtherType {} #[macro_export] macro_rules! m { diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs index 192ca0db8bd4..0bad116934b5 100644 --- a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs +++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs @@ -44,8 +44,15 @@ impl PublicType { pub trait MyPubTrait { type Foo: OtherTrait; + //~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface + + fn required() -> impl OtherTrait; + //~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface + + fn provided() -> impl OtherTrait { OtherType } + //~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface + //~| ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface } -//~^^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface pub trait WithSuperTrait: OtherTrait {} //~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr index 9da47827be4b..275bcfcb7da7 100644 --- a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr +++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr @@ -11,31 +11,31 @@ LL | #![deny(exported_private_dependencies)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: macro `m` from private dependency 'priv_dep' is re-exported - --> $DIR/pub-priv1.rs:94:9 + --> $DIR/pub-priv1.rs:101:9 | LL | pub use priv_dep::m; | ^^^^^^^^^^^ error: macro `fn_like` from private dependency 'pm' is re-exported - --> $DIR/pub-priv1.rs:96:9 + --> $DIR/pub-priv1.rs:103:9 | LL | pub use pm::fn_like; | ^^^^^^^^^^^ error: derive macro `PmDerive` from private dependency 'pm' is re-exported - --> $DIR/pub-priv1.rs:98:9 + --> $DIR/pub-priv1.rs:105:9 | LL | pub use pm::PmDerive; | ^^^^^^^^^^^^ error: attribute macro `pm_attr` from private dependency 'pm' is re-exported - --> $DIR/pub-priv1.rs:100:9 + --> $DIR/pub-priv1.rs:107:9 | LL | pub use pm::pm_attr; | ^^^^^^^^^^^ error: variant `V1` from private dependency 'priv_dep' is re-exported - --> $DIR/pub-priv1.rs:103:9 + --> $DIR/pub-priv1.rs:110:9 | LL | pub use priv_dep::E::V1; | ^^^^^^^^^^^^^^^ @@ -65,66 +65,86 @@ LL | type Foo: OtherTrait; | ^^^^^^^^^^^^^^^^^^^^ error: trait `OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:50:1 + --> $DIR/pub-priv1.rs:49:22 + | +LL | fn required() -> impl OtherTrait; + | ^^^^^^^^^^^^^^^ + +error: trait `OtherTrait` from private dependency 'priv_dep' in public interface + --> $DIR/pub-priv1.rs:52:22 + | +LL | fn provided() -> impl OtherTrait { OtherType } + | ^^^^^^^^^^^^^^^ + +error: trait `OtherTrait` from private dependency 'priv_dep' in public interface + --> $DIR/pub-priv1.rs:52:22 + | +LL | fn provided() -> impl OtherTrait { OtherType } + | ^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: trait `OtherTrait` from private dependency 'priv_dep' in public interface + --> $DIR/pub-priv1.rs:57:1 | LL | pub trait WithSuperTrait: OtherTrait {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:59:5 + --> $DIR/pub-priv1.rs:66:5 | LL | type X = OtherType; | ^^^^^^ error: trait `OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:63:1 + --> $DIR/pub-priv1.rs:70:1 | LL | pub fn in_bounds(x: T) { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:66:1 + --> $DIR/pub-priv1.rs:73:1 | LL | pub fn private_in_generic() -> std::num::Saturating { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:69:1 + --> $DIR/pub-priv1.rs:76:1 | LL | pub static STATIC: OtherType = OtherType; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:72:1 + --> $DIR/pub-priv1.rs:79:1 | LL | pub const CONST: OtherType = OtherType; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:75:1 + --> $DIR/pub-priv1.rs:82:1 | LL | pub type Alias = OtherType; | ^^^^^^^^^^^^^^ error: trait `OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:80:1 + --> $DIR/pub-priv1.rs:87:1 | LL | impl OtherTrait for PublicWithPrivateImpl {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:85:1 + --> $DIR/pub-priv1.rs:92:1 | LL | impl PubTraitOnPrivate for OtherType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:85:1 + --> $DIR/pub-priv1.rs:92:1 | LL | impl PubTraitOnPrivate for OtherType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 20 previous errors +error: aborting due to 23 previous errors From c004a96603bf8cfdd9ac462526a8e06ad6df5b66 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 17 Jul 2025 23:51:47 +0000 Subject: [PATCH 296/363] Do not check privacy for RPITIT. --- compiler/rustc_privacy/src/lib.rs | 8 + tests/ui/privacy/private-in-public-warn.rs | 9 - .../ui/privacy/private-in-public-warn.stderr | 209 +++++------------- tests/ui/privacy/pub-priv-dep/pub-priv1.rs | 3 - .../ui/privacy/pub-priv-dep/pub-priv1.stderr | 52 ++--- 5 files changed, 79 insertions(+), 202 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 80c13e44d7d8..9dd80bc99640 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1624,6 +1624,10 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { self.check(def_id, item_visibility, effective_vis).generics().predicates(); for assoc_item in tcx.associated_items(id.owner_id).in_definition_order() { + if assoc_item.is_impl_trait_in_trait() { + continue; + } + self.check_assoc_item(assoc_item, item_visibility, effective_vis); if assoc_item.is_type() { @@ -1736,6 +1740,10 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { check.ty().trait_ref(); for assoc_item in tcx.associated_items(id.owner_id).in_definition_order() { + if assoc_item.is_impl_trait_in_trait() { + continue; + } + let impl_item_vis = if !of_trait { min(tcx.local_visibility(assoc_item.def_id.expect_local()), impl_vis, tcx) } else { diff --git a/tests/ui/privacy/private-in-public-warn.rs b/tests/ui/privacy/private-in-public-warn.rs index 1794fa956690..f79e4641312e 100644 --- a/tests/ui/privacy/private-in-public-warn.rs +++ b/tests/ui/privacy/private-in-public-warn.rs @@ -49,10 +49,7 @@ mod traits { fn f(arg: T) {} //~^ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::f` fn g() -> impl PrivTr; - //~^ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::g::{anon_assoc#0}` fn h() -> impl PrivTr {} - //~^ ERROR private trait `traits::PrivTr` in public interface - //~| ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::h::{anon_assoc#0}` } impl Pub {} //~ ERROR trait `traits::PrivTr` is more private than the item `traits::Pub` impl PubTr for Pub {} // OK, trait impl predicates @@ -92,13 +89,7 @@ mod generics { pub trait Tr5 { fn required() -> impl PrivTr>; - //~^ ERROR trait `generics::PrivTr>` is more private than the item `Tr5::required::{anon_assoc#0}` - //~| ERROR type `generics::Priv<()>` is more private than the item `Tr5::required::{anon_assoc#0}` fn provided() -> impl PrivTr> {} - //~^ ERROR private trait `generics::PrivTr>` in public interface - //~| ERROR private type `generics::Priv<()>` in public interface - //~| ERROR trait `generics::PrivTr>` is more private than the item `Tr5::provided::{anon_assoc#0}` - //~| ERROR type `generics::Priv<()>` is more private than the item `Tr5::provided::{anon_assoc#0}` } } diff --git a/tests/ui/privacy/private-in-public-warn.stderr b/tests/ui/privacy/private-in-public-warn.stderr index 09dbe4d67e3b..c2a57e3b82c7 100644 --- a/tests/ui/privacy/private-in-public-warn.stderr +++ b/tests/ui/privacy/private-in-public-warn.stderr @@ -194,41 +194,8 @@ note: but trait `traits::PrivTr` is only usable at visibility `pub(self)` LL | trait PrivTr {} | ^^^^^^^^^^^^ -error: trait `traits::PrivTr` is more private than the item `traits::Tr3::g::{anon_assoc#0}` - --> $DIR/private-in-public-warn.rs:51:19 - | -LL | fn g() -> impl PrivTr; - | ^^^^^^^^^^^ opaque type `traits::Tr3::g::{anon_assoc#0}` is reachable at visibility `pub(crate)` - | -note: but trait `traits::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:37:5 - | -LL | trait PrivTr {} - | ^^^^^^^^^^^^ - -error[E0446]: private trait `traits::PrivTr` in public interface - --> $DIR/private-in-public-warn.rs:53:19 - | -LL | trait PrivTr {} - | ------------ `traits::PrivTr` declared as private -... -LL | fn h() -> impl PrivTr {} - | ^^^^^^^^^^^ can't leak private trait - -error: trait `traits::PrivTr` is more private than the item `traits::Tr3::h::{anon_assoc#0}` - --> $DIR/private-in-public-warn.rs:53:19 - | -LL | fn h() -> impl PrivTr {} - | ^^^^^^^^^^^ opaque type `traits::Tr3::h::{anon_assoc#0}` is reachable at visibility `pub(crate)` - | -note: but trait `traits::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:37:5 - | -LL | trait PrivTr {} - | ^^^^^^^^^^^^ - error: trait `traits::PrivTr` is more private than the item `traits::Pub` - --> $DIR/private-in-public-warn.rs:57:5 + --> $DIR/private-in-public-warn.rs:54:5 | LL | impl Pub {} | ^^^^^^^^^^^^^^^^^^^^^^ implementation `traits::Pub` is reachable at visibility `pub(crate)` @@ -240,169 +207,103 @@ LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits_where::PrivTr` is more private than the item `traits_where::Alias` - --> $DIR/private-in-public-warn.rs:66:5 + --> $DIR/private-in-public-warn.rs:63:5 | LL | pub type Alias where T: PrivTr = T; | ^^^^^^^^^^^^^^^^^ type alias `traits_where::Alias` is reachable at visibility `pub(crate)` | note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:62:5 + --> $DIR/private-in-public-warn.rs:59:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits_where::PrivTr` is more private than the item `traits_where::Tr2` - --> $DIR/private-in-public-warn.rs:69:5 + --> $DIR/private-in-public-warn.rs:66:5 | LL | pub trait Tr2 where T: PrivTr {} | ^^^^^^^^^^^^^^^^ trait `traits_where::Tr2` is reachable at visibility `pub(crate)` | note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:62:5 + --> $DIR/private-in-public-warn.rs:59:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits_where::PrivTr` is more private than the item `traits_where::Tr3::f` - --> $DIR/private-in-public-warn.rs:72:9 + --> $DIR/private-in-public-warn.rs:69:9 | LL | fn f(arg: T) where T: PrivTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function `traits_where::Tr3::f` is reachable at visibility `pub(crate)` | note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:62:5 + --> $DIR/private-in-public-warn.rs:59:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits_where::PrivTr` is more private than the item `traits_where::Pub` - --> $DIR/private-in-public-warn.rs:75:5 + --> $DIR/private-in-public-warn.rs:72:5 | LL | impl Pub where T: PrivTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation `traits_where::Pub` is reachable at visibility `pub(crate)` | note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:62:5 + --> $DIR/private-in-public-warn.rs:59:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `generics::PrivTr` is more private than the item `generics::Tr1` - --> $DIR/private-in-public-warn.rs:87:5 + --> $DIR/private-in-public-warn.rs:84:5 | LL | pub trait Tr1: PrivTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `generics::Tr1` is reachable at visibility `pub(crate)` | note: but trait `generics::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:83:5 + --> $DIR/private-in-public-warn.rs:80:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^^^^ error: type `generics::Priv` is more private than the item `generics::Tr2` - --> $DIR/private-in-public-warn.rs:89:5 + --> $DIR/private-in-public-warn.rs:86:5 | LL | pub trait Tr2: PubTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `generics::Tr2` is reachable at visibility `pub(crate)` | note: but type `generics::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:81:5 + --> $DIR/private-in-public-warn.rs:78:5 | LL | struct Priv(T); | ^^^^^^^^^^^^^^^^^^^ error: type `generics::Priv` is more private than the item `generics::Tr3` - --> $DIR/private-in-public-warn.rs:90:5 + --> $DIR/private-in-public-warn.rs:87:5 | LL | pub trait Tr3: PubTr<[Priv; 1]> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `generics::Tr3` is reachable at visibility `pub(crate)` | note: but type `generics::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:81:5 + --> $DIR/private-in-public-warn.rs:78:5 | LL | struct Priv(T); | ^^^^^^^^^^^^^^^^^^^ error: type `generics::Priv` is more private than the item `Tr4` - --> $DIR/private-in-public-warn.rs:91:5 + --> $DIR/private-in-public-warn.rs:88:5 | LL | pub trait Tr4: PubTr> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `Tr4` is reachable at visibility `pub(crate)` | note: but type `generics::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:81:5 - | -LL | struct Priv(T); - | ^^^^^^^^^^^^^^^^^^^ - -error: trait `generics::PrivTr>` is more private than the item `Tr5::required::{anon_assoc#0}` - --> $DIR/private-in-public-warn.rs:94:26 - | -LL | fn required() -> impl PrivTr>; - | ^^^^^^^^^^^^^^^^^^^^^ opaque type `Tr5::required::{anon_assoc#0}` is reachable at visibility `pub(crate)` - | -note: but trait `generics::PrivTr>` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:83:5 - | -LL | trait PrivTr {} - | ^^^^^^^^^^^^^^^ - -error: type `generics::Priv<()>` is more private than the item `Tr5::required::{anon_assoc#0}` - --> $DIR/private-in-public-warn.rs:94:26 - | -LL | fn required() -> impl PrivTr>; - | ^^^^^^^^^^^^^^^^^^^^^ opaque type `Tr5::required::{anon_assoc#0}` is reachable at visibility `pub(crate)` - | -note: but type `generics::Priv<()>` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:81:5 - | -LL | struct Priv(T); - | ^^^^^^^^^^^^^^^^^^^ - -error[E0446]: private trait `generics::PrivTr>` in public interface - --> $DIR/private-in-public-warn.rs:97:26 - | -LL | trait PrivTr {} - | --------------- `generics::PrivTr>` declared as private -... -LL | fn provided() -> impl PrivTr> {} - | ^^^^^^^^^^^^^^^^^^^^^ can't leak private trait - -error[E0446]: private type `generics::Priv<()>` in public interface - --> $DIR/private-in-public-warn.rs:97:26 - | -LL | struct Priv(T); - | ------------------- `generics::Priv<()>` declared as private -... -LL | fn provided() -> impl PrivTr> {} - | ^^^^^^^^^^^^^^^^^^^^^ can't leak private type - -error: trait `generics::PrivTr>` is more private than the item `Tr5::provided::{anon_assoc#0}` - --> $DIR/private-in-public-warn.rs:97:26 - | -LL | fn provided() -> impl PrivTr> {} - | ^^^^^^^^^^^^^^^^^^^^^ opaque type `Tr5::provided::{anon_assoc#0}` is reachable at visibility `pub(crate)` - | -note: but trait `generics::PrivTr>` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:83:5 - | -LL | trait PrivTr {} - | ^^^^^^^^^^^^^^^ - -error: type `generics::Priv<()>` is more private than the item `Tr5::provided::{anon_assoc#0}` - --> $DIR/private-in-public-warn.rs:97:26 - | -LL | fn provided() -> impl PrivTr> {} - | ^^^^^^^^^^^^^^^^^^^^^ opaque type `Tr5::provided::{anon_assoc#0}` is reachable at visibility `pub(crate)` - | -note: but type `generics::Priv<()>` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:81:5 + --> $DIR/private-in-public-warn.rs:78:5 | LL | struct Priv(T); | ^^^^^^^^^^^^^^^^^^^ error[E0446]: private type `impls::Priv` in public interface - --> $DIR/private-in-public-warn.rs:128:9 + --> $DIR/private-in-public-warn.rs:119:9 | LL | struct Priv; | ----------- `impls::Priv` declared as private @@ -411,17 +312,44 @@ LL | type Alias = Priv; | ^^^^^^^^^^ can't leak private type error: type `aliases_pub::Priv` is more private than the item `aliases_pub::::f` - --> $DIR/private-in-public-warn.rs:199:9 + --> $DIR/private-in-public-warn.rs:190:9 | LL | pub fn f(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^ associated function `aliases_pub::::f` is reachable at visibility `pub(crate)` | note: but type `aliases_pub::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:172:5 + --> $DIR/private-in-public-warn.rs:163:5 | LL | struct Priv; | ^^^^^^^^^^^ +error[E0446]: private type `aliases_pub::Priv` in public interface + --> $DIR/private-in-public-warn.rs:193:9 + | +LL | struct Priv; + | ----------- `aliases_pub::Priv` declared as private +... +LL | type Check = Priv; + | ^^^^^^^^^^ can't leak private type + +error[E0446]: private type `aliases_pub::Priv` in public interface + --> $DIR/private-in-public-warn.rs:196:9 + | +LL | struct Priv; + | ----------- `aliases_pub::Priv` declared as private +... +LL | type Check = Priv; + | ^^^^^^^^^^ can't leak private type + +error[E0446]: private type `aliases_pub::Priv` in public interface + --> $DIR/private-in-public-warn.rs:199:9 + | +LL | struct Priv; + | ----------- `aliases_pub::Priv` declared as private +... +LL | type Check = Priv; + | ^^^^^^^^^^ can't leak private type + error[E0446]: private type `aliases_pub::Priv` in public interface --> $DIR/private-in-public-warn.rs:202:9 | @@ -431,65 +359,38 @@ LL | struct Priv; LL | type Check = Priv; | ^^^^^^^^^^ can't leak private type -error[E0446]: private type `aliases_pub::Priv` in public interface - --> $DIR/private-in-public-warn.rs:205:9 - | -LL | struct Priv; - | ----------- `aliases_pub::Priv` declared as private -... -LL | type Check = Priv; - | ^^^^^^^^^^ can't leak private type - -error[E0446]: private type `aliases_pub::Priv` in public interface - --> $DIR/private-in-public-warn.rs:208:9 - | -LL | struct Priv; - | ----------- `aliases_pub::Priv` declared as private -... -LL | type Check = Priv; - | ^^^^^^^^^^ can't leak private type - -error[E0446]: private type `aliases_pub::Priv` in public interface - --> $DIR/private-in-public-warn.rs:211:9 - | -LL | struct Priv; - | ----------- `aliases_pub::Priv` declared as private -... -LL | type Check = Priv; - | ^^^^^^^^^^ can't leak private type - error: trait `PrivTr1` is more private than the item `aliases_priv::Tr1` - --> $DIR/private-in-public-warn.rs:241:5 + --> $DIR/private-in-public-warn.rs:232:5 | LL | pub trait Tr1: PrivUseAliasTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `aliases_priv::Tr1` is reachable at visibility `pub(crate)` | note: but trait `PrivTr1` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:227:5 + --> $DIR/private-in-public-warn.rs:218:5 | LL | trait PrivTr1 { | ^^^^^^^^^^^^^^^^^^^^^ error: trait `PrivTr1` is more private than the item `aliases_priv::Tr2` - --> $DIR/private-in-public-warn.rs:243:5 + --> $DIR/private-in-public-warn.rs:234:5 | LL | pub trait Tr2: PrivUseAliasTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `aliases_priv::Tr2` is reachable at visibility `pub(crate)` | note: but trait `PrivTr1` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:227:5 + --> $DIR/private-in-public-warn.rs:218:5 | LL | trait PrivTr1 { | ^^^^^^^^^^^^^^^^^^^^^ error: type `Priv2` is more private than the item `aliases_priv::Tr2` - --> $DIR/private-in-public-warn.rs:243:5 + --> $DIR/private-in-public-warn.rs:234:5 | LL | pub trait Tr2: PrivUseAliasTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `aliases_priv::Tr2` is reachable at visibility `pub(crate)` | note: but type `Priv2` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:225:5 + --> $DIR/private-in-public-warn.rs:216:5 | LL | struct Priv2; | ^^^^^^^^^^^^ @@ -509,7 +410,7 @@ LL | pub type Alias = T; = note: `#[warn(type_alias_bounds)]` on by default warning: where clauses on type aliases are not enforced - --> $DIR/private-in-public-warn.rs:66:29 + --> $DIR/private-in-public-warn.rs:63:29 | LL | pub type Alias where T: PrivTr = T; | ------^^^^^^^^^ @@ -521,6 +422,6 @@ LL | pub type Alias where T: PrivTr = T; see issue #112792 for more information = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -error: aborting due to 43 previous errors; 2 warnings emitted +error: aborting due to 34 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0446`. diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs index 0bad116934b5..b85f2754fb18 100644 --- a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs +++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs @@ -47,11 +47,8 @@ pub trait MyPubTrait { //~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface fn required() -> impl OtherTrait; - //~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface fn provided() -> impl OtherTrait { OtherType } - //~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface - //~| ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface } pub trait WithSuperTrait: OtherTrait {} diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr index 275bcfcb7da7..24bd071567fc 100644 --- a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr +++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr @@ -11,31 +11,31 @@ LL | #![deny(exported_private_dependencies)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: macro `m` from private dependency 'priv_dep' is re-exported - --> $DIR/pub-priv1.rs:101:9 + --> $DIR/pub-priv1.rs:98:9 | LL | pub use priv_dep::m; | ^^^^^^^^^^^ error: macro `fn_like` from private dependency 'pm' is re-exported - --> $DIR/pub-priv1.rs:103:9 + --> $DIR/pub-priv1.rs:100:9 | LL | pub use pm::fn_like; | ^^^^^^^^^^^ error: derive macro `PmDerive` from private dependency 'pm' is re-exported - --> $DIR/pub-priv1.rs:105:9 + --> $DIR/pub-priv1.rs:102:9 | LL | pub use pm::PmDerive; | ^^^^^^^^^^^^ error: attribute macro `pm_attr` from private dependency 'pm' is re-exported - --> $DIR/pub-priv1.rs:107:9 + --> $DIR/pub-priv1.rs:104:9 | LL | pub use pm::pm_attr; | ^^^^^^^^^^^ error: variant `V1` from private dependency 'priv_dep' is re-exported - --> $DIR/pub-priv1.rs:110:9 + --> $DIR/pub-priv1.rs:107:9 | LL | pub use priv_dep::E::V1; | ^^^^^^^^^^^^^^^ @@ -65,86 +65,66 @@ LL | type Foo: OtherTrait; | ^^^^^^^^^^^^^^^^^^^^ error: trait `OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:49:22 - | -LL | fn required() -> impl OtherTrait; - | ^^^^^^^^^^^^^^^ - -error: trait `OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:52:22 - | -LL | fn provided() -> impl OtherTrait { OtherType } - | ^^^^^^^^^^^^^^^ - -error: trait `OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:52:22 - | -LL | fn provided() -> impl OtherTrait { OtherType } - | ^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: trait `OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:57:1 + --> $DIR/pub-priv1.rs:54:1 | LL | pub trait WithSuperTrait: OtherTrait {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:66:5 + --> $DIR/pub-priv1.rs:63:5 | LL | type X = OtherType; | ^^^^^^ error: trait `OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:70:1 + --> $DIR/pub-priv1.rs:67:1 | LL | pub fn in_bounds(x: T) { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:73:1 + --> $DIR/pub-priv1.rs:70:1 | LL | pub fn private_in_generic() -> std::num::Saturating { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:76:1 + --> $DIR/pub-priv1.rs:73:1 | LL | pub static STATIC: OtherType = OtherType; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:79:1 + --> $DIR/pub-priv1.rs:76:1 | LL | pub const CONST: OtherType = OtherType; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:82:1 + --> $DIR/pub-priv1.rs:79:1 | LL | pub type Alias = OtherType; | ^^^^^^^^^^^^^^ error: trait `OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:87:1 + --> $DIR/pub-priv1.rs:84:1 | LL | impl OtherTrait for PublicWithPrivateImpl {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:92:1 + --> $DIR/pub-priv1.rs:89:1 | LL | impl PubTraitOnPrivate for OtherType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:92:1 + --> $DIR/pub-priv1.rs:89:1 | LL | impl PubTraitOnPrivate for OtherType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 23 previous errors +error: aborting due to 20 previous errors From 2ce0b665d37bceddb29e6dbd45172299380e13f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 18 Jun 2025 15:35:22 +0200 Subject: [PATCH 297/363] HIR ty lowering: Simplify signature of `lower_poly_trait_ref` --- .../src/hir_ty_lowering/bounds.rs | 6 +-- .../src/hir_ty_lowering/dyn_compatibility.rs | 24 ++++------- .../src/hir_ty_lowering/mod.rs | 13 +++--- ...utually-exclusive-trait-bound-modifiers.rs | 3 ++ ...lly-exclusive-trait-bound-modifiers.stderr | 40 ++++++++++++++++--- 5 files changed, 54 insertions(+), 32 deletions(-) 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 9a752aeccdd2..b59ff863383f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -482,12 +482,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match hir_bound { hir::GenericBound::Trait(poly_trait_ref) => { - let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers; let _ = self.lower_poly_trait_ref( - &poly_trait_ref.trait_ref, - poly_trait_ref.span, - constness, - polarity, + poly_trait_ref, param_ty, bounds, predicate_filter, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 364ad38556be..474025e07afc 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -18,9 +18,7 @@ use tracing::{debug, instrument}; use super::HirTyLowerer; use crate::errors::SelfInTypeAlias; -use crate::hir_ty_lowering::{ - GenericArgCountMismatch, GenericArgCountResult, PredicateFilter, RegionInferReason, -}; +use crate::hir_ty_lowering::{GenericArgCountMismatch, PredicateFilter, RegionInferReason}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a trait object type from the HIR to our internal notion of a type. @@ -38,24 +36,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut user_written_bounds = Vec::new(); let mut potential_assoc_types = Vec::new(); - for trait_bound in hir_bounds.iter() { - if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity { + for poly_trait_ref in hir_bounds.iter() { + if let hir::BoundPolarity::Maybe(_) = poly_trait_ref.modifiers.polarity { continue; } - if let GenericArgCountResult { - correct: - Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), - .. - } = self.lower_poly_trait_ref( - &trait_bound.trait_ref, - trait_bound.span, - trait_bound.modifiers.constness, - hir::BoundPolarity::Positive, + let result = self.lower_poly_trait_ref( + poly_trait_ref, dummy_self, &mut user_written_bounds, PredicateFilter::SelfOnly, - ) { - potential_assoc_types.extend(cur_potential_assoc_types); + ); + if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct { + potential_assoc_types.extend(invalid_args); } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index a5bd7c1a34ae..5521f97059b8 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -747,17 +747,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>` /// where `'a` is a bound region at depth 0. Similarly, the `trait_ref` would be `Bar<'a>`. /// The lowered poly-trait-ref will track this binder explicitly, however. - #[instrument(level = "debug", skip(self, span, constness, bounds))] + #[instrument(level = "debug", skip(self, bounds))] pub(crate) fn lower_poly_trait_ref( &self, - trait_ref: &hir::TraitRef<'tcx>, - span: Span, - constness: hir::BoundConstness, - polarity: hir::BoundPolarity, + poly_trait_ref: &hir::PolyTraitRef<'tcx>, self_ty: Ty<'tcx>, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, predicate_filter: PredicateFilter, ) -> GenericArgCountResult { + // We use the *resolved* bound vars later instead of the HIR ones since the former + // also include the bound vars of the overarching predicate if applicable. + let hir::PolyTraitRef { bound_generic_params: _, modifiers, ref trait_ref, span } = + *poly_trait_ref; + let hir::TraitBoundModifiers { constness, polarity } = modifiers; + let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); let trait_segment = trait_ref.path.segments.last().unwrap(); diff --git a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs index 5f47778a1404..8d1d3a4c7907 100644 --- a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs +++ b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs @@ -2,9 +2,12 @@ const fn maybe_const_maybe() {} //~^ ERROR `[const]` trait not allowed with `?` trait polarity modifier +//~| ERROR `[const]` can only be applied to `const` traits +//~| ERROR `[const]` can only be applied to `const` traits fn const_maybe() {} //~^ ERROR `const` trait not allowed with `?` trait polarity modifier +//~| ERROR `const` can only be applied to `const` traits const fn maybe_const_negative() {} //~^ ERROR `[const]` trait not allowed with `!` trait polarity modifier diff --git a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr index 429131f905f0..0ac40c512708 100644 --- a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr +++ b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr @@ -7,7 +7,7 @@ LL | const fn maybe_const_maybe() {} | there is not a well-defined meaning for a `[const] ?` trait error: `const` trait not allowed with `?` trait polarity modifier - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:25 + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:8:25 | LL | fn const_maybe() {} | ----- ^ @@ -15,7 +15,7 @@ LL | fn const_maybe() {} | there is not a well-defined meaning for a `const ?` trait error: `[const]` trait not allowed with `!` trait polarity modifier - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:42 + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:12:42 | LL | const fn maybe_const_negative() {} | ------- ^ @@ -23,7 +23,7 @@ LL | const fn maybe_const_negative() {} | there is not a well-defined meaning for a `[const] !` trait error: `const` trait not allowed with `!` trait polarity modifier - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28 + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:16:28 | LL | fn const_negative() {} | ----- ^ @@ -31,16 +31,44 @@ LL | fn const_negative() {} | there is not a well-defined meaning for a `const !` trait error: negative bounds are not supported - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:42 + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:12:42 | LL | const fn maybe_const_negative() {} | ^ error: negative bounds are not supported - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28 + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:16:28 | LL | fn const_negative() {} | ^ -error: aborting due to 6 previous errors +error: `[const]` can only be applied to `const` traits + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:31 + | +LL | const fn maybe_const_maybe() {} + | ^^^^^^^ can't be applied to `Sized` + | +note: `Sized` can't be used with `[const]` because it isn't `const` + --> $SRC_DIR/core/src/marker.rs:LL:COL + +error: `[const]` can only be applied to `const` traits + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:31 + | +LL | const fn maybe_const_maybe() {} + | ^^^^^^^ can't be applied to `Sized` + | +note: `Sized` can't be used with `[const]` because it isn't `const` + --> $SRC_DIR/core/src/marker.rs:LL:COL + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `const` can only be applied to `const` traits + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:8:19 + | +LL | fn const_maybe() {} + | ^^^^^ can't be applied to `Sized` + | +note: `Sized` can't be used with `const` because it isn't `const` + --> $SRC_DIR/core/src/marker.rs:LL:COL + +error: aborting due to 9 previous errors From 10d7e5faf20d019568de77503cb13f0203296d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 18 Jun 2025 16:43:38 +0200 Subject: [PATCH 298/363] HIR ty lowering: Validate relaxed bounds in trait object types Only relevant to the internal feature `more_maybe_bounds`. --- .../src/hir_ty_lowering/dyn_compatibility.rs | 3 --- .../maybe-bounds-in-dyn-traits.rs | 4 +++ .../maybe-bounds-in-dyn-traits.stderr | 25 +++++++++++++++++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 474025e07afc..813353c12aa0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -37,9 +37,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut user_written_bounds = Vec::new(); let mut potential_assoc_types = Vec::new(); for poly_trait_ref in hir_bounds.iter() { - if let hir::BoundPolarity::Maybe(_) = poly_trait_ref.modifiers.polarity { - continue; - } let result = self.lower_poly_trait_ref( poly_trait_ref, dummy_self, diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs index 5069cd256b27..e7cca41a47ea 100644 --- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs @@ -64,4 +64,8 @@ fn main() { x.leak_foo(); //~^ ERROR the trait bound `dyn Trait: Leak` is not satisfied x.maybe_leak_foo(); + // Ensure that we validate the generic args of relaxed bounds in trait object types. + let _: dyn Trait + ?Leak<(), Undefined = ()>; + //~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR associated type `Undefined` not found for `Leak` } diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr index 48745e40268d..350233b7cbe9 100644 --- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr @@ -18,6 +18,27 @@ note: required by a bound in `Trait::leak_foo` LL | fn leak_foo(&self) {} | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo` -error: aborting due to 2 previous errors +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/maybe-bounds-in-dyn-traits.rs:68:25 + | +LL | let _: dyn Trait + ?Leak<(), Undefined = ()>; + | ^^^^-------------------- help: remove the unnecessary generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/maybe-bounds-in-dyn-traits.rs:44:12 + | +LL | auto trait Leak {} + | ^^^^ -For more information about this error, try `rustc --explain E0277`. +error[E0220]: associated type `Undefined` not found for `Leak` + --> $DIR/maybe-bounds-in-dyn-traits.rs:68:34 + | +LL | let _: dyn Trait + ?Leak<(), Undefined = ()>; + | ^^^^^^^^^ associated type `Undefined` not found + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0107, E0220, E0277. +For more information about an error, try `rustc --explain E0107`. From 9788f59bbf893965db98dc633e64e4405414b698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 18 Jun 2025 17:02:51 +0200 Subject: [PATCH 299/363] Update comment about `where Ty:` We no longer move trait predicates where the self ty is a ty param to "the bounds of a ty param". --- .../src/collect/predicates_of.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index f2f1560d8b22..cc53919626e6 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -267,20 +267,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen match predicate.kind { hir::WherePredicateKind::BoundPredicate(bound_pred) => { let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty); - let bound_vars = tcx.late_bound_vars(predicate.hir_id); - // Keep the type around in a dummy predicate, in case of no bounds. - // That way, `where Ty:` is not a complete noop (see #53696) and `Ty` - // is still checked for WF. + + // This is a `where Ty:` (sic!). if bound_pred.bounds.is_empty() { if let ty::Param(_) = ty.kind() { - // This is a `where T:`, which can be in the HIR from the - // transformation that moves `?Sized` to `T`'s declaration. - // We can skip the predicate because type parameters are - // trivially WF, but also we *should*, to avoid exposing - // users who never wrote `where Type:,` themselves, to - // compiler/tooling bugs from not handling WF predicates. + // We can skip the predicate because type parameters are trivially WF. } else { + // Keep the type around in a dummy predicate. That way, it's not a complete + // noop (see #53696) and `Ty` is still checked for WF. + let span = bound_pred.bounded_ty.span; let predicate = ty::Binder::bind_with_vars( ty::ClauseKind::WellFormed(ty.into()), From 1df99f22d3a1776b36fc00fc35626fd841f7242f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 18 Jun 2025 22:10:53 +0200 Subject: [PATCH 300/363] AST lowering: More robustly deal with relaxed bounds --- compiler/rustc_ast_lowering/messages.ftl | 3 - compiler/rustc_ast_lowering/src/errors.rs | 7 - compiler/rustc_ast_lowering/src/item.rs | 112 ++++++--------- compiler/rustc_ast_lowering/src/lib.rs | 128 +++++++++++++++--- compiler/rustc_ast_passes/messages.ftl | 5 - .../rustc_ast_passes/src/ast_validation.rs | 23 ---- compiler/rustc_ast_passes/src/errors.rs | 16 --- ...issing-associated_item_or_field_def_ids.rs | 5 +- ...ng-associated_item_or_field_def_ids.stderr | 24 ++-- ...ing-associated-items-of-undefined-trait.rs | 5 +- ...associated-items-of-undefined-trait.stderr | 27 ++-- .../feature-gate-more-maybe-bounds.stderr | 19 ++- .../sized-hierarchy/default-supertrait.stderr | 4 +- ...be-trait-bounds-forbidden-locations.stderr | 2 +- ...re.rs => relaxed-bounds-invalid-places.rs} | 3 + ...r => relaxed-bounds-invalid-places.stderr} | 16 +-- 16 files changed, 189 insertions(+), 210 deletions(-) rename tests/ui/unsized/{maybe-bounds-where.rs => relaxed-bounds-invalid-places.rs} (85%) rename tests/ui/unsized/{maybe-bounds-where.stderr => relaxed-bounds-invalid-places.stderr} (87%) diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index c6472fd45fa9..370b15d2871a 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -127,9 +127,6 @@ ast_lowering_misplaced_impl_trait = `impl Trait` is not allowed in {$position} .note = `impl Trait` is only allowed in arguments and return types of functions and methods -ast_lowering_misplaced_relax_trait_bound = - `?Trait` bounds are only permitted at the point where a type parameter is declared - ast_lowering_never_pattern_with_body = a never pattern is always unreachable .label = this will never be executed diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index b444324ef914..83f3a976e83f 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -324,13 +324,6 @@ pub(crate) struct MisplacedDoubleDot { pub span: Span, } -#[derive(Diagnostic)] -#[diag(ast_lowering_misplaced_relax_trait_bound)] -pub(crate) struct MisplacedRelaxTraitBound { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_lowering_match_arm_with_no_body)] pub(crate) struct MatchArmWithNoBody { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index abd70c7517c8..ddf01b69e7f6 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -16,14 +16,11 @@ use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::instrument; -use super::errors::{ - InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound, TupleStructWithDefault, - UnionWithDefault, -}; +use super::errors::{InvalidAbi, InvalidAbiSuggestion, TupleStructWithDefault, UnionWithDefault}; use super::stability::{enabled_names, gate_unstable_abi}; use super::{ AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, - ResolverAstLoweringExt, + RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt, }; pub(super) struct ItemLowerer<'a, 'hir> { @@ -435,6 +432,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { let bounds = this.lower_param_bounds( bounds, + RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::SuperTrait), ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ); let items = this.arena.alloc_from_iter( @@ -455,6 +453,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { this.lower_param_bounds( bounds, + RelaxedBoundPolicy::Allowed, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ) }, @@ -940,6 +939,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::TraitItemKind::Type( this.lower_param_bounds( bounds, + RelaxedBoundPolicy::Allowed, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), ), ty, @@ -1677,61 +1677,6 @@ impl<'hir> LoweringContext<'_, 'hir> { assert!(self.impl_trait_defs.is_empty()); assert!(self.impl_trait_bounds.is_empty()); - // Error if `?Trait` bounds in where clauses don't refer directly to type parameters. - // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering - // these into hir when we lower thee where clauses), but this makes it quite difficult to - // keep track of the Span info. Now, `::add_implicit_sized_bound` - // checks both param bounds and where clauses for `?Sized`. - for pred in &generics.where_clause.predicates { - let WherePredicateKind::BoundPredicate(bound_pred) = &pred.kind else { - continue; - }; - let compute_is_param = || { - // Check if the where clause type is a plain type parameter. - match self - .resolver - .get_partial_res(bound_pred.bounded_ty.id) - .and_then(|r| r.full_res()) - { - Some(Res::Def(DefKind::TyParam, def_id)) - if bound_pred.bound_generic_params.is_empty() => - { - generics - .params - .iter() - .any(|p| def_id == self.local_def_id(p.id).to_def_id()) - } - // Either the `bounded_ty` is not a plain type parameter, or - // it's not found in the generic type parameters list. - _ => false, - } - }; - // We only need to compute this once per `WherePredicate`, but don't - // need to compute this at all unless there is a Maybe bound. - let mut is_param: Option = None; - for bound in &bound_pred.bounds { - if !matches!( - *bound, - GenericBound::Trait(PolyTraitRef { - modifiers: TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. }, - .. - }) - ) { - continue; - } - let is_param = *is_param.get_or_insert_with(compute_is_param); - if !is_param && !self.tcx.features().more_maybe_bounds() { - self.tcx - .sess - .create_feature_err( - MisplacedRelaxTraitBound { span: bound.span() }, - sym::more_maybe_bounds, - ) - .emit(); - } - } - } - let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new(); predicates.extend(generics.params.iter().filter_map(|param| { self.lower_generic_bound_predicate( @@ -1741,6 +1686,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ¶m.bounds, param.colon_span, generics.span, + RelaxedBoundPolicy::Allowed, itctx, PredicateOrigin::GenericParam, ) @@ -1750,7 +1696,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .where_clause .predicates .iter() - .map(|predicate| self.lower_where_predicate(predicate)), + .map(|predicate| self.lower_where_predicate(predicate, &generics.params)), ); let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = self @@ -1827,6 +1773,7 @@ impl<'hir> LoweringContext<'_, 'hir> { bounds: &[GenericBound], colon_span: Option, parent_span: Span, + rbp: RelaxedBoundPolicy<'_>, itctx: ImplTraitContext, origin: PredicateOrigin, ) -> Option> { @@ -1835,7 +1782,7 @@ impl<'hir> LoweringContext<'_, 'hir> { return None; } - let bounds = self.lower_param_bounds(bounds, itctx); + let bounds = self.lower_param_bounds(bounds, rbp, itctx); let param_span = ident.span; @@ -1887,7 +1834,11 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(hir::WherePredicate { hir_id, span, kind }) } - fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> { + fn lower_where_predicate( + &mut self, + pred: &WherePredicate, + params: &[ast::GenericParam], + ) -> hir::WherePredicate<'hir> { let hir_id = self.lower_node_id(pred.id); let span = self.lower_span(pred.span); self.lower_attrs(hir_id, &pred.attrs, span); @@ -1896,17 +1847,29 @@ impl<'hir> LoweringContext<'_, 'hir> { bound_generic_params, bounded_ty, bounds, - }) => hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate { - bound_generic_params: self - .lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder), - bounded_ty: self - .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), - bounds: self.lower_param_bounds( - bounds, - ImplTraitContext::Disallowed(ImplTraitPosition::Bound), - ), - origin: PredicateOrigin::WhereClause, - }), + }) => { + let rbp = if bound_generic_params.is_empty() { + RelaxedBoundPolicy::AllowedIfOnTyParam(bounded_ty.id, params) + } else { + RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::LateBoundVarsInScope) + }; + hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate { + bound_generic_params: self.lower_generic_params( + bound_generic_params, + hir::GenericParamSource::Binder, + ), + bounded_ty: self.lower_ty( + bounded_ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ), + bounds: self.lower_param_bounds( + bounds, + rbp, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ), + origin: PredicateOrigin::WhereClause, + }) + } WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => { hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { lifetime: self.lower_lifetime( @@ -1916,6 +1879,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), bounds: self.lower_param_bounds( bounds, + RelaxedBoundPolicy::Allowed, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ), in_where_clause: true, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1c96a375035a..d3d521e83b09 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -53,14 +53,14 @@ use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::lints::DelayedLint; use rustc_hir::{ - self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, - LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate, + self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource, + LifetimeSyntax, ParamName, TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; -use rustc_session::parse::add_feature_diagnostics; +use rustc_session::parse::{add_feature_diagnostics, feature_err}; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, DesugaringKind, Span}; use smallvec::SmallVec; @@ -281,6 +281,24 @@ impl ResolverAstLowering { } } +/// How relaxed bounds `?Trait` should be treated. +/// +/// Relaxed bounds should only be allowed in places where we later +/// (namely during HIR ty lowering) perform *sized elaboration*. +#[derive(Clone, Copy, Debug)] +enum RelaxedBoundPolicy<'a> { + Allowed, + AllowedIfOnTyParam(NodeId, &'a [ast::GenericParam]), + Forbidden(RelaxedBoundForbiddenReason), +} + +#[derive(Clone, Copy, Debug)] +enum RelaxedBoundForbiddenReason { + TraitObjectTy, + SuperTrait, + LateBoundVarsInScope, +} + /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree, /// and if so, what meaning it has. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -1084,10 +1102,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar))); hir::AssocItemConstraintKind::Equality { term: err_ty.into() } } else { - // Desugar `AssocTy: Bounds` into an assoc type binding where the - // later desugars into a trait predicate. - let bounds = self.lower_param_bounds(bounds, itctx); - + // FIXME(#135229): These should be forbidden! + let bounds = + self.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx); hir::AssocItemConstraintKind::Bound { bounds } } } @@ -1216,6 +1233,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: t.span, parens: ast::Parens::No, }, + RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::TraitObjectTy), itctx, ); let bounds = this.arena.alloc_from_iter([bound]); @@ -1271,7 +1289,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { parenthesized: hir::GenericArgsParentheses::No, span_ext: span, }); - let path = self.make_lang_item_qpath(LangItem::Pin, span, Some(args)); + let path = self.make_lang_item_qpath(hir::LangItem::Pin, span, Some(args)); hir::TyKind::Path(path) } TyKind::FnPtr(f) => { @@ -1332,7 +1350,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // takes care of rejecting invalid modifier combinations and // const trait bounds in trait object types. GenericBound::Trait(ty) => { - let trait_ref = this.lower_poly_trait_ref(ty, itctx); + let trait_ref = this.lower_poly_trait_ref( + ty, + RelaxedBoundPolicy::Forbidden( + RelaxedBoundForbiddenReason::TraitObjectTy, + ), + itctx, + ); Some(trait_ref) } GenericBound::Outlives(lifetime) => { @@ -1387,9 +1411,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } path } - ImplTraitContext::InBinding => { - hir::TyKind::TraitAscription(self.lower_param_bounds(bounds, itctx)) - } + ImplTraitContext::InBinding => hir::TyKind::TraitAscription( + self.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx), + ), ImplTraitContext::FeatureGated(position, feature) => { let guar = self .tcx @@ -1505,7 +1529,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); self.lower_opaque_inner(opaque_ty_node_id, origin, opaque_ty_span, |this| { - this.lower_param_bounds(bounds, itctx) + this.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx) }) } @@ -1799,10 +1823,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_param_bound( &mut self, tpb: &GenericBound, + rbp: RelaxedBoundPolicy<'_>, itctx: ImplTraitContext, ) -> hir::GenericBound<'hir> { match tpb { - GenericBound::Trait(p) => hir::GenericBound::Trait(self.lower_poly_trait_ref(p, itctx)), + GenericBound::Trait(p) => { + hir::GenericBound::Trait(self.lower_poly_trait_ref(p, rbp, itctx)) + } GenericBound::Outlives(lifetime) => hir::GenericBound::Outlives(self.lower_lifetime( lifetime, LifetimeSource::OutlivesBound, @@ -2017,21 +2044,77 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn lower_poly_trait_ref( &mut self, - p: &PolyTraitRef, + PolyTraitRef { bound_generic_params, modifiers, trait_ref, span, parens: _ }: &PolyTraitRef, + rbp: RelaxedBoundPolicy<'_>, itctx: ImplTraitContext, ) -> hir::PolyTraitRef<'hir> { let bound_generic_params = - self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params); - let trait_ref = self.lower_trait_ref(p.modifiers, &p.trait_ref, itctx); - let modifiers = self.lower_trait_bound_modifiers(p.modifiers); + self.lower_lifetime_binder(trait_ref.ref_id, bound_generic_params); + let trait_ref = self.lower_trait_ref(*modifiers, trait_ref, itctx); + let modifiers = self.lower_trait_bound_modifiers(*modifiers); + + if let ast::BoundPolarity::Maybe(_) = modifiers.polarity { + self.validate_relaxed_bound(trait_ref, *span, rbp); + } + hir::PolyTraitRef { bound_generic_params, modifiers, trait_ref, - span: self.lower_span(p.span), + span: self.lower_span(*span), } } + fn validate_relaxed_bound( + &self, + trait_ref: hir::TraitRef<'_>, + span: Span, + rbp: RelaxedBoundPolicy<'_>, + ) { + let err = |message| feature_err(&self.tcx.sess, sym::more_maybe_bounds, span, message); + + match rbp { + RelaxedBoundPolicy::Allowed => return, + RelaxedBoundPolicy::AllowedIfOnTyParam(id, params) => { + if let Some(res) = self.resolver.get_partial_res(id).and_then(|r| r.full_res()) + && let Res::Def(DefKind::TyParam, def_id) = res + && params.iter().any(|p| def_id == self.local_def_id(p.id).to_def_id()) + { + return; + } + if self.tcx.features().more_maybe_bounds() { + return; + } + } + RelaxedBoundPolicy::Forbidden(reason) => { + if self.tcx.features().more_maybe_bounds() { + return; + } + + match reason { + RelaxedBoundForbiddenReason::TraitObjectTy => { + err("`?Trait` is not permitted in trait object types").emit(); + return; + } + RelaxedBoundForbiddenReason::SuperTrait => { + let mut diag = err("`?Trait` is not permitted in supertraits"); + if let Some(def_id) = trait_ref.trait_def_id() + && self.tcx.is_lang_item(def_id, hir::LangItem::Sized) + { + diag.note("traits are `?Sized` by default"); + } + diag.emit(); + return; + } + RelaxedBoundForbiddenReason::LateBoundVarsInScope => {} + }; + } + } + + err("`?Trait` bounds are only permitted at the point where a type parameter is declared") + .emit(); + } + fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl } } @@ -2040,17 +2123,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_param_bounds( &mut self, bounds: &[GenericBound], + rbp: RelaxedBoundPolicy<'_>, itctx: ImplTraitContext, ) -> hir::GenericBounds<'hir> { - self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx)) + self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, rbp, itctx)) } fn lower_param_bounds_mut( &mut self, bounds: &[GenericBound], + rbp: RelaxedBoundPolicy<'_>, itctx: ImplTraitContext, ) -> impl Iterator> { - bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx)) + bounds.iter().map(move |bound| self.lower_param_bound(bound, rbp, itctx)) } #[instrument(level = "debug", skip(self), ret)] @@ -2084,6 +2169,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds, /* colon_span */ None, span, + RelaxedBoundPolicy::Allowed, ImplTraitContext::Universal, hir::PredicateOrigin::ImplTrait, ); diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index e419154d65d1..af93d55c8982 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -212,11 +212,6 @@ ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax .help = use `auto trait Trait {"{}"}` instead -ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types - -ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits - .note = traits are `?{$path_str}` by default - ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters .suggestion = reorder the parameters: lifetimes, then consts and types diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index c69250c03052..a08dae111530 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1381,29 +1381,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match bound { GenericBound::Trait(trait_ref) => { match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) { - (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) - if !self.features.more_maybe_bounds() => - { - self.sess - .create_feature_err( - errors::OptionalTraitSupertrait { - span: trait_ref.span, - path_str: pprust::path_to_string(&trait_ref.trait_ref.path), - }, - sym::more_maybe_bounds, - ) - .emit(); - } - (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) - if !self.features.more_maybe_bounds() => - { - self.sess - .create_feature_err( - errors::OptionalTraitObject { span: trait_ref.span }, - sym::more_maybe_bounds, - ) - .emit(); - } ( BoundKind::TraitObject, BoundConstness::Always(_), diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index c1ebd025c7a4..fd4b2528541e 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -566,22 +566,6 @@ pub(crate) struct NestedLifetimes { pub span: Span, } -#[derive(Diagnostic)] -#[diag(ast_passes_optional_trait_supertrait)] -#[note] -pub(crate) struct OptionalTraitSupertrait { - #[primary_span] - pub span: Span, - pub path_str: String, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_optional_trait_object)] -pub(crate) struct OptionalTraitObject { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_passes_const_bound_trait_object)] pub(crate) struct ConstBoundTraitObject { diff --git a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs index b90bb9ea4ddf..18c71e5c7442 100644 --- a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs +++ b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs @@ -1,8 +1,7 @@ // Regression test for . fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { - //~^ ERROR `?Trait` is not permitted in trait object types - //~| ERROR expected trait, found associated function `Iterator::advance_by` - //~| ERROR the value of the associated type `Item` in `Iterator` must be specified + //~^ ERROR expected trait, found associated function `Iterator::advance_by` + //~| ERROR `?Trait` is not permitted in trait object types todo!() } diff --git a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr index 7f0fbc800ed1..6ec8e01c78d3 100644 --- a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr +++ b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr @@ -1,3 +1,9 @@ +error[E0404]: expected trait, found associated function `Iterator::advance_by` + --> $DIR/missing-associated_item_or_field_def_ids.rs:3:30 + | +LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a trait + error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/missing-associated_item_or_field_def_ids.rs:3:29 | @@ -7,19 +13,7 @@ LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { = help: add `#![feature(more_maybe_bounds)]` 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[E0404]: expected trait, found associated function `Iterator::advance_by` - --> $DIR/missing-associated_item_or_field_def_ids.rs:3:30 - | -LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a trait +error: aborting due to 2 previous errors -error[E0191]: the value of the associated type `Item` in `Iterator` must be specified - --> $DIR/missing-associated_item_or_field_def_ids.rs:3:18 - | -LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { - | ^^^^^^^^ help: specify the associated type: `Iterator` - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0191, E0404, E0658. -For more information about an error, try `rustc --explain E0191`. +Some errors have detailed explanations: E0404, E0658. +For more information about an error, try `rustc --explain E0404`. diff --git a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs index f6b749a5100b..9e0a86abb2e0 100644 --- a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs +++ b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs @@ -6,7 +6,6 @@ trait Tr { fn main() { let _: dyn Tr + ?Foo; - //~^ ERROR: `?Trait` is not permitted in trait object types - //~| ERROR: cannot find trait `Foo` in this scope - //~| ERROR: the value of the associated type `Item` in `Tr` must be specified + //~^ ERROR: cannot find trait `Foo` in this scope + //~| ERROR: `?Trait` is not permitted in trait object types } diff --git a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr index f31a1de76a79..bd83c1a9ea89 100644 --- a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr +++ b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr @@ -1,3 +1,9 @@ +error[E0405]: cannot find trait `Foo` in this scope + --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:22 + | +LL | let _: dyn Tr + ?Foo; + | ^^^ not found in this scope + error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:21 | @@ -7,22 +13,7 @@ LL | let _: dyn Tr + ?Foo; = help: add `#![feature(more_maybe_bounds)]` 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[E0405]: cannot find trait `Foo` in this scope - --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:22 - | -LL | let _: dyn Tr + ?Foo; - | ^^^ not found in this scope +error: aborting due to 2 previous errors -error[E0191]: the value of the associated type `Item` in `Tr` must be specified - --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:16 - | -LL | type Item; - | --------- `Item` defined here -... -LL | let _: dyn Tr + ?Foo; - | ^^ help: specify the associated type: `Tr` - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0191, E0405, E0658. -For more information about an error, try `rustc --explain E0191`. +Some errors have detailed explanations: E0405, E0658. +For more information about an error, try `rustc --explain E0405`. diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr index 729df4eb37ca..f52532a035b4 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr @@ -4,16 +4,6 @@ error[E0658]: `?Trait` is not permitted in supertraits LL | trait Trait3: ?Trait1 {} | ^^^^^^^ | - = note: traits are `?Trait1` by default - = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types - --> $DIR/feature-gate-more-maybe-bounds.rs:10:28 - | -LL | fn foo(_: Box) {} - | ^^^^^^^ - | = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date @@ -26,6 +16,15 @@ LL | trait Trait4 where Self: ?Trait1 {} = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types + --> $DIR/feature-gate-more-maybe-bounds.rs:10:28 + | +LL | fn foo(_: Box) {} + | ^^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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[E0203]: type parameter has more than one relaxed default bound, only one is supported --> $DIR/feature-gate-more-maybe-bounds.rs:12:11 | diff --git a/tests/ui/sized-hierarchy/default-supertrait.stderr b/tests/ui/sized-hierarchy/default-supertrait.stderr index de23936b900b..0cb4f346a630 100644 --- a/tests/ui/sized-hierarchy/default-supertrait.stderr +++ b/tests/ui/sized-hierarchy/default-supertrait.stderr @@ -4,9 +4,9 @@ error[E0658]: `?Trait` is not permitted in supertraits LL | trait NegSized: ?Sized { } | ^^^^^^ | - = note: traits are `?Sized` by default = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: traits are `?Sized` by default error[E0658]: `?Trait` is not permitted in supertraits --> $DIR/default-supertrait.rs:13:21 @@ -14,7 +14,6 @@ error[E0658]: `?Trait` is not permitted in supertraits LL | trait NegMetaSized: ?MetaSized { } | ^^^^^^^^^^ | - = note: traits are `?MetaSized` by default = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date @@ -24,7 +23,6 @@ error[E0658]: `?Trait` is not permitted in supertraits LL | trait NegPointeeSized: ?PointeeSized { } | ^^^^^^^^^^^^^ | - = note: traits are `?PointeeSized` by default = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr b/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr index bd0baa580bdf..5c4100d0e269 100644 --- a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr +++ b/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr @@ -4,9 +4,9 @@ error[E0658]: `?Trait` is not permitted in supertraits LL | trait Tr: ?Sized {} | ^^^^^^ | - = note: traits are `?Sized` by default = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: traits are `?Sized` by default error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-trait-bounds-forbidden-locations.rs:13:20 diff --git a/tests/ui/unsized/maybe-bounds-where.rs b/tests/ui/unsized/relaxed-bounds-invalid-places.rs similarity index 85% rename from tests/ui/unsized/maybe-bounds-where.rs rename to tests/ui/unsized/relaxed-bounds-invalid-places.rs index 4c4141631a7c..ce3f35608beb 100644 --- a/tests/ui/unsized/maybe-bounds-where.rs +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.rs @@ -1,3 +1,6 @@ +// Test that relaxed bounds can only be placed on type parameters defined by the closest item +// (ignoring relaxed bounds inside `impl Trait` and in associated type defs here). + struct S1(T) where (T): ?Sized; //~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared diff --git a/tests/ui/unsized/maybe-bounds-where.stderr b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr similarity index 87% rename from tests/ui/unsized/maybe-bounds-where.stderr rename to tests/ui/unsized/relaxed-bounds-invalid-places.stderr index fb6d37c29660..3287eb8d1e9d 100644 --- a/tests/ui/unsized/maybe-bounds-where.stderr +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr @@ -1,5 +1,5 @@ error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:1:28 + --> $DIR/relaxed-bounds-invalid-places.rs:4:28 | LL | struct S1(T) where (T): ?Sized; | ^^^^^^ @@ -8,7 +8,7 @@ LL | struct S1(T) where (T): ?Sized; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:4:27 + --> $DIR/relaxed-bounds-invalid-places.rs:7:27 | LL | struct S2(T) where u8: ?Sized; | ^^^^^^ @@ -17,7 +17,7 @@ LL | struct S2(T) where u8: ?Sized; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:7:35 + --> $DIR/relaxed-bounds-invalid-places.rs:10:35 | LL | struct S3(T) where &'static T: ?Sized; | ^^^^^^ @@ -26,7 +26,7 @@ LL | struct S3(T) where &'static T: ?Sized; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:12:34 + --> $DIR/relaxed-bounds-invalid-places.rs:15:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; | ^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | struct S4(T) where for<'a> T: ?Trait<'a>; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:21:21 + --> $DIR/relaxed-bounds-invalid-places.rs:24:21 | LL | fn f() where T: ?Sized {} | ^^^^^^ @@ -44,13 +44,13 @@ LL | fn f() where T: ?Sized {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-bounds-where.rs:12:34 + --> $DIR/relaxed-bounds-invalid-places.rs:15:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; | ^^^^^^^^^^ error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/maybe-bounds-where.rs:16:33 + --> $DIR/relaxed-bounds-invalid-places.rs:19:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^^^^^^^^^^^^^^^ ^^^^^^ @@ -59,7 +59,7 @@ LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-bounds-where.rs:16:33 + --> $DIR/relaxed-bounds-invalid-places.rs:19:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^^^^^^^^^^^^^^^ From 8388b31c5bb1478defee2963c6caae69348a7e1a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 18 Jul 2025 14:02:00 +1000 Subject: [PATCH 301/363] Split some multi-snapshot tests to make blessing easier When a snapshot test fails, it only emits a `.pending-snap` file for the first snapshot assertion that actually failed, because subsequent assertions aren't executed. That makes it cumbersome to re-bless tests that contain multiple snapshot assertions. --- src/bootstrap/src/core/builder/tests.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 51a906496923..e71edbb8bc5f 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -712,7 +712,11 @@ mod snapshot { [build] llvm [build] rustc 0 -> rustc 1 "); + } + #[test] + fn build_rustc_no_explicit_stage() { + let ctx = TestCtx::new(); insta::assert_snapshot!( ctx.config("build") .path("rustc") @@ -1299,7 +1303,11 @@ mod snapshot { [check] rustc 0 -> cranelift 1 [check] rustc 0 -> gcc 1 "); + } + #[test] + fn check_rustc_no_explicit_stage() { + let ctx = TestCtx::new(); insta::assert_snapshot!( ctx.config("check") .path("rustc") From 7a217e1ba51b486cd7d56eb684ae44dc3a44e1b3 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 16 Jul 2025 17:16:15 +1000 Subject: [PATCH 302/363] Don't trigger an LLVM build from check builds using the stage 0 compiler --- src/bootstrap/src/core/build_steps/compile.rs | 29 ++++++++++++------- src/bootstrap/src/core/builder/tests.rs | 8 ----- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 09bb2e35bdaa..9d29b1320b11 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1323,7 +1323,7 @@ pub fn rustc_cargo_env( builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection, - build_stage: u32, + _build_stage: u32, ) { // Set some configuration variables picked up by build scripts and // the compiler alike @@ -1379,18 +1379,24 @@ pub fn rustc_cargo_env( cargo.rustflag("--cfg=llvm_enzyme"); } - // Note that this is disabled if LLVM itself is disabled or we're in a check - // build. If we are in a check build we still go ahead here presuming we've - // detected that LLVM is already built and good to go which helps prevent - // busting caches (e.g. like #71152). + // These conditionals represent a tension between three forces: + // - For non-check builds, we need to define some LLVM-related environment + // variables, requiring LLVM to have been built. + // - For check builds, we want to avoid building LLVM if possible. + // - Check builds and non-check builds should have the same environment if + // possible, to avoid unnecessary rebuilds due to cache-busting. + // + // Therefore we try to avoid building LLVM for check builds, but only if + // building LLVM would be expensive. If "building" LLVM is cheap + // (i.e. it's already built or is downloadable), we prefer to maintain a + // consistent environment between check and non-check builds. if builder.config.llvm_enabled(target) { - let building_is_expensive = + let building_llvm_is_expensive = crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target, false) .should_build(); - // `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler - let can_skip_build = builder.kind == Kind::Check && builder.top_stage == build_stage; - let should_skip_build = building_is_expensive && can_skip_build; - if !should_skip_build { + + let skip_llvm = (builder.kind == Kind::Check) && building_llvm_is_expensive; + if !skip_llvm { rustc_llvm_env(builder, cargo, target) } } @@ -1407,6 +1413,9 @@ pub fn rustc_cargo_env( /// Pass down configuration from the LLVM build into the build of /// rustc_llvm and rustc_codegen_llvm. +/// +/// Note that this has the side-effect of _building LLVM_, which is sometimes +/// unwanted (e.g. for check builds). fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { if builder.config.is_rust_llvm(target) { cargo.env("LLVM_RUSTLLVM", "1"); diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index e71edbb8bc5f..97e7e512ce1a 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1298,7 +1298,6 @@ mod snapshot { ctx.config("check") .path("compiler") .render_steps(), @r" - [build] llvm [check] rustc 0 -> rustc 1 [check] rustc 0 -> cranelift 1 [check] rustc 0 -> gcc 1 @@ -1312,7 +1311,6 @@ mod snapshot { ctx.config("check") .path("rustc") .render_steps(), @r" - [build] llvm [check] rustc 0 -> rustc 1 "); } @@ -1332,7 +1330,6 @@ mod snapshot { .path("compiler") .stage(1) .render_steps(), @r" - [build] llvm [check] rustc 0 -> rustc 1 [check] rustc 0 -> cranelift 1 [check] rustc 0 -> gcc 1 @@ -1464,7 +1461,6 @@ mod snapshot { .paths(&["library", "compiler"]) .args(&args) .render_steps(), @r" - [build] llvm [check] rustc 0 -> rustc 1 [check] rustc 0 -> cranelift 1 [check] rustc 0 -> gcc 1 @@ -1478,7 +1474,6 @@ mod snapshot { ctx.config("check") .path("miri") .render_steps(), @r" - [build] llvm [check] rustc 0 -> rustc 1 [check] rustc 0 -> Miri 1 "); @@ -1499,7 +1494,6 @@ mod snapshot { .path("miri") .stage(1) .render_steps(), @r" - [build] llvm [check] rustc 0 -> rustc 1 [check] rustc 0 -> Miri 1 "); @@ -1552,7 +1546,6 @@ mod snapshot { ctx.config("check") .path("rustc_codegen_cranelift") .render_steps(), @r" - [build] llvm [check] rustc 0 -> rustc 1 [check] rustc 0 -> cranelift 1 [check] rustc 0 -> gcc 1 @@ -1566,7 +1559,6 @@ mod snapshot { ctx.config("check") .path("rust-analyzer") .render_steps(), @r" - [build] llvm [check] rustc 0 -> rustc 1 [check] rustc 0 -> rust-analyzer 1 "); From a028ca5f9bd771e825e5c8c3c55f938aea89985e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 16 Jul 2025 20:53:29 +1000 Subject: [PATCH 303/363] Clean up an unused compiler-stage parameter --- src/bootstrap/src/core/build_steps/check.rs | 2 +- src/bootstrap/src/core/build_steps/compile.rs | 11 +++-------- src/bootstrap/src/core/build_steps/test.rs | 4 ++-- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 3278b55305c8..0aec3cf7ca4b 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -350,7 +350,7 @@ impl Step for CodegenBackend { cargo .arg("--manifest-path") .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml"))); - rustc_cargo_env(builder, &mut cargo, target, build_compiler.stage); + rustc_cargo_env(builder, &mut cargo, target); let _guard = builder.msg_check(format!("rustc_codegen_{backend}"), target, None); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 9d29b1320b11..fc5bf6dc354e 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1316,15 +1316,10 @@ pub fn rustc_cargo( cargo.env("RUSTC_WRAPPER", ccache); } - rustc_cargo_env(builder, cargo, target, build_compiler.stage); + rustc_cargo_env(builder, cargo, target); } -pub fn rustc_cargo_env( - builder: &Builder<'_>, - cargo: &mut Cargo, - target: TargetSelection, - _build_stage: u32, -) { +pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { // Set some configuration variables picked up by build scripts and // the compiler alike cargo @@ -1674,7 +1669,7 @@ impl Step for CodegenBackend { cargo .arg("--manifest-path") .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml"))); - rustc_cargo_env(builder, &mut cargo, target, compiler.stage); + rustc_cargo_env(builder, &mut cargo, target); // Ideally, we'd have a separate step for the individual codegen backends, // like we have in tests (test::CodegenGCC) but that would require a lot of restructuring. diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 9e7ea5c115f1..b7dd2b778bb6 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3386,7 +3386,7 @@ impl Step for CodegenCranelift { cargo .arg("--manifest-path") .arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml")); - compile::rustc_cargo_env(builder, &mut cargo, target, compiler.stage); + compile::rustc_cargo_env(builder, &mut cargo, target); // Avoid incremental cache issues when changing rustc cargo.env("CARGO_BUILD_INCREMENTAL", "false"); @@ -3518,7 +3518,7 @@ impl Step for CodegenGCC { cargo .arg("--manifest-path") .arg(builder.src.join("compiler/rustc_codegen_gcc/build_system/Cargo.toml")); - compile::rustc_cargo_env(builder, &mut cargo, target, compiler.stage); + compile::rustc_cargo_env(builder, &mut cargo, target); add_cg_gcc_cargo_flags(&mut cargo, &gcc); // Avoid incremental cache issues when changing rustc From cadcc1ce7137e63c70740e6cc3897557094382af Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 17 Jul 2025 20:14:16 +0200 Subject: [PATCH 304/363] bootstrap: Ignore `rust.debuginfo-level-tests` for codegen tests codegen tests typically depend on the raw LLVM IR output and are sensitive to debuginfo level. So do not apply `rust.debuginfo-level-tests` for codegen tests. Before this commit: $ ./x test --set rust.debuginfo-level-tests=2 tests/codegen --force-rerun test result: FAILED. 654 passed; 136 failed; 75 ignored; 0 measured; 0 filtered out; finished in 3.22s After this commit: $ ./x test --set rust.debuginfo-level-tests=2 tests/codegen --force-rerun NOTE: ignoring `rust.debuginfo-level-tests=2` for codegen tests test result: ok. 790 passed; 0 failed; 75 ignored; 0 measured; 0 filtered out; finished in 3.21s --- src/bootstrap/src/core/build_steps/test.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 9e7ea5c115f1..38f36de8f05c 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1810,7 +1810,24 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the } let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] }; - flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests)); + flags.push(format!( + "-Cdebuginfo={}", + if suite == "codegen" { + // codegen tests typically check LLVM IR and are sensitive to additional debuginfo. + // So do not apply `rust.debuginfo-level-tests` for codegen tests. + if builder.config.rust_debuginfo_level_tests + != crate::core::config::DebuginfoLevel::None + { + println!( + "NOTE: ignoring `rust.debuginfo-level-tests={}` for codegen tests", + builder.config.rust_debuginfo_level_tests + ); + } + crate::core::config::DebuginfoLevel::None + } else { + builder.config.rust_debuginfo_level_tests + } + )); flags.extend(builder.config.cmd.compiletest_rustc_args().iter().map(|s| s.to_string())); if suite != "mir-opt" { From 63e1074c97b60d248f86321f021871f93ba10c31 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 9 Jul 2025 14:18:37 +0200 Subject: [PATCH 305/363] Update AMDGPU data layout --- compiler/rustc_codegen_llvm/src/context.rs | 5 +++++ compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 6a23becaa96f..34bed2a1d2a3 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -207,6 +207,11 @@ pub(crate) unsafe fn create_module<'ll>( // LLVM 21 updated the default layout on nvptx: https://github.com/llvm/llvm-project/pull/124961 target_data_layout = target_data_layout.replace("e-p6:32:32-i64", "e-i64"); } + if sess.target.arch == "amdgpu" { + // LLVM 21 adds the address width for address space 8. + // See https://github.com/llvm/llvm-project/pull/139419 + target_data_layout = target_data_layout.replace("p8:128:128:128:48", "p8:128:128") + } } // Ensure the data-layout values hardcoded remain the defaults. diff --git a/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs b/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs index f20782cabb87..0d6c6194e269 100644 --- a/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs +++ b/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs @@ -3,7 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, Target, TargetMetadata, pub(crate) fn target() -> Target { Target { arch: "amdgpu".into(), - data_layout: "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9".into(), + data_layout: "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9".into(), llvm_target: "amdgcn-amd-amdhsa".into(), metadata: TargetMetadata { description: Some("AMD GPU".into()), From 12b19be741ea07934d7478bd8e450dca8f85afe5 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 11 Jul 2025 10:11:03 +0200 Subject: [PATCH 306/363] Pass wasm exception model to TargetOptions This is no longer implied by -wasm-enable-eh. --- compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs | 2 ++ compiler/rustc_codegen_llvm/src/back/write.rs | 4 ++++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 5 ++++- tests/assembly/wasm_exceptions.rs | 1 - 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index dfde45955906..8e82013e94ad 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -39,6 +39,7 @@ impl OwnedTargetMachine { debug_info_compression: &CStr, use_emulated_tls: bool, args_cstr_buff: &[u8], + use_wasm_eh: bool, ) -> Result> { assert!(args_cstr_buff.len() > 0); assert!( @@ -72,6 +73,7 @@ impl OwnedTargetMachine { use_emulated_tls, args_cstr_buff.as_ptr() as *const c_char, args_cstr_buff.len(), + use_wasm_eh, ) }; diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 68279008c03d..6f8fba2a30dc 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -15,6 +15,7 @@ use rustc_codegen_ssa::back::write::{ BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn, }; +use rustc_codegen_ssa::base::wants_wasm_eh; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind}; use rustc_data_structures::profiling::SelfProfilerRef; @@ -285,6 +286,8 @@ pub(crate) fn target_machine_factory( let file_name_display_preference = sess.filename_display_preference(RemapPathScopeComponents::DEBUGINFO); + let use_wasm_eh = wants_wasm_eh(sess); + Arc::new(move |config: TargetMachineFactoryConfig| { let path_to_cstring_helper = |path: Option| -> CString { let path = path.unwrap_or_default(); @@ -321,6 +324,7 @@ pub(crate) fn target_machine_factory( &debuginfo_compression, use_emulated_tls, &args_cstr_buff, + use_wasm_eh, ) }) } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 0b1e632cbc42..80a0e5c5accc 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2425,6 +2425,7 @@ unsafe extern "C" { UseEmulatedTls: bool, ArgsCstrBuff: *const c_char, ArgsCstrBuffLen: usize, + UseWasmEH: bool, ) -> *mut TargetMachine; pub(crate) fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index cc33764e485a..e649978780e4 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -396,7 +396,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray, const char *SplitDwarfFile, const char *OutputObjFile, const char *DebugInfoCompression, bool UseEmulatedTls, - const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) { + const char *ArgsCstrBuff, size_t ArgsCstrBuffLen, bool UseWasmEH) { auto OptLevel = fromRust(RustOptLevel); auto RM = fromRust(RustReloc); @@ -462,6 +462,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.ThreadModel = ThreadModel::Single; } + if (UseWasmEH) + Options.ExceptionModel = ExceptionHandling::Wasm; + Options.EmitStackSizeSection = EmitStackSizeSection; if (ArgsCstrBuff != nullptr) { diff --git a/tests/assembly/wasm_exceptions.rs b/tests/assembly/wasm_exceptions.rs index f05ccfadc585..704e8026f3f4 100644 --- a/tests/assembly/wasm_exceptions.rs +++ b/tests/assembly/wasm_exceptions.rs @@ -2,7 +2,6 @@ //@ assembly-output: emit-asm //@ compile-flags: -C target-feature=+exception-handling //@ compile-flags: -C panic=unwind -//@ compile-flags: -C llvm-args=-wasm-enable-eh #![crate_type = "lib"] #![feature(core_intrinsics)] From a65563e9cd817e2cfd75291bb97529dfb14eb451 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 14 Jul 2025 10:29:05 +0200 Subject: [PATCH 307/363] Make emit-arity-indicator.rs a no_core test The presence of `@add-core-stubs` indicates that this was already intended. --- .../sanitizer/kcfi/emit-arity-indicator.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs b/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs index b3b623b509b4..f9966a234469 100644 --- a/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs +++ b/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs @@ -8,6 +8,14 @@ //@ min-llvm-version: 21.0.0 #![crate_type = "lib"] +#![feature(no_core)] +#![no_core] + +extern crate minicore; + +unsafe extern "C" { + safe fn add(x: i32, y: i32) -> i32; +} pub fn add_one(x: i32) -> i32 { // CHECK-LABEL: __cfi__{{.*}}7add_one{{.*}}: @@ -23,7 +31,7 @@ pub fn add_one(x: i32) -> i32 { // CHECK-NEXT: nop // CHECK-NEXT: nop // CHECK-NEXT: mov ecx, 2628068948 - x + 1 + add(x, 1) } pub fn add_two(x: i32, _y: i32) -> i32 { @@ -40,7 +48,7 @@ pub fn add_two(x: i32, _y: i32) -> i32 { // CHECK-NEXT: nop // CHECK-NEXT: nop // CHECK-NEXT: mov edx, 2505940310 - x + 2 + add(x, 2) } pub fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { @@ -57,5 +65,5 @@ pub fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { // CHECK-NEXT: nop // CHECK-NEXT: nop // CHECK-NEXT: mov edx, 653723426 - f(arg) + f(arg) + add(f(arg), f(arg)) } From 99507a3ce8c5fb5d29833ae6caac9d72febee670 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 18 Jul 2025 09:36:38 +0200 Subject: [PATCH 308/363] update comment --- compiler/rustc_next_trait_solver/src/solve/trait_goals.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 098dc9dbaf0c..650b85d99d2c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1219,10 +1219,8 @@ where // the type (even if after unification and processing nested goals // it does not hold) will disqualify the built-in auto impl. // - // This differs from the current stable behavior and fixes #84857. - // Due to breakage found via crater, we currently instead lint - // patterns which can be used to exploit this unsoundness on stable, - // see #93367 for more details. + // We've originally had a more permissive check here which resulted + // in unsoundness, see #84857. ty::Bool | ty::Char | ty::Int(_) From 9e4f777602cdac0458c57615f3019c92e4152d72 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Fri, 18 Jul 2025 00:46:56 +0200 Subject: [PATCH 309/363] bootstrap: Detect musl hosts Currently, all non-Android Linux hosts are assumed to be using glibc. This obviously isn't very portable and will currently result in downloading a stage0 toolchain for glibc even on musl hosts. There are multiple ways to detect musl somewhat reliably, but the easiest option is to check for the python SOABI config variable, which has values like "cpython-313-x86_64-linux-gnu" or "cpython-313-powerpc64-linux-musl". Signed-off-by: Jens Reidel --- src/bootstrap/bootstrap.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index d8c6be782477..40e08361a0f1 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -8,6 +8,7 @@ import re import shutil import subprocess import sys +import sysconfig import tarfile import tempfile @@ -333,7 +334,11 @@ def default_build_triple(verbose): if ostype == "Android": kernel = "linux-android" else: - kernel = "unknown-linux-gnu" + python_soabi = sysconfig.get_config_var("SOABI") + if python_soabi is not None and "musl" in python_soabi: + kernel = "unknown-linux-musl" + else: + kernel = "unknown-linux-gnu" elif kernel == "SunOS": kernel = "pc-solaris" # On Solaris, uname -m will return a machine classification instead From 652ba279ecc693d8b4310c40e645a62009f5b0ed Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 18 Jun 2025 12:51:47 +0000 Subject: [PATCH 310/363] Show the memory of uninit reads --- .../rustc_const_eval/src/const_eval/error.rs | 25 ++++-- .../src/const_eval/eval_queries.rs | 4 +- .../libc_pthread_cond_double_destroy.rs | 2 + .../libc_pthread_cond_double_destroy.stderr | 10 +-- .../libc_pthread_condattr_double_destroy.rs | 2 + ...ibc_pthread_condattr_double_destroy.stderr | 8 +- .../libc_pthread_mutex_double_destroy.rs | 2 + .../libc_pthread_mutex_double_destroy.stderr | 10 +-- .../libc_pthread_mutexattr_double_destroy.rs | 2 + ...bc_pthread_mutexattr_double_destroy.stderr | 8 +- .../libc_pthread_rwlock_double_destroy.rs | 2 + .../libc_pthread_rwlock_double_destroy.stderr | 11 +-- .../ptr_metadata_uninit_slice_data.rs | 5 +- .../ptr_metadata_uninit_slice_data.stderr | 8 +- .../ptr_metadata_uninit_slice_len.rs | 5 +- .../ptr_metadata_uninit_slice_len.stderr | 8 +- .../intrinsics/ptr_metadata_uninit_thin.rs | 3 + .../ptr_metadata_uninit_thin.stderr | 8 +- .../tests/fail/read_from_trivial_switch.rs | 3 + .../fail/read_from_trivial_switch.stderr | 8 +- .../miri/tests/fail/uninit/padding-enum.rs | 3 + .../tests/fail/uninit/padding-enum.stderr | 9 +-- .../miri/tests/fail/uninit/padding-pair.rs | 3 + .../tests/fail/uninit/padding-pair.stderr | 8 +- .../tests/fail/uninit/padding-wide-ptr.rs | 3 + .../tests/fail/uninit/padding-wide-ptr.stderr | 8 +- .../fail/uninit/transmute-pair-uninit.rs | 3 + .../fail/uninit/transmute-pair-uninit.stderr | 8 +- .../native-lib/fail/tracing/partial_init.rs | 2 +- .../fail/tracing/partial_init.stderr | 7 +- .../invalid-patterns.32bit.stderr | 8 ++ .../invalid-patterns.64bit.stderr | 8 ++ tests/ui/consts/const-compare-bytes-ub.stderr | 8 ++ .../const-err-enum-discriminant.32bit.stderr | 13 ++++ ... const-err-enum-discriminant.64bit.stderr} | 6 +- .../ui/consts/const-err-enum-discriminant.rs | 2 + ...inter-values-in-various-types.64bit.stderr | 12 ++- .../const-eval/ub-enum-overwrite.stderr | 4 + tests/ui/consts/const-eval/ub-enum.rs | 3 +- tests/ui/consts/const-eval/ub-enum.stderr | 34 +++++---- tests/ui/consts/const-eval/ub-nonnull.stderr | 4 + tests/ui/consts/const-eval/ub-ref-ptr.rs | 3 +- tests/ui/consts/const-eval/ub-ref-ptr.stderr | 46 ++++++----- tests/ui/consts/const-eval/ub-wide-ptr.rs | 7 +- tests/ui/consts/const-eval/ub-wide-ptr.stderr | 76 ++++++++++--------- .../const-eval/union-const-eval-field.rs | 1 + .../const-eval/union-const-eval-field.stderr | 10 ++- tests/ui/consts/const-eval/union-ice.stderr | 12 +++ .../consts/const-eval/union-ub.32bit.stderr | 4 + .../consts/const-eval/union-ub.64bit.stderr | 4 + .../intrinsic-raw_eq-const-bad.stderr | 4 + tests/ui/type/pattern_types/validity.stderr | 8 ++ 52 files changed, 302 insertions(+), 163 deletions(-) create mode 100644 tests/ui/consts/const-err-enum-discriminant.32bit.stderr rename tests/ui/consts/{const-err-enum-discriminant.stderr => const-err-enum-discriminant.64bit.stderr} (64%) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 3e880d020013..e00fb2c1eaf9 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -2,17 +2,17 @@ use std::mem; use rustc_errors::{Diag, DiagArgName, DiagArgValue, DiagMessage, IntoDiagArg}; use rustc_middle::mir::AssertKind; -use rustc_middle::mir::interpret::{AllocId, Provenance, ReportedErrorInfo}; +use rustc_middle::mir::interpret::{AllocId, Provenance, ReportedErrorInfo, UndefinedBehaviorInfo}; use rustc_middle::query::TyCtxtAt; +use rustc_middle::ty::ConstInt; use rustc_middle::ty::layout::LayoutError; -use rustc_middle::ty::{ConstInt, TyCtxt}; use rustc_span::{Span, Symbol}; use super::CompileTimeMachine; use crate::errors::{self, FrameNote, ReportErrorExt}; use crate::interpret::{ - CtfeProvenance, ErrorHandled, Frame, InterpErrorInfo, InterpErrorKind, MachineStopType, - Pointer, err_inval, err_machine_stop, + CtfeProvenance, ErrorHandled, Frame, InterpCx, InterpErrorInfo, InterpErrorKind, + MachineStopType, Pointer, err_inval, err_machine_stop, }; /// The CTFE machine has some custom error kinds. @@ -163,7 +163,7 @@ pub fn get_span_and_frames<'tcx>( /// You can use it to add a stacktrace of current execution according to /// `get_span_and_frames` or just give context on where the const eval error happened. pub(super) fn report<'tcx, C, F>( - tcx: TyCtxt<'tcx>, + ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>, error: InterpErrorKind<'tcx>, span: Span, get_span_and_frames: C, @@ -173,6 +173,7 @@ where C: FnOnce() -> (Span, Vec), F: FnOnce(&mut Diag<'_>, Span, Vec), { + let tcx = ecx.tcx.tcx; // Special handling for certain errors match error { // Don't emit a new diagnostic for these errors, they are already reported elsewhere or @@ -198,6 +199,20 @@ where InterpErrorKind::ResourceExhaustion(_) | InterpErrorKind::InvalidProgram(_) ); + if let InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes( + Some((alloc_id, _access)), + )) = error + { + let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id); + let info = ecx.get_alloc_info(alloc_id); + let raw_bytes = errors::RawBytesNote { + size: info.size.bytes(), + align: info.align.bytes(), + bytes, + }; + err.subdiagnostic(raw_bytes); + } + error.add_args(&mut err); mk(&mut err, span, frames); diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index ce72d59b8b0e..f584f6c948e5 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -411,7 +411,7 @@ fn report_eval_error<'tcx>( let instance = with_no_trimmed_paths!(cid.instance.to_string()); super::report( - *ecx.tcx, + ecx, error, DUMMY_SP, || super::get_span_and_frames(ecx.tcx, ecx.stack()), @@ -451,7 +451,7 @@ fn report_validation_error<'tcx>( errors::RawBytesNote { size: info.size.bytes(), align: info.align.bytes(), bytes }; crate::const_eval::report( - *ecx.tcx, + ecx, error, DUMMY_SP, || crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()), diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs index 8624e4d28fbe..5778765589de 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs @@ -1,4 +1,6 @@ //@ignore-target: windows # No pthreads on Windows +//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}" +//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]" /// Test that destroying a pthread_cond twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr index 3318ac7fca59..6156070cf955 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs:LL:CC | LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); @@ -9,12 +9,8 @@ LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs:LL:CC -Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: -ALLOC (stack variable, size: 48, align: 8) { - 0x00 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ - 0x10 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ - 0x20 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ -} +Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: +ALLOC DUMP note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs index a510ee77cfb2..911696604912 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs @@ -1,5 +1,7 @@ //@ignore-target: windows # No pthreads on Windows //@ignore-target: apple # Our macOS condattr don't have any fields so we do not notice this. +//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}" +//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]" /// Test that destroying a pthread_condattr twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr index 1971bbc72103..da64970ff2e2 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs:LL:CC | LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); @@ -9,10 +9,8 @@ LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs:LL:CC -Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: -ALLOC (stack variable, size: 4, align: 4) { - __ __ __ __ │ ░░░░ -} +Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: +ALLOC DUMP note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs index 71a802920329..f04fe8be6b38 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs @@ -1,4 +1,6 @@ //@ignore-target: windows # No pthreads on Windows +//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}" +//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]" /// Test that destroying a pthread_mutex twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr index 251f8036e383..05db823b252b 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs:LL:CC | LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); @@ -9,12 +9,8 @@ LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs:LL:CC -Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: -ALLOC (stack variable, size: 40, align: 8) { - 0x00 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ - 0x10 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ - 0x20 │ __ __ __ __ __ __ __ __ │ ░░░░░░░░ -} +Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: +ALLOC DUMP note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs index 28dacc9931a4..d9daf5259bba 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs @@ -1,4 +1,6 @@ //@ignore-target: windows # No pthreads on Windows +//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}" +//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]" /// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr index b341efb7770c..ee3883de36ba 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs:LL:CC | LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); @@ -9,10 +9,8 @@ LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs:LL:CC -Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: -ALLOC (stack variable, size: 4, align: 4) { - __ __ __ __ │ ░░░░ -} +Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: +ALLOC DUMP note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs index a46a124bf2ec..720ba71d2383 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs @@ -1,4 +1,6 @@ //@ignore-target: windows # No pthreads on Windows +//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}" +//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]" /// Test that destroying a pthread_rwlock twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr index 8f388577a27d..430398dc8fd7 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs:LL:CC | LL | libc::pthread_rwlock_destroy(&mut lock); @@ -9,13 +9,8 @@ LL | libc::pthread_rwlock_destroy(&mut lock); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs:LL:CC -Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: -ALLOC (stack variable, size: 56, align: 8) { - 0x00 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ - 0x10 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ - 0x20 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ - 0x30 │ __ __ __ __ __ __ __ __ │ ░░░░░░░░ -} +Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: +ALLOC DUMP note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs index 16f07c7ee994..c03e468cfbaa 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs @@ -1,4 +1,7 @@ //@compile-flags: -Zmiri-disable-validation +//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}" +//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]" + #![feature(core_intrinsics, custom_mir)] use std::intrinsics::mir::*; @@ -9,7 +12,7 @@ use std::intrinsics::mir::*; pub unsafe fn deref_meta(p: *const *const [i32]) -> usize { mir! { { - RET = PtrMetadata(*p); //~ ERROR: /Undefined Behavior: .*, but memory is uninitialized/ + RET = PtrMetadata(*p); //~ ERROR: /Undefined Behavior: .* but memory is uninitialized/ Return() } } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr index 9bacd80f7d52..1e7f500edb2d 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory --> tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs:LL:CC | LL | RET = PtrMetadata(*p); @@ -14,10 +14,8 @@ note: inside `main` LL | let _meta = deref_meta(p.as_ptr().cast()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Uninitialized memory occurred at ALLOC[0x0..0x8], in this allocation: -ALLOC (stack variable, size: 16, align: 8) { - __ __ __ __ __ __ __ __ 04 00 00 00 00 00 00 00 │ ░░░░░░░░........ -} +Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: +ALLOC DUMP note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs index 38db894537b7..7053c0f6e187 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs @@ -1,4 +1,7 @@ //@compile-flags: -Zmiri-disable-validation +//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}" +//@ normalize-stderr-test: "\[0x[0-9a-z]+..0x[0-9a-z]+\]" -> "[0xX..0xY]" + #![feature(core_intrinsics, custom_mir)] use std::intrinsics::mir::*; @@ -9,7 +12,7 @@ use std::intrinsics::mir::*; pub unsafe fn deref_meta(p: *const *const [i32]) -> usize { mir! { { - RET = PtrMetadata(*p); //~ ERROR: /Undefined Behavior: .*, but memory is uninitialized/ + RET = PtrMetadata(*p); //~ ERROR: /Undefined Behavior: .* but memory is uninitialized/ Return() } } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr index 621325d72ff7..80b4c8bec0d7 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr @@ -12,7 +12,7 @@ LL | (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32; = note: BACKTRACE: = note: inside `main` at tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC -error: Undefined Behavior: reading memory at ALLOC[0x8..0x10], but memory is uninitialized at [0x8..0x10], and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory --> tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC | LL | RET = PtrMetadata(*p); @@ -28,10 +28,8 @@ note: inside `main` LL | let _meta = deref_meta(p.as_ptr().cast()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Uninitialized memory occurred at ALLOC[0x8..0x10], in this allocation: -ALLOC (stack variable, size: 16, align: 8) { - ╾────0x4[wildcard]────╼ __ __ __ __ __ __ __ __ │ ╾──────╼░░░░░░░░ -} +Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: +ALLOC DUMP note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs index 179fd33ed7c4..3ba298473374 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs @@ -1,4 +1,7 @@ //@compile-flags: -Zmiri-disable-validation +//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}" +//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]" + #![feature(core_intrinsics, custom_mir)] use std::intrinsics::mir::*; diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr index b0e452420570..7a1f3d6ea84f 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory --> tests/fail/intrinsics/ptr_metadata_uninit_thin.rs:LL:CC | LL | RET = PtrMetadata(*p); @@ -14,10 +14,8 @@ note: inside `main` LL | let _meta = deref_meta(p.as_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^ -Uninitialized memory occurred at ALLOC[0x0..0x8], in this allocation: -ALLOC (stack variable, size: 8, align: 8) { - __ __ __ __ __ __ __ __ │ ░░░░░░░░ -} +Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: +ALLOC DUMP note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/read_from_trivial_switch.rs b/src/tools/miri/tests/fail/read_from_trivial_switch.rs index 35117c80b738..2696c42aeae2 100644 --- a/src/tools/miri/tests/fail/read_from_trivial_switch.rs +++ b/src/tools/miri/tests/fail/read_from_trivial_switch.rs @@ -4,6 +4,9 @@ // // See . +//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}" +//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]" + use std::mem::MaybeUninit; fn main() { diff --git a/src/tools/miri/tests/fail/read_from_trivial_switch.stderr b/src/tools/miri/tests/fail/read_from_trivial_switch.stderr index 1d0c76c3c087..1dcc341b7e67 100644 --- a/src/tools/miri/tests/fail/read_from_trivial_switch.stderr +++ b/src/tools/miri/tests/fail/read_from_trivial_switch.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory --> tests/fail/read_from_trivial_switch.rs:LL:CC | LL | let &(0 | _) = bad_ref; @@ -9,10 +9,8 @@ LL | let &(0 | _) = bad_ref; = note: BACKTRACE: = note: inside `main` at tests/fail/read_from_trivial_switch.rs:LL:CC -Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: -ALLOC (stack variable, size: 4, align: 4) { - __ __ __ __ │ ░░░░ -} +Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: +ALLOC DUMP note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/uninit/padding-enum.rs b/src/tools/miri/tests/fail/uninit/padding-enum.rs index e1a16bea23cc..606fa21016fd 100644 --- a/src/tools/miri/tests/fail/uninit/padding-enum.rs +++ b/src/tools/miri/tests/fail/uninit/padding-enum.rs @@ -1,3 +1,6 @@ +//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}" +//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]" + use std::mem; // We have three fields to avoid the ScalarPair optimization. diff --git a/src/tools/miri/tests/fail/uninit/padding-enum.stderr b/src/tools/miri/tests/fail/uninit/padding-enum.stderr index ee3867fc60ba..64229ac88172 100644 --- a/src/tools/miri/tests/fail/uninit/padding-enum.stderr +++ b/src/tools/miri/tests/fail/uninit/padding-enum.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reading memory at ALLOC[0x8..0x9], but memory is uninitialized at [0x8..0x9], and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory --> tests/fail/uninit/padding-enum.rs:LL:CC | LL | let _val = *c.add(padding_offset); @@ -9,11 +9,8 @@ LL | let _val = *c.add(padding_offset); = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/padding-enum.rs:LL:CC -Uninitialized memory occurred at ALLOC[0x8..0x9], in this allocation: -ALLOC (stack variable, size: 24, align: 8) { - 0x00 │ 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░ - 0x10 │ __ __ __ __ __ __ __ __ │ ░░░░░░░░ -} +Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: +ALLOC DUMP note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/uninit/padding-pair.rs b/src/tools/miri/tests/fail/uninit/padding-pair.rs index c8c00b3c65a0..70ae48ff77d9 100644 --- a/src/tools/miri/tests/fail/uninit/padding-pair.rs +++ b/src/tools/miri/tests/fail/uninit/padding-pair.rs @@ -1,3 +1,6 @@ +//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}" +//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]" + #![feature(core_intrinsics)] use std::mem::{self, MaybeUninit}; diff --git a/src/tools/miri/tests/fail/uninit/padding-pair.stderr b/src/tools/miri/tests/fail/uninit/padding-pair.stderr index a9841815de39..2e7a577f204a 100644 --- a/src/tools/miri/tests/fail/uninit/padding-pair.stderr +++ b/src/tools/miri/tests/fail/uninit/padding-pair.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reading memory at ALLOC[0x9..0xa], but memory is uninitialized at [0x9..0xa], and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory --> tests/fail/uninit/padding-pair.rs:LL:CC | LL | let v = unsafe { *z.offset(first_undef) }; @@ -9,10 +9,8 @@ LL | let v = unsafe { *z.offset(first_undef) }; = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/padding-pair.rs:LL:CC -Uninitialized memory occurred at ALLOC[0x9..0xa], in this allocation: -ALLOC (stack variable, size: 16, align: 8) { - 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░ -} +Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: +ALLOC DUMP note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.rs b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.rs index 4e363dbf81e0..549785e0223b 100644 --- a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.rs +++ b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.rs @@ -1,3 +1,6 @@ +//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}" +//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]" + use std::mem; // If this is `None`, the metadata becomes padding. diff --git a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr index f6446a5a95b5..ce11320ca1bf 100644 --- a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr +++ b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reading memory at ALLOC[0x8..0x9], but memory is uninitialized at [0x8..0x9], and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory --> tests/fail/uninit/padding-wide-ptr.rs:LL:CC | LL | let _val = *c.add(mem::size_of::<*const u8>()); @@ -9,10 +9,8 @@ LL | let _val = *c.add(mem::size_of::<*const u8>()); = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/padding-wide-ptr.rs:LL:CC -Uninitialized memory occurred at ALLOC[0x8..0x9], in this allocation: -ALLOC (stack variable, size: 16, align: 8) { - 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░ -} +Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: +ALLOC DUMP note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.rs b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.rs index 0ba5520a5446..c1d284c7057c 100644 --- a/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.rs +++ b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.rs @@ -1,3 +1,6 @@ +//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}" +//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]" + #![feature(core_intrinsics)] use std::mem::{self, MaybeUninit}; diff --git a/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr index 385d877e2ee2..eb049dd41ec2 100644 --- a/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr +++ b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reading memory at ALLOC[0x9..0xa], but memory is uninitialized at [0x9..0xa], and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory --> tests/fail/uninit/transmute-pair-uninit.rs:LL:CC | LL | let v = unsafe { *z.offset(first_undef) }; @@ -9,10 +9,8 @@ LL | let v = unsafe { *z.offset(first_undef) }; = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/transmute-pair-uninit.rs:LL:CC -Uninitialized memory occurred at ALLOC[0x9..0xa], in this allocation: -ALLOC (stack variable, size: 16, align: 8) { - 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░ -} +Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: +ALLOC DUMP note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.rs b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.rs index e267f82e215b..7ab160773ff3 100644 --- a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.rs +++ b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.rs @@ -20,6 +20,6 @@ fn partial_init() { assert!(*slice_ptr == 0); assert!(*slice_ptr.offset(1) == 0); // Reading the third is UB! - let _val = *slice_ptr.offset(2); //~ ERROR: Undefined Behavior: using uninitialized data + let _val = *slice_ptr.offset(2); //~ ERROR: /Undefined Behavior: reading memory.*, but memory is uninitialized/ } } diff --git a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr index 84fd913b5e5b..74a599ede5c3 100644 --- a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr +++ b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr @@ -17,7 +17,7 @@ note: inside `main` LL | partial_init(); | ^^^^^^^^^^^^^^ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x2..0x3], but memory is uninitialized at [0x2..0x3], and this operation requires initialized memory --> tests/native-lib/fail/tracing/partial_init.rs:LL:CC | LL | let _val = *slice_ptr.offset(2); @@ -33,6 +33,11 @@ note: inside `main` LL | partial_init(); | ^^^^^^^^^^^^^^ +Uninitialized memory occurred at ALLOC[0x2..0x3], in this allocation: +ALLOC (stack variable, size: 3, align: 1) { + ╾00[wildcard] (1 ptr byte)╼ ╾00[wildcard] (1 ptr byte)╼ __ │ ━━░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr index 107179516bc3..0c57eddbe937 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr @@ -3,6 +3,10 @@ error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at | LL | get_flag::(); | ^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#7}` failed here + | + = note: the raw bytes of the constant (size: 4, align: 4) { + ff __ __ __ │ .░░░ + } error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean --> $DIR/invalid-patterns.rs:42:14 @@ -31,6 +35,10 @@ error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); | ^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#11}` failed here + | + = note: the raw bytes of the constant (size: 4, align: 4) { + ff __ __ __ │ .░░░ + } error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:31:21 diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr index 107179516bc3..0c57eddbe937 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr @@ -3,6 +3,10 @@ error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at | LL | get_flag::(); | ^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#7}` failed here + | + = note: the raw bytes of the constant (size: 4, align: 4) { + ff __ __ __ │ .░░░ + } error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean --> $DIR/invalid-patterns.rs:42:14 @@ -31,6 +35,10 @@ error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); | ^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#11}` failed here + | + = note: the raw bytes of the constant (size: 4, align: 4) { + ff __ __ __ │ .░░░ + } error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:31:21 diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr index c1706a8c4b0a..770a55cc7267 100644 --- a/tests/ui/consts/const-compare-bytes-ub.stderr +++ b/tests/ui/consts/const-compare-bytes-ub.stderr @@ -33,12 +33,20 @@ error[E0080]: reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at | LL | compare_bytes(MaybeUninit::uninit().as_ptr(), [1].as_ptr(), 1) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::LHS_UNINIT` failed here + | + = note: the raw bytes of the constant (size: 1, align: 1) { + __ │ ░ + } error[E0080]: reading memory at ALLOC3[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/const-compare-bytes-ub.rs:33:9 | LL | compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::RHS_UNINIT` failed here + | + = note: the raw bytes of the constant (size: 1, align: 1) { + __ │ ░ + } error[E0080]: unable to turn pointer into integer --> $DIR/const-compare-bytes-ub.rs:37:9 diff --git a/tests/ui/consts/const-err-enum-discriminant.32bit.stderr b/tests/ui/consts/const-err-enum-discriminant.32bit.stderr new file mode 100644 index 000000000000..cc786108f648 --- /dev/null +++ b/tests/ui/consts/const-err-enum-discriminant.32bit.stderr @@ -0,0 +1,13 @@ +error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory + --> $DIR/const-err-enum-discriminant.rs:10:21 + | +LL | Boo = [unsafe { Foo { b: () }.a }; 4][3], + | ^^^^^^^^^^^^^^^ evaluation of `Bar::Boo::{constant#0}` failed here + | + = note: the raw bytes of the constant (size: 4, align: 4) { + __ __ __ __ │ ░░░░ + } + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-err-enum-discriminant.stderr b/tests/ui/consts/const-err-enum-discriminant.64bit.stderr similarity index 64% rename from tests/ui/consts/const-err-enum-discriminant.stderr rename to tests/ui/consts/const-err-enum-discriminant.64bit.stderr index f935d1054de6..1d32851aac17 100644 --- a/tests/ui/consts/const-err-enum-discriminant.stderr +++ b/tests/ui/consts/const-err-enum-discriminant.64bit.stderr @@ -1,8 +1,12 @@ error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory - --> $DIR/const-err-enum-discriminant.rs:8:21 + --> $DIR/const-err-enum-discriminant.rs:10:21 | LL | Boo = [unsafe { Foo { b: () }.a }; 4][3], | ^^^^^^^^^^^^^^^ evaluation of `Bar::Boo::{constant#0}` failed here + | + = note: the raw bytes of the constant (size: 8, align: 8) { + __ __ __ __ __ __ __ __ │ ░░░░░░░░ + } error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-err-enum-discriminant.rs b/tests/ui/consts/const-err-enum-discriminant.rs index 190ef47f4362..556746005843 100644 --- a/tests/ui/consts/const-err-enum-discriminant.rs +++ b/tests/ui/consts/const-err-enum-discriminant.rs @@ -1,3 +1,5 @@ +//@ stderr-per-bitwidth + #[derive(Copy, Clone)] union Foo { a: isize, diff --git a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr index 65e846b5741e..60f6ef0f64b1 100644 --- a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr +++ b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr @@ -43,11 +43,15 @@ LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uin = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: reading memory at ALLOC0[0x0..0x10], but memory is uninitialized at [0x8..0x10], and this operation requires initialized memory +error[E0080]: reading memory at ALLOC2[0x0..0x10], but memory is uninitialized at [0x8..0x10], and this operation requires initialized memory --> $DIR/const-pointer-values-in-various-types.rs:42:47 | LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_U128_UNION` failed here + | + = note: the raw bytes of the constant (size: 16, align: 16) { + ╾ALLOC0╼ __ __ __ __ __ __ __ __ │ ╾──────╼░░░░░░░░ + } error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:45:43 @@ -85,11 +89,15 @@ LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: reading memory at ALLOC1[0x0..0x10], but memory is uninitialized at [0x8..0x10], and this operation requires initialized memory +error[E0080]: reading memory at ALLOC3[0x0..0x10], but memory is uninitialized at [0x8..0x10], and this operation requires initialized memory --> $DIR/const-pointer-values-in-various-types.rs:57:47 | LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_I128_UNION` failed here + | + = note: the raw bytes of the constant (size: 16, align: 16) { + ╾ALLOC1╼ __ __ __ __ __ __ __ __ │ ╾──────╼░░░░░░░░ + } error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:60:45 diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr index 14f369eace47..2fd01b67c492 100644 --- a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr +++ b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr @@ -3,6 +3,10 @@ error[E0080]: reading memory at ALLOC0[0x1..0x2], but memory is uninitialized at | LL | unsafe { *p } | ^^ evaluation of `_` failed here + | + = note: the raw bytes of the constant (size: 2, align: 1) { + 01 __ │ .░ + } error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/ub-enum.rs b/tests/ui/consts/const-eval/ub-enum.rs index 52fc99450683..9c78bb6efed7 100644 --- a/tests/ui/consts/const-eval/ub-enum.rs +++ b/tests/ui/consts/const-eval/ub-enum.rs @@ -1,7 +1,8 @@ // Strip out raw byte dumps to make comparison platform-independent: //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -//@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" +//@ normalize-stderr: "([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" //@ normalize-stderr: "0x0+" -> "0x0" +//@ normalize-stderr: "0x[0-9](\.\.|\])" -> "0x%$1" //@ dont-require-annotations: NOTE #![feature(never_type)] diff --git a/tests/ui/consts/const-eval/ub-enum.stderr b/tests/ui/consts/const-eval/ub-enum.stderr index 6665830e2502..5cbd6176c92d 100644 --- a/tests/ui/consts/const-eval/ub-enum.stderr +++ b/tests/ui/consts/const-eval/ub-enum.stderr @@ -1,5 +1,5 @@ error[E0080]: constructing invalid value at .: encountered 0x01, but expected a valid enum tag - --> $DIR/ub-enum.rs:29:1 + --> $DIR/ub-enum.rs:30:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -10,7 +10,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; } error[E0080]: unable to turn pointer into integer - --> $DIR/ub-enum.rs:32:1 + --> $DIR/ub-enum.rs:33:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM_PTR` failed here @@ -19,7 +19,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: unable to turn pointer into integer - --> $DIR/ub-enum.rs:35:1 + --> $DIR/ub-enum.rs:36:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM_WRAPPED` failed here @@ -28,7 +28,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: constructing invalid value at .: encountered 0x0, but expected a valid enum tag - --> $DIR/ub-enum.rs:47:1 + --> $DIR/ub-enum.rs:48:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -39,7 +39,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; } error[E0080]: unable to turn pointer into integer - --> $DIR/ub-enum.rs:49:1 + --> $DIR/ub-enum.rs:50:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM2_PTR` failed here @@ -48,7 +48,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: unable to turn pointer into integer - --> $DIR/ub-enum.rs:52:1 + --> $DIR/ub-enum.rs:53:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM2_WRAPPED` failed here @@ -56,14 +56,18 @@ LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory - --> $DIR/ub-enum.rs:61:41 +error[E0080]: reading memory at ALLOC0[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory + --> $DIR/ub-enum.rs:62:41 | LL | const BAD_ENUM2_UNDEF: Enum2 = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM2_UNDEF` failed here + | + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } error[E0080]: unable to turn pointer into integer - --> $DIR/ub-enum.rs:65:1 + --> $DIR/ub-enum.rs:66:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM2_OPTION_PTR` failed here @@ -72,7 +76,7 @@ LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant - --> $DIR/ub-enum.rs:82:1 + --> $DIR/ub-enum.rs:83:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -83,7 +87,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant - --> $DIR/ub-enum.rs:84:1 + --> $DIR/ub-enum.rs:85:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -94,7 +98,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) - --> $DIR/ub-enum.rs:92:1 + --> $DIR/ub-enum.rs:93:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -105,19 +109,19 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran } error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant - --> $DIR/ub-enum.rs:97:77 + --> $DIR/ub-enum.rs:98:77 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; | ^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_UNINHABITED_WITH_DATA1` failed here error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant - --> $DIR/ub-enum.rs:99:77 + --> $DIR/ub-enum.rs:100:77 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; | ^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_UNINHABITED_WITH_DATA2` failed here error[E0080]: read discriminant of an uninhabited enum variant - --> $DIR/ub-enum.rs:105:9 + --> $DIR/ub-enum.rs:106:9 | LL | std::mem::discriminant(&*(&() as *const () as *const Never)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `TEST_ICE_89765` failed inside this call diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index c92797f330af..19ae66cf3c63 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -42,6 +42,10 @@ error[E0080]: reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at | LL | const UNINIT: NonZero = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT` failed here + | + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + __ │ ░ + } error[E0080]: constructing invalid value: encountered 42, but expected something in the range 10..=30 --> $DIR/ub-nonnull.rs:44:1 diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.rs b/tests/ui/consts/const-eval/ub-ref-ptr.rs index 64b48939be6d..d8e5102fcbe7 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.rs +++ b/tests/ui/consts/const-eval/ub-ref-ptr.rs @@ -1,8 +1,9 @@ // ignore-tidy-linelength // Strip out raw byte dumps to make comparison platform-independent: //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -//@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" +//@ normalize-stderr: "([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" //@ dont-require-annotations: NOTE +//@ normalize-stderr: "0x[0-9](\.\.|\])" -> "0x%$1" #![allow(invalid_value)] diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index beb54e435341..451ebb6eba1a 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -1,5 +1,5 @@ error[E0080]: constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) - --> $DIR/ub-ref-ptr.rs:17:1 + --> $DIR/ub-ref-ptr.rs:18:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -10,7 +10,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) - --> $DIR/ub-ref-ptr.rs:20:1 + --> $DIR/ub-ref-ptr.rs:21:1 | LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -21,7 +21,7 @@ LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: constructing invalid value: encountered a null reference - --> $DIR/ub-ref-ptr.rs:23:1 + --> $DIR/ub-ref-ptr.rs:24:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -32,7 +32,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; } error[E0080]: constructing invalid value: encountered a null box - --> $DIR/ub-ref-ptr.rs:26:1 + --> $DIR/ub-ref-ptr.rs:27:1 | LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -43,7 +43,7 @@ LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; } error[E0080]: unable to turn pointer into integer - --> $DIR/ub-ref-ptr.rs:33:1 + --> $DIR/ub-ref-ptr.rs:34:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE` failed here @@ -52,7 +52,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: unable to turn pointer into integer - --> $DIR/ub-ref-ptr.rs:36:39 + --> $DIR/ub-ref-ptr.rs:37:39 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE_SLICE` failed here @@ -61,13 +61,13 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported note: erroneous constant encountered - --> $DIR/ub-ref-ptr.rs:36:38 + --> $DIR/ub-ref-ptr.rs:37:38 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: unable to turn pointer into integer - --> $DIR/ub-ref-ptr.rs:39:86 + --> $DIR/ub-ref-ptr.rs:40:86 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; | ^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE_BOX_SLICE` failed here @@ -76,13 +76,13 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported note: erroneous constant encountered - --> $DIR/ub-ref-ptr.rs:39:85 + --> $DIR/ub-ref-ptr.rs:40:85 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; | ^^^^^^^^^^^^^^^^^^^^^ error[E0080]: constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) - --> $DIR/ub-ref-ptr.rs:42:1 + --> $DIR/ub-ref-ptr.rs:43:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -93,7 +93,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; } error[E0080]: constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) - --> $DIR/ub-ref-ptr.rs:45:1 + --> $DIR/ub-ref-ptr.rs:46:1 | LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -103,14 +103,18 @@ LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; HEX_DUMP } -error[E0080]: reading memory at ALLOC3[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory - --> $DIR/ub-ref-ptr.rs:48:41 +error[E0080]: reading memory at ALLOC3[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory + --> $DIR/ub-ref-ptr.rs:49:41 | LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_PTR` failed here + | + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } error[E0080]: constructing invalid value: encountered null pointer, but expected a function pointer - --> $DIR/ub-ref-ptr.rs:51:1 + --> $DIR/ub-ref-ptr.rs:52:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -120,14 +124,18 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; HEX_DUMP } -error[E0080]: reading memory at ALLOC4[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory - --> $DIR/ub-ref-ptr.rs:53:38 +error[E0080]: reading memory at ALLOC4[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory + --> $DIR/ub-ref-ptr.rs:54:38 | LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_FN_PTR` failed here + | + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected a function pointer - --> $DIR/ub-ref-ptr.rs:55:1 + --> $DIR/ub-ref-ptr.rs:56:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -138,7 +146,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; } error[E0080]: constructing invalid value: encountered ALLOC2, but expected a function pointer - --> $DIR/ub-ref-ptr.rs:57:1 + --> $DIR/ub-ref-ptr.rs:58:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -149,7 +157,7 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; } error[E0080]: accessing memory based on pointer with alignment 1, but alignment 4 is required - --> $DIR/ub-ref-ptr.rs:64:5 + --> $DIR/ub-ref-ptr.rs:65:5 | LL | ptr.read(); | ^^^^^^^^^^ evaluation of `UNALIGNED_READ` failed here diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.rs b/tests/ui/consts/const-eval/ub-wide-ptr.rs index 86235897e7e8..0bbb104c0322 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.rs +++ b/tests/ui/consts/const-eval/ub-wide-ptr.rs @@ -6,9 +6,10 @@ use std::{ptr, mem}; // Strip out raw byte dumps to make comparison platform-independent: //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -//@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" +//@ normalize-stderr: "([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" //@ normalize-stderr: "offset \d+" -> "offset N" //@ normalize-stderr: "size \d+" -> "size N" +//@ normalize-stderr: "0x[0-9](\.\.|\])" -> "0x%$1" //@ dont-require-annotations: NOTE /// A newtype wrapper to prevent MIR generation from inserting reborrows that would affect the error @@ -61,7 +62,7 @@ const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: const SLICE_VALID: &[u8] = unsafe { mem::transmute((&42u8, 1usize)) }; // bad slice: length uninit const SLICE_LENGTH_UNINIT: &[u8] = unsafe { -//~^ ERROR uninitialized + //~^ ERROR uninitialized let uninit_len = MaybeUninit:: { uninit: () }; mem::transmute((42, uninit_len)) }; @@ -99,7 +100,7 @@ const RAW_SLICE_VALID: *const [u8] = unsafe { mem::transmute((&42u8, 1usize)) }; const RAW_SLICE_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, 999usize)) }; // ok because raw const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, usize::MAX)) }; // ok because raw const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { -//~^ ERROR uninitialized + //~^ ERROR uninitialized let uninit_len = MaybeUninit:: { uninit: () }; mem::transmute((42, uninit_len)) }; diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index a3eb5c720319..ab15ba826a5f 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -1,5 +1,5 @@ error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) - --> $DIR/ub-wide-ptr.rs:39:1 + --> $DIR/ub-wide-ptr.rs:40:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -10,7 +10,7 @@ LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object - --> $DIR/ub-wide-ptr.rs:41:1 + --> $DIR/ub-wide-ptr.rs:42:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -21,7 +21,7 @@ LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, us } error[E0080]: unable to turn pointer into integer - --> $DIR/ub-wide-ptr.rs:44:1 + --> $DIR/ub-wide-ptr.rs:45:1 | LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `STR_LENGTH_PTR` failed here @@ -30,7 +30,7 @@ LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: unable to turn pointer into integer - --> $DIR/ub-wide-ptr.rs:47:1 + --> $DIR/ub-wide-ptr.rs:48:1 | LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `MY_STR_LENGTH_PTR` failed here @@ -39,7 +39,7 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object - --> $DIR/ub-wide-ptr.rs:49:1 + --> $DIR/ub-wide-ptr.rs:50:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -50,7 +50,7 @@ LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize: } error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected a string - --> $DIR/ub-wide-ptr.rs:53:1 + --> $DIR/ub-wide-ptr.rs:54:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -61,7 +61,7 @@ LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit: } error[E0080]: constructing invalid value at ..0: encountered uninitialized memory, but expected a string - --> $DIR/ub-wide-ptr.rs:56:1 + --> $DIR/ub-wide-ptr.rs:57:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -71,14 +71,18 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni HEX_DUMP } -error[E0080]: reading memory at ALLOC32[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory - --> $DIR/ub-wide-ptr.rs:63:1 +error[E0080]: reading memory at ALLOC32[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory + --> $DIR/ub-wide-ptr.rs:64:1 | LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SLICE_LENGTH_UNINIT` failed here + | + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) - --> $DIR/ub-wide-ptr.rs:69:1 + --> $DIR/ub-wide-ptr.rs:70:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -89,7 +93,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object - --> $DIR/ub-wide-ptr.rs:72:1 + --> $DIR/ub-wide-ptr.rs:73:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -100,7 +104,7 @@ LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, is } error[E0080]: unable to turn pointer into integer - --> $DIR/ub-wide-ptr.rs:75:1 + --> $DIR/ub-wide-ptr.rs:76:1 | LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SLICE_LENGTH_PTR` failed here @@ -109,7 +113,7 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) - --> $DIR/ub-wide-ptr.rs:78:1 + --> $DIR/ub-wide-ptr.rs:79:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -120,7 +124,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us } error[E0080]: unable to turn pointer into integer - --> $DIR/ub-wide-ptr.rs:81:1 + --> $DIR/ub-wide-ptr.rs:82:1 | LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SLICE_LENGTH_PTR_BOX` failed here @@ -129,7 +133,7 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3) = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: constructing invalid value at .[0]: encountered 0x03, but expected a boolean - --> $DIR/ub-wide-ptr.rs:85:1 + --> $DIR/ub-wide-ptr.rs:86:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -140,13 +144,13 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; } note: erroneous constant encountered - --> $DIR/ub-wide-ptr.rs:85:40 + --> $DIR/ub-wide-ptr.rs:86:40 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: constructing invalid value at ..0: encountered 0x03, but expected a boolean - --> $DIR/ub-wide-ptr.rs:91:1 + --> $DIR/ub-wide-ptr.rs:92:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -157,13 +161,13 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3 } note: erroneous constant encountered - --> $DIR/ub-wide-ptr.rs:91:42 + --> $DIR/ub-wide-ptr.rs:92:42 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean - --> $DIR/ub-wide-ptr.rs:94:1 + --> $DIR/ub-wide-ptr.rs:95:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -174,19 +178,23 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran } note: erroneous constant encountered - --> $DIR/ub-wide-ptr.rs:94:42 + --> $DIR/ub-wide-ptr.rs:95:42 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: reading memory at ALLOC33[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory - --> $DIR/ub-wide-ptr.rs:101:1 +error[E0080]: reading memory at ALLOC33[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory + --> $DIR/ub-wide-ptr.rs:102:1 | LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_SLICE_LENGTH_UNINIT` failed here + | + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } error[E0080]: constructing invalid value at .0: encountered ALLOC12, but expected a vtable pointer - --> $DIR/ub-wide-ptr.rs:109:1 + --> $DIR/ub-wide-ptr.rs:110:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -197,7 +205,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: constructing invalid value at .0: encountered ALLOC14, but expected a vtable pointer - --> $DIR/ub-wide-ptr.rs:112:1 + --> $DIR/ub-wide-ptr.rs:113:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -208,7 +216,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer - --> $DIR/ub-wide-ptr.rs:115:1 + --> $DIR/ub-wide-ptr.rs:116:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -219,7 +227,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u } error[E0080]: constructing invalid value: encountered ALLOC17, but expected a vtable pointer - --> $DIR/ub-wide-ptr.rs:117:1 + --> $DIR/ub-wide-ptr.rs:118:1 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -230,7 +238,7 @@ LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92 } error[E0080]: constructing invalid value: encountered ALLOC19, but expected a vtable pointer - --> $DIR/ub-wide-ptr.rs:119:1 + --> $DIR/ub-wide-ptr.rs:120:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -241,7 +249,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92 } error[E0080]: constructing invalid value: encountered ALLOC21, but expected a vtable pointer - --> $DIR/ub-wide-ptr.rs:121:1 + --> $DIR/ub-wide-ptr.rs:122:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -252,7 +260,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u } error[E0080]: constructing invalid value at .0: encountered ALLOC23, but expected a vtable pointer - --> $DIR/ub-wide-ptr.rs:123:1 + --> $DIR/ub-wide-ptr.rs:124:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -263,7 +271,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: constructing invalid value at ..: encountered 0x03, but expected a boolean - --> $DIR/ub-wide-ptr.rs:127:1 + --> $DIR/ub-wide-ptr.rs:128:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -274,7 +282,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, } error[E0080]: constructing invalid value: encountered null pointer, but expected a vtable pointer - --> $DIR/ub-wide-ptr.rs:131:1 + --> $DIR/ub-wide-ptr.rs:132:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -285,7 +293,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute } error[E0080]: constructing invalid value: encountered ALLOC28, but expected a vtable pointer - --> $DIR/ub-wide-ptr.rs:133:1 + --> $DIR/ub-wide-ptr.rs:134:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -296,7 +304,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm } error[E0080]: constructing invalid value: encountered null pointer, but expected a vtable pointer - --> $DIR/ub-wide-ptr.rs:140:1 + --> $DIR/ub-wide-ptr.rs:141:1 | LL | static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -307,7 +315,7 @@ LL | static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe } error[E0080]: constructing invalid value: encountered ALLOC31, but expected a vtable pointer - --> $DIR/ub-wide-ptr.rs:144:1 + --> $DIR/ub-wide-ptr.rs:145:1 | LL | static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value diff --git a/tests/ui/consts/const-eval/union-const-eval-field.rs b/tests/ui/consts/const-eval/union-const-eval-field.rs index 0ad94eee7f45..719e59b007c0 100644 --- a/tests/ui/consts/const-eval/union-const-eval-field.rs +++ b/tests/ui/consts/const-eval/union-const-eval-field.rs @@ -1,4 +1,5 @@ //@ dont-require-annotations: NOTE +//@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" type Field1 = i32; type Field2 = f32; diff --git a/tests/ui/consts/const-eval/union-const-eval-field.stderr b/tests/ui/consts/const-eval/union-const-eval-field.stderr index deddf9e0b6d3..1843ce273ac0 100644 --- a/tests/ui/consts/const-eval/union-const-eval-field.stderr +++ b/tests/ui/consts/const-eval/union-const-eval-field.stderr @@ -1,17 +1,21 @@ error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory - --> $DIR/union-const-eval-field.rs:28:37 + --> $DIR/union-const-eval-field.rs:29:37 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; | ^^^^^^^^^^^^ evaluation of `read_field3::FIELD3` failed here + | + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + 00 00 80 3f __ __ __ __ │ ...?░░░░ + } note: erroneous constant encountered - --> $DIR/union-const-eval-field.rs:30:5 + --> $DIR/union-const-eval-field.rs:31:5 | LL | FIELD3 | ^^^^^^ note: erroneous constant encountered - --> $DIR/union-const-eval-field.rs:30:5 + --> $DIR/union-const-eval-field.rs:31:5 | LL | FIELD3 | ^^^^^^ diff --git a/tests/ui/consts/const-eval/union-ice.stderr b/tests/ui/consts/const-eval/union-ice.stderr index 826d7440a808..0506be63ea6f 100644 --- a/tests/ui/consts/const-eval/union-ice.stderr +++ b/tests/ui/consts/const-eval/union-ice.stderr @@ -3,18 +3,30 @@ error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; | ^^^^^^^^^^^^ evaluation of `FIELD3` failed here + | + = note: the raw bytes of the constant (size: 8, align: 8) { + 00 00 80 3f __ __ __ __ │ ...?░░░░ + } error[E0080]: reading memory at ALLOC1[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/union-ice.rs:19:17 | LL | b: unsafe { UNION.field3 }, | ^^^^^^^^^^^^ evaluation of `FIELD_PATH` failed here + | + = note: the raw bytes of the constant (size: 8, align: 8) { + 00 00 80 3f __ __ __ __ │ ...?░░░░ + } error[E0080]: reading memory at ALLOC2[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/union-ice.rs:31:18 | LL | unsafe { UNION.field3 }, | ^^^^^^^^^^^^ evaluation of `FIELD_PATH2` failed here + | + = note: the raw bytes of the constant (size: 8, align: 8) { + 00 00 80 3f __ __ __ __ │ ...?░░░░ + } error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const-eval/union-ub.32bit.stderr b/tests/ui/consts/const-eval/union-ub.32bit.stderr index 70bf2cf53908..757bcea91c3c 100644 --- a/tests/ui/consts/const-eval/union-ub.32bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.32bit.stderr @@ -14,6 +14,10 @@ error[E0080]: reading memory at ALLOC0[0x0..0x1], but memory is uninitialized at | LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_BOOL` failed here + | + = note: the raw bytes of the constant (size: 1, align: 1) { + __ │ ░ + } error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/union-ub.64bit.stderr b/tests/ui/consts/const-eval/union-ub.64bit.stderr index 70bf2cf53908..757bcea91c3c 100644 --- a/tests/ui/consts/const-eval/union-ub.64bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.64bit.stderr @@ -14,6 +14,10 @@ error[E0080]: reading memory at ALLOC0[0x0..0x1], but memory is uninitialized at | LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_BOOL` failed here + | + = note: the raw bytes of the constant (size: 1, align: 1) { + __ │ ░ + } error: aborting due to 2 previous errors diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr index 10f4d8d1a711..5f4ef14d5869 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr @@ -3,6 +3,10 @@ error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at | LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_EQ_PADDING` failed here + | + = note: the raw bytes of the constant (size: 4, align: 2) { + 01 __ 02 00 │ .░.. + } error[E0080]: unable to turn pointer into integer --> $DIR/intrinsic-raw_eq-const-bad.rs:9:5 diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr index 76824055d8a1..b545cd75ddb5 100644 --- a/tests/ui/type/pattern_types/validity.stderr +++ b/tests/ui/type/pattern_types/validity.stderr @@ -14,6 +14,10 @@ error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at | LL | const BAD_UNINIT: pattern_type!(u32 is 1..) = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_UNINIT` failed here + | + = note: the raw bytes of the constant (size: 4, align: 4) { + __ __ __ __ │ ░░░░ + } error[E0080]: unable to turn pointer into integer --> $DIR/validity.rs:17:1 @@ -51,6 +55,10 @@ error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at | LL | const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `CHAR_UNINIT` failed here + | + = note: the raw bytes of the constant (size: 4, align: 4) { + __ __ __ __ │ ░░░░ + } error[E0080]: constructing invalid value: encountered 97, but expected something in the range 65..=89 --> $DIR/validity.rs:33:1 From 8e840f726d013f824cc2e98aa54307f27295b34b Mon Sep 17 00:00:00 2001 From: Maksim Bondarenkov Date: Fri, 18 Jul 2025 11:20:03 +0300 Subject: [PATCH 311/363] opt-dist: make llvm builds optional adds command line option for disabling llvm builds. it's useful in case of user having their own optimized LLVM, so they won't waste time for (at least) 3 LLVM builds. in this case PGO optimized will be already built in Stage 1, so my previous PR should be addressed for this change --- src/tools/opt-dist/src/environment.rs | 5 ++ src/tools/opt-dist/src/exec.rs | 12 ++- src/tools/opt-dist/src/main.rs | 114 +++++++++++++++----------- src/tools/opt-dist/src/training.rs | 4 +- 4 files changed, 83 insertions(+), 52 deletions(-) diff --git a/src/tools/opt-dist/src/environment.rs b/src/tools/opt-dist/src/environment.rs index 946e926a3c01..d41dc80e6b2a 100644 --- a/src/tools/opt-dist/src/environment.rs +++ b/src/tools/opt-dist/src/environment.rs @@ -27,6 +27,7 @@ pub struct Environment { shared_llvm: bool, run_tests: bool, fast_try_build: bool, + build_llvm: bool, } impl Environment { @@ -111,6 +112,10 @@ impl Environment { pub fn is_fast_try_build(&self) -> bool { self.fast_try_build } + + pub fn build_llvm(&self) -> bool { + self.build_llvm + } } /// What is the extension of binary executables on this platform? diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs index 0dc6e56b9d5f..56eff2ca2a7d 100644 --- a/src/tools/opt-dist/src/exec.rs +++ b/src/tools/opt-dist/src/exec.rs @@ -139,8 +139,10 @@ impl Bootstrap { self } - pub fn llvm_pgo_optimize(mut self, profile: &LlvmPGOProfile) -> Self { - self.cmd = self.cmd.arg("--llvm-profile-use").arg(profile.0.as_str()); + pub fn llvm_pgo_optimize(mut self, profile: Option<&LlvmPGOProfile>) -> Self { + if let Some(prof) = profile { + self.cmd = self.cmd.arg("--llvm-profile-use").arg(prof.0.as_str()); + } self } @@ -174,8 +176,10 @@ impl Bootstrap { self } - pub fn with_bolt_profile(mut self, profile: BoltProfile) -> Self { - self.cmd = self.cmd.arg("--reproducible-artifact").arg(profile.0.as_str()); + pub fn with_bolt_profile(mut self, profile: Option) -> Self { + if let Some(prof) = profile { + self.cmd = self.cmd.arg("--reproducible-artifact").arg(prof.0.as_str()); + } self } diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index 9c8a6637a3b1..7857f196626b 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -98,6 +98,10 @@ enum EnvironmentCmd { /// Perform tests after final build if it's not a fast try build #[arg(long)] run_tests: bool, + + /// Will be LLVM built during the run? + #[arg(long, default_value_t = true, action(clap::ArgAction::Set))] + build_llvm: bool, }, /// Perform an optimized build on Linux CI, from inside Docker. LinuxCi { @@ -133,6 +137,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec)> benchmark_cargo_config, shared, run_tests, + build_llvm, } => { let env = EnvironmentBuilder::default() .host_tuple(target_triple) @@ -148,6 +153,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec)> .benchmark_cargo_config(benchmark_cargo_config) .run_tests(run_tests) .fast_try_build(is_fast_try_build) + .build_llvm(build_llvm) .build()?; (env, shared.build_args) @@ -172,6 +178,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec)> .skipped_tests(vec![]) .run_tests(true) .fast_try_build(is_fast_try_build) + .build_llvm(true) .build()?; (env, shared.build_args) @@ -193,6 +200,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec)> .skipped_tests(vec![]) .run_tests(true) .fast_try_build(is_fast_try_build) + .build_llvm(true) .build()?; (env, shared.build_args) @@ -255,30 +263,35 @@ fn execute_pipeline( // Stage 2: Gather LLVM PGO profiles // Here we build a PGO instrumented LLVM, reusing the previously PGO optimized rustc. // Then we use the instrumented LLVM to gather LLVM PGO profiles. - let llvm_pgo_profile = timer.section("Stage 2 (LLVM PGO)", |stage| { - // Remove the previous, uninstrumented build of LLVM. - clear_llvm_files(env)?; + let llvm_pgo_profile = if env.build_llvm() { + timer.section("Stage 2 (LLVM PGO)", |stage| { + // Remove the previous, uninstrumented build of LLVM. + clear_llvm_files(env)?; - let llvm_profile_dir_root = env.artifact_dir().join("llvm-pgo"); + let llvm_profile_dir_root = env.artifact_dir().join("llvm-pgo"); - stage.section("Build PGO instrumented LLVM", |section| { - Bootstrap::build(env) - .llvm_pgo_instrument(&llvm_profile_dir_root) - .avoid_rustc_rebuild() - .run(section) - })?; + stage.section("Build PGO instrumented LLVM", |section| { + Bootstrap::build(env) + .llvm_pgo_instrument(&llvm_profile_dir_root) + .avoid_rustc_rebuild() + .run(section) + })?; - let profile = stage - .section("Gather profiles", |_| gather_llvm_profiles(env, &llvm_profile_dir_root))?; + let profile = stage.section("Gather profiles", |_| { + gather_llvm_profiles(env, &llvm_profile_dir_root) + })?; - print_free_disk_space()?; + print_free_disk_space()?; - // Proactively delete the instrumented artifacts, to avoid using them by accident in - // follow-up stages. - clear_llvm_files(env)?; + // Proactively delete the instrumented artifacts, to avoid using them by accident in + // follow-up stages. + clear_llvm_files(env)?; - Ok(profile) - })?; + Ok(Some(profile)) + })? + } else { + None + }; let bolt_profiles = if env.use_bolt() { // Stage 3: Build BOLT instrumented LLVM @@ -286,37 +299,43 @@ fn execute_pipeline( // Note that we don't remove LLVM artifacts after this step, so that they are reused in the final dist build. // BOLT instrumentation is performed "on-the-fly" when the LLVM library is copied to the sysroot of rustc, // therefore the LLVM artifacts on disk are not "tainted" with BOLT instrumentation and they can be reused. + let libdir = env.build_artifacts().join("stage2").join("lib"); timer.section("Stage 3 (BOLT)", |stage| { - stage.section("Build PGO optimized LLVM", |stage| { - Bootstrap::build(env) - .with_llvm_bolt_ldflags() - .llvm_pgo_optimize(&llvm_pgo_profile) - .avoid_rustc_rebuild() - .run(stage) - })?; + let llvm_profile = if env.build_llvm() { + stage.section("Build PGO optimized LLVM", |stage| { + Bootstrap::build(env) + .with_llvm_bolt_ldflags() + .llvm_pgo_optimize(llvm_pgo_profile.as_ref()) + .avoid_rustc_rebuild() + .run(stage) + })?; - let libdir = env.build_artifacts().join("stage2").join("lib"); - // The actual name will be something like libLLVM.so.18.1-rust-dev. - let llvm_lib = io::find_file_in_dir(&libdir, "libLLVM.so", "")?; + // The actual name will be something like libLLVM.so.18.1-rust-dev. + let llvm_lib = io::find_file_in_dir(&libdir, "libLLVM.so", "")?; - log::info!("Optimizing {llvm_lib} with BOLT"); + log::info!("Optimizing {llvm_lib} with BOLT"); - // FIXME(kobzol): try gather profiles together, at once for LLVM and rustc - // Instrument the libraries and gather profiles - let llvm_profile = with_bolt_instrumented(&llvm_lib, |llvm_profile_dir| { - stage.section("Gather profiles", |_| { - gather_bolt_profiles(env, "LLVM", llvm_benchmarks(env), llvm_profile_dir) - }) - })?; - print_free_disk_space()?; + // FIXME(kobzol): try gather profiles together, at once for LLVM and rustc + // Instrument the libraries and gather profiles + let llvm_profile = with_bolt_instrumented(&llvm_lib, |llvm_profile_dir| { + stage.section("Gather profiles", |_| { + gather_bolt_profiles(env, "LLVM", llvm_benchmarks(env), llvm_profile_dir) + }) + })?; + print_free_disk_space()?; - // Now optimize the library with BOLT. The `libLLVM-XXX.so` library is actually hard-linked - // from several places, and this specific path (`llvm_lib`) will *not* be packaged into - // the final dist build. However, when BOLT optimizes an artifact, it does so *in-place*, - // therefore it will actually optimize all the hard links, which means that the final - // packaged `libLLVM.so` file *will* be BOLT optimized. - bolt_optimize(&llvm_lib, &llvm_profile, env) - .context("Could not optimize LLVM with BOLT")?; + // Now optimize the library with BOLT. The `libLLVM-XXX.so` library is actually hard-linked + // from several places, and this specific path (`llvm_lib`) will *not* be packaged into + // the final dist build. However, when BOLT optimizes an artifact, it does so *in-place*, + // therefore it will actually optimize all the hard links, which means that the final + // packaged `libLLVM.so` file *will* be BOLT optimized. + bolt_optimize(&llvm_lib, &llvm_profile, env) + .context("Could not optimize LLVM with BOLT")?; + + Some(llvm_profile) + } else { + None + }; let rustc_lib = io::find_file_in_dir(&libdir, "librustc_driver", ".so")?; @@ -334,15 +353,16 @@ fn execute_pipeline( bolt_optimize(&rustc_lib, &rustc_profile, env) .context("Could not optimize rustc with BOLT")?; - // LLVM is not being cleared here, we want to use the BOLT-optimized LLVM - Ok(vec![llvm_profile, rustc_profile]) + // LLVM is not being cleared here. Either we built it and we want to use the BOLT-optimized LLVM, or we + // didn't build it, so we don't want to remove it. + Ok(vec![llvm_profile, Some(rustc_profile)]) })? } else { vec![] }; let mut dist = Bootstrap::dist(env, &dist_args) - .llvm_pgo_optimize(&llvm_pgo_profile) + .llvm_pgo_optimize(llvm_pgo_profile.as_ref()) .rustc_pgo_optimize(&rustc_pgo_profile) .avoid_rustc_rebuild(); diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs index 36a7d6a7cba4..ae062d5c60c6 100644 --- a/src/tools/opt-dist/src/training.rs +++ b/src/tools/opt-dist/src/training.rs @@ -163,7 +163,9 @@ pub fn gather_rustc_profiles( let merged_profile = env.artifact_dir().join("rustc-pgo.profdata"); log::info!("Merging Rustc PGO profiles to {merged_profile}"); - merge_llvm_profiles(env, &merged_profile, profile_root, LlvmProfdata::Target)?; + let llvm_profdata = if env.build_llvm() { LlvmProfdata::Target } else { LlvmProfdata::Host }; + + merge_llvm_profiles(env, &merged_profile, profile_root, llvm_profdata)?; log_profile_stats("Rustc", &merged_profile, profile_root)?; // We don't need the individual .profraw files now that they have been merged From 84ed70b69daa6865d3713d36fabad90a2fb96afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 20 Jun 2025 21:39:19 +0200 Subject: [PATCH 312/363] Reword diagnostics about relaxed bounds in invalid contexts --- compiler/rustc_ast_lowering/src/lib.rs | 26 +++++-- ...issing-associated_item_or_field_def_ids.rs | 2 +- ...ng-associated_item_or_field_def_ids.stderr | 8 +-- ...ing-associated-items-of-undefined-trait.rs | 2 +- ...associated-items-of-undefined-trait.stderr | 8 +-- .../feature-gate-more-maybe-bounds.rs | 8 +-- .../feature-gate-more-maybe-bounds.stderr | 34 ++++----- tests/ui/parser/trait-object-trait-parens.rs | 6 +- .../parser/trait-object-trait-parens.stderr | 18 ++--- .../ui/sized-hierarchy/default-supertrait.rs | 6 +- .../sized-hierarchy/default-supertrait.stderr | 17 ++--- .../maybe-trait-bounds-forbidden-locations.rs | 18 ----- ...be-trait-bounds-forbidden-locations.stderr | 31 -------- tests/ui/traits/wf-object/maybe-bound.rs | 18 ----- tests/ui/traits/wf-object/maybe-bound.stderr | 48 ------------- tests/ui/traits/wf-object/only-maybe-bound.rs | 2 +- .../traits/wf-object/only-maybe-bound.stderr | 8 +-- .../unsized/relaxed-bounds-invalid-places.rs | 35 ++++++---- .../relaxed-bounds-invalid-places.stderr | 70 ++++++++++++------- 19 files changed, 125 insertions(+), 240 deletions(-) delete mode 100644 tests/ui/traits/maybe-trait-bounds-forbidden-locations.rs delete mode 100644 tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr delete mode 100644 tests/ui/traits/wf-object/maybe-bound.rs delete mode 100644 tests/ui/traits/wf-object/maybe-bound.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d3d521e83b09..533ee9bff54f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -60,7 +60,7 @@ use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; -use rustc_session::parse::{add_feature_diagnostics, feature_err}; +use rustc_session::parse::add_feature_diagnostics; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, DesugaringKind, Span}; use smallvec::SmallVec; @@ -2071,7 +2071,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, rbp: RelaxedBoundPolicy<'_>, ) { - let err = |message| feature_err(&self.tcx.sess, sym::more_maybe_bounds, span, message); + // Even though feature `more_maybe_bounds` bypasses the given policy and (currently) enables + // relaxed bounds in every conceivable position[^1], we don't want to advertise it to the user + // (via a feature gate) since it's super internal. Besides this, it'd be quite distracting. + // + // [^1]: Strictly speaking, this is incorrect (at the very least for `Sized`) because it's + // no longer fully consistent with default trait elaboration in HIR ty lowering. match rbp { RelaxedBoundPolicy::Allowed => return, @@ -2093,11 +2098,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match reason { RelaxedBoundForbiddenReason::TraitObjectTy => { - err("`?Trait` is not permitted in trait object types").emit(); + self.dcx().span_err( + span, + "relaxed bounds are not permitted in trait object types", + ); return; } RelaxedBoundForbiddenReason::SuperTrait => { - let mut diag = err("`?Trait` is not permitted in supertraits"); + let mut diag = self.dcx().struct_span_err( + span, + "relaxed bounds are not permitted in supertrait bounds", + ); if let Some(def_id) = trait_ref.trait_def_id() && self.tcx.is_lang_item(def_id, hir::LangItem::Sized) { @@ -2111,7 +2122,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - err("`?Trait` bounds are only permitted at the point where a type parameter is declared") + self.dcx() + .struct_span_err(span, "this relaxed bound is not permitted here") + .with_note( + "in this context, relaxed bounds are only allowed on \ + type parameters defined by the closest item", + ) .emit(); } diff --git a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs index 18c71e5c7442..029ce7d0e7e4 100644 --- a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs +++ b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs @@ -2,6 +2,6 @@ fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { //~^ ERROR expected trait, found associated function `Iterator::advance_by` - //~| ERROR `?Trait` is not permitted in trait object types + //~| ERROR relaxed bounds are not permitted in trait object types todo!() } diff --git a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr index 6ec8e01c78d3..ffe0b14a030d 100644 --- a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr +++ b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr @@ -4,16 +4,12 @@ error[E0404]: expected trait, found associated function `Iterator::advance_by` LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a trait -error[E0658]: `?Trait` is not permitted in trait object types +error: relaxed bounds are not permitted in trait object types --> $DIR/missing-associated_item_or_field_def_ids.rs:3:29 | LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 2 previous errors -Some errors have detailed explanations: E0404, E0658. -For more information about an error, try `rustc --explain E0404`. +For more information about this error, try `rustc --explain E0404`. diff --git a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs index 9e0a86abb2e0..bac4e6088677 100644 --- a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs +++ b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs @@ -7,5 +7,5 @@ trait Tr { fn main() { let _: dyn Tr + ?Foo; //~^ ERROR: cannot find trait `Foo` in this scope - //~| ERROR: `?Trait` is not permitted in trait object types + //~| ERROR: relaxed bounds are not permitted in trait object types } diff --git a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr index bd83c1a9ea89..3660fcece62a 100644 --- a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr +++ b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr @@ -4,16 +4,12 @@ error[E0405]: cannot find trait `Foo` in this scope LL | let _: dyn Tr + ?Foo; | ^^^ not found in this scope -error[E0658]: `?Trait` is not permitted in trait object types +error: relaxed bounds are not permitted in trait object types --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:21 | LL | let _: dyn Tr + ?Foo; | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 2 previous errors -Some errors have detailed explanations: E0405, E0658. -For more information about an error, try `rustc --explain E0405`. +For more information about this error, try `rustc --explain E0405`. diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs index 6a832744e3ee..3066967f87e2 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs @@ -2,13 +2,11 @@ trait Trait1 {} auto trait Trait2 {} -trait Trait3: ?Trait1 {} -//~^ ERROR `?Trait` is not permitted in supertraits -trait Trait4 where Self: ?Trait1 {} -//~^ ERROR ?Trait` bounds are only permitted at the point where a type parameter is declared +trait Trait3: ?Trait1 {} //~ ERROR relaxed bounds are not permitted in supertrait bounds +trait Trait4 where Self: ?Trait1 {} //~ ERROR this relaxed bound is not permitted here fn foo(_: Box) {} -//~^ ERROR `?Trait` is not permitted in trait object types +//~^ ERROR relaxed bounds are not permitted in trait object types fn bar(_: T) {} //~^ ERROR type parameter has more than one relaxed default bound, only one is supported //~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr index f52532a035b4..35b5b80d69eb 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr @@ -1,32 +1,25 @@ -error[E0658]: `?Trait` is not permitted in supertraits +error: relaxed bounds are not permitted in supertrait bounds --> $DIR/feature-gate-more-maybe-bounds.rs:5:15 | LL | trait Trait3: ?Trait1 {} | ^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/feature-gate-more-maybe-bounds.rs:7:26 +error: this relaxed bound is not permitted here + --> $DIR/feature-gate-more-maybe-bounds.rs:6:26 | LL | trait Trait4 where Self: ?Trait1 {} | ^^^^^^^ | - = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item -error[E0658]: `?Trait` is not permitted in trait object types - --> $DIR/feature-gate-more-maybe-bounds.rs:10:28 +error: relaxed bounds are not permitted in trait object types + --> $DIR/feature-gate-more-maybe-bounds.rs:8:28 | LL | fn foo(_: Box) {} | ^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/feature-gate-more-maybe-bounds.rs:12:11 + --> $DIR/feature-gate-more-maybe-bounds.rs:10:11 | LL | fn bar(_: T) {} | ^^^^^^^ ^^^^^^^ @@ -35,36 +28,35 @@ LL | fn bar(_: T) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/feature-gate-more-maybe-bounds.rs:12:11 + --> $DIR/feature-gate-more-maybe-bounds.rs:10:11 | LL | fn bar(_: T) {} | ^^^^^^^ error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/feature-gate-more-maybe-bounds.rs:12:21 + --> $DIR/feature-gate-more-maybe-bounds.rs:10:21 | LL | fn bar(_: T) {} | ^^^^^^^ error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/feature-gate-more-maybe-bounds.rs:19:11 + --> $DIR/feature-gate-more-maybe-bounds.rs:17:11 | LL | fn baz(_ : T) {} | ^^^^^^ ^^^^^^ error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/feature-gate-more-maybe-bounds.rs:19:11 + --> $DIR/feature-gate-more-maybe-bounds.rs:17:11 | LL | fn baz(_ : T) {} | ^^^^^^ error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/feature-gate-more-maybe-bounds.rs:19:20 + --> $DIR/feature-gate-more-maybe-bounds.rs:17:20 | LL | fn baz(_ : T) {} | ^^^^^^ error: aborting due to 9 previous errors -Some errors have detailed explanations: E0203, E0658. -For more information about an error, try `rustc --explain E0203`. +For more information about this error, try `rustc --explain E0203`. diff --git a/tests/ui/parser/trait-object-trait-parens.rs b/tests/ui/parser/trait-object-trait-parens.rs index 438034bc38aa..51f0e2de6116 100644 --- a/tests/ui/parser/trait-object-trait-parens.rs +++ b/tests/ui/parser/trait-object-trait-parens.rs @@ -6,17 +6,17 @@ fn f Trait<'a>)>() {} fn main() { let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; - //~^ ERROR `?Trait` is not permitted in trait object types + //~^ ERROR relaxed bounds are not permitted in trait object types //~| ERROR only auto traits can be used as additional traits //~| WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition let _: Box Trait<'a>) + (Obj)>; - //~^ ERROR `?Trait` is not permitted in trait object types + //~^ ERROR relaxed bounds are not permitted in trait object types //~| ERROR only auto traits can be used as additional traits //~| WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition let _: Box Trait<'a> + (Obj) + (?Sized)>; - //~^ ERROR `?Trait` is not permitted in trait object types + //~^ ERROR relaxed bounds are not permitted in trait object types //~| ERROR only auto traits can be used as additional traits //~| WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition diff --git a/tests/ui/parser/trait-object-trait-parens.stderr b/tests/ui/parser/trait-object-trait-parens.stderr index d75352b6811e..26d388f87798 100644 --- a/tests/ui/parser/trait-object-trait-parens.stderr +++ b/tests/ui/parser/trait-object-trait-parens.stderr @@ -1,29 +1,20 @@ -error[E0658]: `?Trait` is not permitted in trait object types +error: relaxed bounds are not permitted in trait object types --> $DIR/trait-object-trait-parens.rs:8:24 | LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; | ^^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types +error: relaxed bounds are not permitted in trait object types --> $DIR/trait-object-trait-parens.rs:13:16 | LL | let _: Box Trait<'a>) + (Obj)>; | ^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types +error: relaxed bounds are not permitted in trait object types --> $DIR/trait-object-trait-parens.rs:18:44 | LL | let _: Box Trait<'a> + (Obj) + (?Sized)>; | ^^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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: trait objects without an explicit `dyn` are deprecated --> $DIR/trait-object-trait-parens.rs:8:16 @@ -100,5 +91,4 @@ LL | let _: Box Trait<'a> + (Obj) + (?Sized)>; error: aborting due to 6 previous errors; 3 warnings emitted -Some errors have detailed explanations: E0225, E0658. -For more information about an error, try `rustc --explain E0225`. +For more information about this error, try `rustc --explain E0225`. diff --git a/tests/ui/sized-hierarchy/default-supertrait.rs b/tests/ui/sized-hierarchy/default-supertrait.rs index b25acf9e6ea4..ab3b28e84db5 100644 --- a/tests/ui/sized-hierarchy/default-supertrait.rs +++ b/tests/ui/sized-hierarchy/default-supertrait.rs @@ -6,18 +6,18 @@ use std::marker::{MetaSized, PointeeSized}; trait Sized_: Sized { } trait NegSized: ?Sized { } -//~^ ERROR `?Trait` is not permitted in supertraits +//~^ ERROR relaxed bounds are not permitted in supertrait bounds trait MetaSized_: MetaSized { } trait NegMetaSized: ?MetaSized { } -//~^ ERROR `?Trait` is not permitted in supertraits +//~^ ERROR relaxed bounds are not permitted in supertrait bounds trait PointeeSized_: PointeeSized { } trait NegPointeeSized: ?PointeeSized { } -//~^ ERROR `?Trait` is not permitted in supertraits +//~^ ERROR relaxed bounds are not permitted in supertrait bounds trait Bare {} diff --git a/tests/ui/sized-hierarchy/default-supertrait.stderr b/tests/ui/sized-hierarchy/default-supertrait.stderr index 0cb4f346a630..f5589d6e279c 100644 --- a/tests/ui/sized-hierarchy/default-supertrait.stderr +++ b/tests/ui/sized-hierarchy/default-supertrait.stderr @@ -1,30 +1,22 @@ -error[E0658]: `?Trait` is not permitted in supertraits +error: relaxed bounds are not permitted in supertrait bounds --> $DIR/default-supertrait.rs:8:17 | LL | trait NegSized: ?Sized { } | ^^^^^^ | - = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: traits are `?Sized` by default -error[E0658]: `?Trait` is not permitted in supertraits +error: relaxed bounds are not permitted in supertrait bounds --> $DIR/default-supertrait.rs:13:21 | LL | trait NegMetaSized: ?MetaSized { } | ^^^^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in supertraits +error: relaxed bounds are not permitted in supertrait bounds --> $DIR/default-supertrait.rs:19:24 | LL | trait NegPointeeSized: ?PointeeSized { } | ^^^^^^^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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[E0277]: the size for values of type `T` cannot be known --> $DIR/default-supertrait.rs:52:38 @@ -119,5 +111,4 @@ LL | fn with_bare_trait() { error: aborting due to 9 previous errors -Some errors have detailed explanations: E0277, E0658. -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/traits/maybe-trait-bounds-forbidden-locations.rs b/tests/ui/traits/maybe-trait-bounds-forbidden-locations.rs deleted file mode 100644 index 04963c98765e..000000000000 --- a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Test that ?Trait bounds are forbidden in supertraits and trait object types. -//! -//! While `?Sized` and other maybe bounds are allowed in type parameter bounds and where clauses, -//! they are explicitly forbidden in certain syntactic positions: -//! - As supertraits in trait definitions -//! - In trait object type expressions -//! -//! See https://github.com/rust-lang/rust/issues/20503 - -trait Tr: ?Sized {} -//~^ ERROR `?Trait` is not permitted in supertraits - -type A1 = dyn Tr + (?Sized); -//~^ ERROR `?Trait` is not permitted in trait object types -type A2 = dyn for<'a> Tr + (?Sized); -//~^ ERROR `?Trait` is not permitted in trait object types - -fn main() {} diff --git a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr b/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr deleted file mode 100644 index 5c4100d0e269..000000000000 --- a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0658]: `?Trait` is not permitted in supertraits - --> $DIR/maybe-trait-bounds-forbidden-locations.rs:10:11 - | -LL | trait Tr: ?Sized {} - | ^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: traits are `?Sized` by default - -error[E0658]: `?Trait` is not permitted in trait object types - --> $DIR/maybe-trait-bounds-forbidden-locations.rs:13:20 - | -LL | type A1 = dyn Tr + (?Sized); - | ^^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types - --> $DIR/maybe-trait-bounds-forbidden-locations.rs:15:28 - | -LL | type A2 = dyn for<'a> Tr + (?Sized); - | ^^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/wf-object/maybe-bound.rs b/tests/ui/traits/wf-object/maybe-bound.rs deleted file mode 100644 index 17771e976ef3..000000000000 --- a/tests/ui/traits/wf-object/maybe-bound.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Test that `dyn ... + ?Sized + ...` is okay (though `?Sized` has no effect in trait objects). - -trait Foo {} - -type _0 = dyn ?Sized + Foo; -//~^ ERROR `?Trait` is not permitted in trait object types - -type _1 = dyn Foo + ?Sized; -//~^ ERROR `?Trait` is not permitted in trait object types - -type _2 = dyn Foo + ?Sized + ?Sized; -//~^ ERROR `?Trait` is not permitted in trait object types -//~| ERROR `?Trait` is not permitted in trait object types - -type _3 = dyn ?Sized + Foo; -//~^ ERROR `?Trait` is not permitted in trait object types - -fn main() {} diff --git a/tests/ui/traits/wf-object/maybe-bound.stderr b/tests/ui/traits/wf-object/maybe-bound.stderr deleted file mode 100644 index be7afabd0d01..000000000000 --- a/tests/ui/traits/wf-object/maybe-bound.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error[E0658]: `?Trait` is not permitted in trait object types - --> $DIR/maybe-bound.rs:5:15 - | -LL | type _0 = dyn ?Sized + Foo; - | ^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types - --> $DIR/maybe-bound.rs:8:21 - | -LL | type _1 = dyn Foo + ?Sized; - | ^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types - --> $DIR/maybe-bound.rs:11:21 - | -LL | type _2 = dyn Foo + ?Sized + ?Sized; - | ^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types - --> $DIR/maybe-bound.rs:11:30 - | -LL | type _2 = dyn Foo + ?Sized + ?Sized; - | ^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types - --> $DIR/maybe-bound.rs:15:15 - | -LL | type _3 = dyn ?Sized + Foo; - | ^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/wf-object/only-maybe-bound.rs b/tests/ui/traits/wf-object/only-maybe-bound.rs index 3e6db3e997c9..96360e0331cd 100644 --- a/tests/ui/traits/wf-object/only-maybe-bound.rs +++ b/tests/ui/traits/wf-object/only-maybe-bound.rs @@ -2,6 +2,6 @@ type _0 = dyn ?Sized; //~^ ERROR at least one trait is required for an object type [E0224] -//~| ERROR ?Trait` is not permitted in trait object types +//~| ERROR relaxed bounds are not permitted in trait object types fn main() {} diff --git a/tests/ui/traits/wf-object/only-maybe-bound.stderr b/tests/ui/traits/wf-object/only-maybe-bound.stderr index 26269476eaae..6ae4568c699a 100644 --- a/tests/ui/traits/wf-object/only-maybe-bound.stderr +++ b/tests/ui/traits/wf-object/only-maybe-bound.stderr @@ -1,11 +1,8 @@ -error[E0658]: `?Trait` is not permitted in trait object types +error: relaxed bounds are not permitted in trait object types --> $DIR/only-maybe-bound.rs:3:15 | LL | type _0 = dyn ?Sized; | ^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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[E0224]: at least one trait is required for an object type --> $DIR/only-maybe-bound.rs:3:11 @@ -15,5 +12,4 @@ LL | type _0 = dyn ?Sized; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0224, E0658. -For more information about an error, try `rustc --explain E0224`. +For more information about this error, try `rustc --explain E0224`. diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.rs b/tests/ui/unsized/relaxed-bounds-invalid-places.rs index ce3f35608beb..e9f39d5f2117 100644 --- a/tests/ui/unsized/relaxed-bounds-invalid-places.rs +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.rs @@ -1,19 +1,18 @@ -// Test that relaxed bounds can only be placed on type parameters defined by the closest item -// (ignoring relaxed bounds inside `impl Trait` and in associated type defs here). +// Test various places where relaxed bounds are not permitted. +// +// Relaxed bounds are only permitted inside impl-Trait, assoc ty item bounds and +// on type params defined by the closest item. -struct S1(T) where (T): ?Sized; -//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared +struct S1(T) where (T): ?Sized; //~ ERROR this relaxed bound is not permitted here -struct S2(T) where u8: ?Sized; -//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared +struct S2(T) where u8: ?Sized; //~ ERROR this relaxed bound is not permitted here -struct S3(T) where &'static T: ?Sized; -//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared +struct S3(T) where &'static T: ?Sized; //~ ERROR this relaxed bound is not permitted here trait Trait<'a> {} struct S4(T) where for<'a> T: ?Trait<'a>; -//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared +//~^ ERROR this relaxed bound is not permitted here //~| ERROR relaxing a default bound only does something for `?Sized` struct S5(*const T) where T: ?Trait<'static> + ?Sized; @@ -21,11 +20,17 @@ struct S5(*const T) where T: ?Trait<'static> + ?Sized; //~| ERROR relaxing a default bound only does something for `?Sized` impl S1 { - fn f() where T: ?Sized {} - //~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared + fn f() where T: ?Sized {} //~ ERROR this relaxed bound is not permitted here } -fn main() { - let u = vec![1, 2, 3]; - let _s: S5<[u8]> = S5(&u[..]); // OK -} +trait Tr: ?Sized {} //~ ERROR relaxed bounds are not permitted in supertrait bounds + +// Test that relaxed `Sized` bounds are rejected in trait object types: + +type O1 = dyn Tr + ?Sized; //~ ERROR relaxed bounds are not permitted in trait object types +type O2 = dyn ?Sized + ?Sized + Tr; +//~^ ERROR relaxed bounds are not permitted in trait object types +//~| ERROR relaxed bounds are not permitted in trait object types + +fn main() {} + diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr index 3287eb8d1e9d..a08dc15058a5 100644 --- a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr @@ -1,56 +1,77 @@ -error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/relaxed-bounds-invalid-places.rs:4:28 +error: this relaxed bound is not permitted here + --> $DIR/relaxed-bounds-invalid-places.rs:6:28 | LL | struct S1(T) where (T): ?Sized; | ^^^^^^ | - = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item -error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/relaxed-bounds-invalid-places.rs:7:27 +error: this relaxed bound is not permitted here + --> $DIR/relaxed-bounds-invalid-places.rs:8:27 | LL | struct S2(T) where u8: ?Sized; | ^^^^^^ | - = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item -error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared +error: this relaxed bound is not permitted here --> $DIR/relaxed-bounds-invalid-places.rs:10:35 | LL | struct S3(T) where &'static T: ?Sized; | ^^^^^^ | - = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item -error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/relaxed-bounds-invalid-places.rs:15:34 +error: this relaxed bound is not permitted here + --> $DIR/relaxed-bounds-invalid-places.rs:14:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; | ^^^^^^^^^^ | - = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item -error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/relaxed-bounds-invalid-places.rs:24:21 +error: this relaxed bound is not permitted here + --> $DIR/relaxed-bounds-invalid-places.rs:23:21 | LL | fn f() where T: ?Sized {} | ^^^^^^ | - = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item + +error: relaxed bounds are not permitted in supertrait bounds + --> $DIR/relaxed-bounds-invalid-places.rs:26:11 + | +LL | trait Tr: ?Sized {} + | ^^^^^^ + | + = note: traits are `?Sized` by default + +error: relaxed bounds are not permitted in trait object types + --> $DIR/relaxed-bounds-invalid-places.rs:30:20 + | +LL | type O1 = dyn Tr + ?Sized; + | ^^^^^^ + +error: relaxed bounds are not permitted in trait object types + --> $DIR/relaxed-bounds-invalid-places.rs:31:15 + | +LL | type O2 = dyn ?Sized + ?Sized + Tr; + | ^^^^^^ + +error: relaxed bounds are not permitted in trait object types + --> $DIR/relaxed-bounds-invalid-places.rs:31:24 + | +LL | type O2 = dyn ?Sized + ?Sized + Tr; + | ^^^^^^ error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/relaxed-bounds-invalid-places.rs:15:34 + --> $DIR/relaxed-bounds-invalid-places.rs:14:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; | ^^^^^^^^^^ error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/relaxed-bounds-invalid-places.rs:19:33 + --> $DIR/relaxed-bounds-invalid-places.rs:18:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^^^^^^^^^^^^^^^ ^^^^^^ @@ -59,12 +80,11 @@ LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/relaxed-bounds-invalid-places.rs:19:33 + --> $DIR/relaxed-bounds-invalid-places.rs:18:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 12 previous errors -Some errors have detailed explanations: E0203, E0658. -For more information about an error, try `rustc --explain E0203`. +For more information about this error, try `rustc --explain E0203`. From 879f62bb3c23b7a90ac71bb217056fd49ff8dafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Thu, 19 Jun 2025 18:41:57 +0200 Subject: [PATCH 313/363] Reword diagnostic about relaxing non-`Sized` bound * The phrasing "only does something for" made sense back when this diagnostic was a (hard) warning. Now however, it's simply a hard error and thus completely rules out "doing something". * The primary message was way too long * The new wording more closely mirrors the wording we use for applying other bound modifiers (like `const` and `async`) to incompatible traits. * "all other traits are not bound by default" is no longer accurate under Sized Hierarchy. E.g., traits and assoc tys are (currently) bounded by `MetaSized` by default but can't be relaxed using `?MetaSized` (instead, you relax it by adding `PointeeSized`). * I've decided against adding any diagnositic notes or suggestions for now like "trait `Trait` can't be relaxed as it's not bound by default" which would be incorrect for `MetaSized` and assoc tys as mentioned above) or "consider changing `?MetaSized` to `PointeeSized`" as the Sized Hierarchy impl is still WIP) --- .../src/hir_ty_lowering/bounds.rs | 27 ++++++++--- .../src/hir_ty_lowering/errors.rs | 47 +++++++++---------- .../feature-gate-more-maybe-bounds.rs | 8 ++-- .../feature-gate-more-maybe-bounds.stderr | 8 ++-- .../impl-trait/opt-out-bound-not-satisfied.rs | 4 +- .../opt-out-bound-not-satisfied.stderr | 4 +- tests/ui/issues/issue-37534.rs | 2 +- tests/ui/issues/issue-37534.stderr | 2 +- tests/ui/issues/issue-87199.rs | 8 ++-- tests/ui/issues/issue-87199.stderr | 8 ++-- tests/ui/sized-hierarchy/default-bound.rs | 4 +- tests/ui/sized-hierarchy/default-bound.stderr | 4 +- .../trait-bounds/maybe-bound-has-path-args.rs | 2 +- .../maybe-bound-has-path-args.stderr | 2 +- .../ui/trait-bounds/maybe-bound-with-assoc.rs | 4 +- .../maybe-bound-with-assoc.stderr | 4 +- tests/ui/trait-bounds/more_maybe_bounds.rs | 29 ++++++++++++ .../ui/trait-bounds/more_maybe_bounds.stderr | 20 ++++++++ tests/ui/traits/maybe-polarity-pass.rs | 25 ---------- tests/ui/traits/maybe-polarity-pass.stderr | 20 -------- tests/ui/traits/maybe-polarity-repeated.rs | 4 +- .../ui/traits/maybe-polarity-repeated.stderr | 4 +- .../unsized/relaxed-bounds-invalid-places.rs | 4 +- .../relaxed-bounds-invalid-places.stderr | 4 +- 24 files changed, 131 insertions(+), 117 deletions(-) create mode 100644 tests/ui/trait-bounds/more_maybe_bounds.rs create mode 100644 tests/ui/trait-bounds/more_maybe_bounds.stderr delete mode 100644 tests/ui/traits/maybe-polarity-pass.rs delete mode 100644 tests/ui/traits/maybe-polarity-pass.stderr 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 b59ff863383f..dbd22fabab8b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -85,17 +85,17 @@ fn search_bounds_for<'tcx>( } } -fn collect_unbounds<'tcx>( +fn collect_relaxed_bounds<'tcx>( hir_bounds: &'tcx [hir::GenericBound<'tcx>], self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, ) -> SmallVec<[&'tcx PolyTraitRef<'tcx>; 1]> { - let mut unbounds: SmallVec<[_; 1]> = SmallVec::new(); + let mut relaxed_bounds: SmallVec<[_; 1]> = SmallVec::new(); search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| { if matches!(ptr.modifiers.polarity, hir::BoundPolarity::Maybe(_)) { - unbounds.push(ptr); + relaxed_bounds.push(ptr); } }); - unbounds + relaxed_bounds } fn collect_bounds<'a, 'tcx>( @@ -209,9 +209,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return; } } else { - // Report invalid unbounds on sizedness-bounded generic parameters. - let unbounds = collect_unbounds(hir_bounds, self_ty_where_predicates); - self.check_and_report_invalid_unbounds_on_param(unbounds); + // Report invalid relaxed bounds. + // FIXME: Since we only call this validation function here in this function, we only + // fully validate relaxed bounds in contexts where we perform + // "sized elaboration". In most cases that doesn't matter because we *usually* + // reject such relaxed bounds outright during AST lowering. + // However, this can easily get out of sync! Ideally, we would perform this step + // where we are guaranteed to catch *all* bounds like in + // `Self::lower_poly_trait_ref`. List of concrete issues: + // FIXME(more_maybe_bounds): We don't call this for e.g., trait object tys or + // supertrait bounds! + // FIXME(trait_alias, #143122): We don't call it for the RHS. Arguably however, + // AST lowering should reject them outright. + // FIXME(associated_type_bounds): We don't call this for them. However, AST + // lowering should reject them outright (#135229). + let bounds = collect_relaxed_bounds(hir_bounds, self_ty_where_predicates); + self.check_and_report_invalid_relaxed_bounds(bounds); } let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span); 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 5d85a3f8455e..8c99a41f6268 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -8,7 +8,7 @@ use rustc_errors::{ }; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir, HirId, LangItem, PolyTraitRef}; +use rustc_hir::{self as hir, HirId, PolyTraitRef}; use rustc_middle::bug; use rustc_middle::ty::fast_reject::{TreatParams, simplify_type}; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; @@ -35,26 +35,24 @@ use crate::fluent_generated as fluent; use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { - /// Check for multiple relaxed default bounds and relaxed bounds of non-sizedness traits. - pub(crate) fn check_and_report_invalid_unbounds_on_param( + /// Check for multiple relaxed bounds and relaxed bounds of non-default traits. + pub(crate) fn check_and_report_invalid_relaxed_bounds( &self, - unbounds: SmallVec<[&PolyTraitRef<'_>; 1]>, + relaxed_bounds: SmallVec<[&PolyTraitRef<'_>; 1]>, ) { let tcx = self.tcx(); - let sized_did = tcx.require_lang_item(LangItem::Sized, DUMMY_SP); - let mut unique_bounds = FxIndexSet::default(); let mut seen_repeat = false; - for unbound in &unbounds { - if let Res::Def(DefKind::Trait, unbound_def_id) = unbound.trait_ref.path.res { - seen_repeat |= !unique_bounds.insert(unbound_def_id); + for bound in &relaxed_bounds { + if let Res::Def(DefKind::Trait, trait_def_id) = bound.trait_ref.path.res { + seen_repeat |= !unique_bounds.insert(trait_def_id); } } - if unbounds.len() > 1 { + if relaxed_bounds.len() > 1 { let err = errors::MultipleRelaxedDefaultBounds { - spans: unbounds.iter().map(|ptr| ptr.span).collect(), + spans: relaxed_bounds.iter().map(|ptr| ptr.span).collect(), }; if seen_repeat { @@ -64,24 +62,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; } - for unbound in unbounds { - if let Res::Def(DefKind::Trait, did) = unbound.trait_ref.path.res - && ((did == sized_did) || tcx.is_default_trait(did)) + let sized_def_id = tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP); + + for bound in relaxed_bounds { + if let Res::Def(DefKind::Trait, def_id) = bound.trait_ref.path.res + && (def_id == sized_def_id || tcx.is_default_trait(def_id)) { continue; } - - let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds { - true => "`?Sized` and `experimental_default_bounds`", - false => "`?Sized`", - }; self.dcx().span_err( - unbound.span, - format!( - "relaxing a default bound only does something for {}; all other traits are \ - not bound by default", - unbound_traits - ), + bound.span, + if tcx.sess.opts.unstable_opts.experimental_default_bounds + || tcx.features().more_maybe_bounds() + { + "bound modifier `?` can only be applied to default traits like `Sized`" + } else { + "bound modifier `?` can only be applied to `Sized`" + }, ); } } diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs index 3066967f87e2..7c9d88462f63 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs @@ -9,14 +9,14 @@ fn foo(_: Box) {} //~^ ERROR relaxed bounds are not permitted in trait object types fn bar(_: T) {} //~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR bound modifier `?` can only be applied to `Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` trait Trait {} // Do not suggest `#![feature(more_maybe_bounds)]` for repetitions fn baz(_ : T) {} //~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR bound modifier `?` can only be applied to `Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr index 35b5b80d69eb..c6d940db57bf 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr @@ -27,13 +27,13 @@ LL | fn bar(_: T) {} = help: add `#![feature(more_maybe_bounds)]` 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: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/feature-gate-more-maybe-bounds.rs:10:11 | LL | fn bar(_: T) {} | ^^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/feature-gate-more-maybe-bounds.rs:10:21 | LL | fn bar(_: T) {} @@ -45,13 +45,13 @@ error[E0203]: type parameter has more than one relaxed default bound, only one i LL | fn baz(_ : T) {} | ^^^^^^ ^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/feature-gate-more-maybe-bounds.rs:17:11 | LL | fn baz(_ : T) {} | ^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/feature-gate-more-maybe-bounds.rs:17:20 | LL | fn baz(_ : T) {} diff --git a/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs b/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs index 27c493a13bf9..7e0e1eadf9c7 100644 --- a/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs +++ b/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs @@ -3,8 +3,8 @@ use std::future::Future; fn foo() -> impl ?Future { - //~^ ERROR: relaxing a default bound only does something for `?Sized` - //~| ERROR: relaxing a default bound only does something for `?Sized` + //~^ ERROR: bound modifier `?` can only be applied to `Sized` + //~| ERROR: bound modifier `?` can only be applied to `Sized` () } diff --git a/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr b/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr index dc4314c58ad2..f99d6a7e5f6d 100644 --- a/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr +++ b/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr @@ -1,10 +1,10 @@ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/opt-out-bound-not-satisfied.rs:5:18 | LL | fn foo() -> impl ?Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/opt-out-bound-not-satisfied.rs:5:18 | LL | fn foo() -> impl ?Future { diff --git a/tests/ui/issues/issue-37534.rs b/tests/ui/issues/issue-37534.rs index 09d60b7786b9..63f6479ae2e2 100644 --- a/tests/ui/issues/issue-37534.rs +++ b/tests/ui/issues/issue-37534.rs @@ -1,5 +1,5 @@ struct Foo {} //~^ ERROR expected trait, found derive macro `Hash` -//~| ERROR relaxing a default bound only does something for `?Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` fn main() {} diff --git a/tests/ui/issues/issue-37534.stderr b/tests/ui/issues/issue-37534.stderr index 3219854bc70c..086073542030 100644 --- a/tests/ui/issues/issue-37534.stderr +++ b/tests/ui/issues/issue-37534.stderr @@ -9,7 +9,7 @@ help: consider importing this trait instead LL + use std::hash::Hash; | -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/issue-37534.rs:1:15 | LL | struct Foo {} diff --git a/tests/ui/issues/issue-87199.rs b/tests/ui/issues/issue-87199.rs index 4e4e35c6a71e..dd9dfc74ca35 100644 --- a/tests/ui/issues/issue-87199.rs +++ b/tests/ui/issues/issue-87199.rs @@ -6,12 +6,12 @@ // Check that these function definitions only emit warnings, not errors fn arg(_: T) {} -//~^ ERROR: relaxing a default bound only does something for `?Sized` +//~^ ERROR: bound modifier `?` can only be applied to `Sized` fn ref_arg(_: &T) {} -//~^ ERROR: relaxing a default bound only does something for `?Sized` +//~^ ERROR: bound modifier `?` can only be applied to `Sized` fn ret() -> impl Iterator + ?Send { std::iter::empty() } -//~^ ERROR: relaxing a default bound only does something for `?Sized` -//~| ERROR: relaxing a default bound only does something for `?Sized` +//~^ ERROR: bound modifier `?` can only be applied to `Sized` +//~| ERROR: bound modifier `?` can only be applied to `Sized` // Check that there's no `?Sized` relaxation! fn main() { diff --git a/tests/ui/issues/issue-87199.stderr b/tests/ui/issues/issue-87199.stderr index acc4e84779c9..8a930a3d704c 100644 --- a/tests/ui/issues/issue-87199.stderr +++ b/tests/ui/issues/issue-87199.stderr @@ -1,22 +1,22 @@ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/issue-87199.rs:8:11 | LL | fn arg(_: T) {} | ^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/issue-87199.rs:10:15 | LL | fn ref_arg(_: &T) {} | ^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/issue-87199.rs:12:40 | LL | fn ret() -> impl Iterator + ?Send { std::iter::empty() } | ^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/issue-87199.rs:12:40 | LL | fn ret() -> impl Iterator + ?Send { std::iter::empty() } diff --git a/tests/ui/sized-hierarchy/default-bound.rs b/tests/ui/sized-hierarchy/default-bound.rs index 12b2eb2b5c1b..bbb2c6d96baa 100644 --- a/tests/ui/sized-hierarchy/default-bound.rs +++ b/tests/ui/sized-hierarchy/default-bound.rs @@ -14,13 +14,13 @@ fn neg_sized() {} fn metasized() {} fn neg_metasized() {} -//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~^ ERROR bound modifier `?` can only be applied to `Sized` fn pointeesized() { } fn neg_pointeesized() { } -//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~^ ERROR bound modifier `?` can only be applied to `Sized` fn main() { diff --git a/tests/ui/sized-hierarchy/default-bound.stderr b/tests/ui/sized-hierarchy/default-bound.stderr index 22f0fa29d3e2..0a4ea6f44d8e 100644 --- a/tests/ui/sized-hierarchy/default-bound.stderr +++ b/tests/ui/sized-hierarchy/default-bound.stderr @@ -1,10 +1,10 @@ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/default-bound.rs:16:21 | LL | fn neg_metasized() {} | ^^^^^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/default-bound.rs:22:24 | LL | fn neg_pointeesized() { } diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs index e5abcae5d219..14a266704977 100644 --- a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs +++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs @@ -2,6 +2,6 @@ trait Trait {} fn test::Trait>() {} //~^ ERROR type arguments are not allowed on module `maybe_bound_has_path_args` -//~| ERROR relaxing a default bound only does something for `?Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` fn main() {} diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr index dc55b26c9183..bf968b05af08 100644 --- a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr +++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr @@ -1,4 +1,4 @@ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/maybe-bound-has-path-args.rs:3:12 | LL | fn test::Trait>() {} diff --git a/tests/ui/trait-bounds/maybe-bound-with-assoc.rs b/tests/ui/trait-bounds/maybe-bound-with-assoc.rs index 9127c2de16d5..e123f18474d1 100644 --- a/tests/ui/trait-bounds/maybe-bound-with-assoc.rs +++ b/tests/ui/trait-bounds/maybe-bound-with-assoc.rs @@ -2,11 +2,11 @@ trait HasAssoc { type Assoc; } fn hasassoc>() {} -//~^ ERROR relaxing a default bound +//~^ ERROR bound modifier `?` can only be applied to `Sized` trait NoAssoc {} fn noassoc>() {} -//~^ ERROR relaxing a default bound +//~^ ERROR bound modifier `?` can only be applied to `Sized` //~| ERROR associated type `Missing` not found for `NoAssoc` fn main() {} diff --git a/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr b/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr index 36a1e0ade206..b2ae0584aff9 100644 --- a/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr +++ b/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr @@ -1,10 +1,10 @@ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/maybe-bound-with-assoc.rs:4:16 | LL | fn hasassoc>() {} | ^^^^^^^^^^^^^^^^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/maybe-bound-with-assoc.rs:8:15 | LL | fn noassoc>() {} diff --git a/tests/ui/trait-bounds/more_maybe_bounds.rs b/tests/ui/trait-bounds/more_maybe_bounds.rs new file mode 100644 index 000000000000..61b630479ac3 --- /dev/null +++ b/tests/ui/trait-bounds/more_maybe_bounds.rs @@ -0,0 +1,29 @@ +// FIXME(more_maybe_bounds): Even under `more_maybe_bounds` / `-Zexperimental-default-bounds`, +// trying to relax non-default bounds should still be an error in all contexts! As you can see +// there are placed like supertrait bounds and trait object types where we currently don't perform +// this check. +#![feature(auto_traits, more_maybe_bounds, negative_impls)] + +trait Trait1 {} +auto trait Trait2 {} + +// FIXME: `?Trait1` should be rejected, `Trait1` isn't marked `#[lang = "default_traitN"]`. +trait Trait3: ?Trait1 {} +trait Trait4 where Self: Trait1 {} + +// FIXME: `?Trait2` should be rejected, `Trait2` isn't marked `#[lang = "default_traitN"]`. +fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {} +fn bar(_: &T) {} +//~^ ERROR bound modifier `?` can only be applied to default traits like `Sized` +//~| ERROR bound modifier `?` can only be applied to default traits like `Sized` +//~| ERROR bound modifier `?` can only be applied to default traits like `Sized` + +struct S; +impl !Trait2 for S {} +impl Trait1 for S {} +impl Trait3 for S {} + +fn main() { + foo(Box::new(S)); + bar(&S); +} diff --git a/tests/ui/trait-bounds/more_maybe_bounds.stderr b/tests/ui/trait-bounds/more_maybe_bounds.stderr new file mode 100644 index 000000000000..09c9fc311657 --- /dev/null +++ b/tests/ui/trait-bounds/more_maybe_bounds.stderr @@ -0,0 +1,20 @@ +error: bound modifier `?` can only be applied to default traits like `Sized` + --> $DIR/more_maybe_bounds.rs:16:20 + | +LL | fn bar(_: &T) {} + | ^^^^^^^ + +error: bound modifier `?` can only be applied to default traits like `Sized` + --> $DIR/more_maybe_bounds.rs:16:30 + | +LL | fn bar(_: &T) {} + | ^^^^^^^ + +error: bound modifier `?` can only be applied to default traits like `Sized` + --> $DIR/more_maybe_bounds.rs:16:40 + | +LL | fn bar(_: &T) {} + | ^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/traits/maybe-polarity-pass.rs b/tests/ui/traits/maybe-polarity-pass.rs deleted file mode 100644 index 1ccd52bc1694..000000000000 --- a/tests/ui/traits/maybe-polarity-pass.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![feature(auto_traits)] -#![feature(more_maybe_bounds)] -#![feature(negative_impls)] - -trait Trait1 {} -auto trait Trait2 {} - -trait Trait3 : ?Trait1 {} -trait Trait4 where Self: Trait1 {} - -fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {} -fn bar(_: &T) {} -//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - -struct S; -impl !Trait2 for S {} -impl Trait1 for S {} -impl Trait3 for S {} - -fn main() { - foo(Box::new(S)); - bar(&S); -} diff --git a/tests/ui/traits/maybe-polarity-pass.stderr b/tests/ui/traits/maybe-polarity-pass.stderr deleted file mode 100644 index 1f378dd665ae..000000000000 --- a/tests/ui/traits/maybe-polarity-pass.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-polarity-pass.rs:12:20 - | -LL | fn bar(_: &T) {} - | ^^^^^^^ - -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-polarity-pass.rs:12:30 - | -LL | fn bar(_: &T) {} - | ^^^^^^^ - -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-polarity-pass.rs:12:40 - | -LL | fn bar(_: &T) {} - | ^^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/tests/ui/traits/maybe-polarity-repeated.rs b/tests/ui/traits/maybe-polarity-repeated.rs index fd1ef567b3ea..962e3d5dbc5c 100644 --- a/tests/ui/traits/maybe-polarity-repeated.rs +++ b/tests/ui/traits/maybe-polarity-repeated.rs @@ -3,7 +3,7 @@ trait Trait {} fn foo(_: T) {} //~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR bound modifier `?` can only be applied to default traits like `Sized` +//~| ERROR bound modifier `?` can only be applied to default traits like `Sized` fn main() {} diff --git a/tests/ui/traits/maybe-polarity-repeated.stderr b/tests/ui/traits/maybe-polarity-repeated.stderr index 4fa1dc45bda8..de16c1471800 100644 --- a/tests/ui/traits/maybe-polarity-repeated.stderr +++ b/tests/ui/traits/maybe-polarity-repeated.stderr @@ -4,13 +4,13 @@ error[E0203]: type parameter has more than one relaxed default bound, only one i LL | fn foo(_: T) {} | ^^^^^^ ^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to default traits like `Sized` --> $DIR/maybe-polarity-repeated.rs:4:11 | LL | fn foo(_: T) {} | ^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to default traits like `Sized` --> $DIR/maybe-polarity-repeated.rs:4:20 | LL | fn foo(_: T) {} diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.rs b/tests/ui/unsized/relaxed-bounds-invalid-places.rs index e9f39d5f2117..64d4523ac499 100644 --- a/tests/ui/unsized/relaxed-bounds-invalid-places.rs +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.rs @@ -13,11 +13,11 @@ trait Trait<'a> {} struct S4(T) where for<'a> T: ?Trait<'a>; //~^ ERROR this relaxed bound is not permitted here -//~| ERROR relaxing a default bound only does something for `?Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` struct S5(*const T) where T: ?Trait<'static> + ?Sized; //~^ ERROR type parameter has more than one relaxed default bound -//~| ERROR relaxing a default bound only does something for `?Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` impl S1 { fn f() where T: ?Sized {} //~ ERROR this relaxed bound is not permitted here diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr index a08dc15058a5..cfa0d274b26c 100644 --- a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr @@ -64,7 +64,7 @@ error: relaxed bounds are not permitted in trait object types LL | type O2 = dyn ?Sized + ?Sized + Tr; | ^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/relaxed-bounds-invalid-places.rs:14:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; @@ -79,7 +79,7 @@ LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; = help: add `#![feature(more_maybe_bounds)]` 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: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/relaxed-bounds-invalid-places.rs:18:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; From cdc3d701cb4ff37e9d0c96c1c68b2e8789c19441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 18 Jul 2025 12:24:56 +0200 Subject: [PATCH 314/363] Don't reject *multiple* relaxed bounds, reject *duplicate* ones. Having multiple relaxed bounds like `?Sized + ?Iterator` is actually *fine*. We actually want to reject *duplicate* relaxed bounds like `?Sized + ?Sized` because these most certainly represent a user error. Note that this doesn't mean that we accept more code because a bound like `?Iterator` is still invalid as it's not relaxing a *default* trait and the only way to define / use more default bounds is under the experimental and internal feature `more_maybe_bounds` plus `lang_items` plus unstable flag `-Zexperimental-default-bounds` (historical context: for the longest time, bounds like `?Iterator` were actually allowed and lead to a hard warning). Ultimately, this simply *reframes* the diagnostic. The scope of `more_maybe_bounds` / `-Zexperimental-default-bounds` remains unchanged as well. --- .../src/error_codes/E0203.md | 10 ++-- compiler/rustc_hir_analysis/messages.ftl | 3 -- compiler/rustc_hir_analysis/src/errors.rs | 7 --- .../src/hir_ty_lowering/errors.rs | 26 +++++----- .../feature-gate-more-maybe-bounds.rs | 10 +--- .../feature-gate-more-maybe-bounds.stderr | 30 +----------- .../trait-bounds/duplicate-relaxed-bounds.rs | 22 +++++++++ .../duplicate-relaxed-bounds.stderr | 47 +++++++++++++++++++ ...7441.rs => fix-dyn-sized-fn-param-sugg.rs} | 25 +++++----- ...err => fix-dyn-sized-fn-param-sugg.stderr} | 40 ++++++++-------- tests/ui/trait-bounds/more_maybe_bounds.rs | 2 +- tests/ui/traits/maybe-polarity-repeated.rs | 9 ---- .../ui/traits/maybe-polarity-repeated.stderr | 21 --------- .../unsized/relaxed-bounds-invalid-places.rs | 4 +- .../relaxed-bounds-invalid-places.stderr | 22 +++------ 15 files changed, 128 insertions(+), 150 deletions(-) create mode 100644 tests/ui/trait-bounds/duplicate-relaxed-bounds.rs create mode 100644 tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr rename tests/ui/trait-bounds/{bad-suggestionf-for-repeated-unsized-bound-127441.rs => fix-dyn-sized-fn-param-sugg.rs} (51%) rename tests/ui/trait-bounds/{bad-suggestionf-for-repeated-unsized-bound-127441.stderr => fix-dyn-sized-fn-param-sugg.stderr} (80%) delete mode 100644 tests/ui/traits/maybe-polarity-repeated.rs delete mode 100644 tests/ui/traits/maybe-polarity-repeated.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0203.md b/compiler/rustc_error_codes/src/error_codes/E0203.md index 1edb519275f7..a4dceedbf1fd 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0203.md +++ b/compiler/rustc_error_codes/src/error_codes/E0203.md @@ -1,15 +1,15 @@ -Having multiple relaxed default bounds is unsupported. +Having duplicate relaxed default bounds is unsupported. Erroneous code example: ```compile_fail,E0203 -struct Bad{ - inner: T +struct Bad{ + inner: T, } ``` -Here the type `T` cannot have a relaxed bound for multiple default traits -(`Sized` and `Send`). This can be fixed by only using one relaxed bound. +Here the type parameter `T` cannot have duplicate relaxed bounds for default +trait `Sized`. This can be fixed by only using one relaxed bound: ``` struct Good{ diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index a20becbe7e84..90cb17270340 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -371,9 +371,6 @@ hir_analysis_missing_type_params = *[other] parameters } must be specified on the object type -hir_analysis_multiple_relaxed_default_bounds = - type parameter has more than one relaxed default bound, only one is supported - hir_analysis_must_be_name_of_associated_function = must be a name of an associated function hir_analysis_must_implement_not_function = not a function diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index eb65050c17c7..3283ce95ee05 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -278,13 +278,6 @@ pub(crate) struct CopyImplOnTypeWithDtor { pub span: Span, } -#[derive(Diagnostic)] -#[diag(hir_analysis_multiple_relaxed_default_bounds, code = E0203)] -pub(crate) struct MultipleRelaxedDefaultBounds { - #[primary_span] - pub spans: Vec, -} - #[derive(Diagnostic)] #[diag(hir_analysis_copy_impl_on_non_adt, code = E0206)] pub(crate) struct CopyImplOnNonAdt { 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 8c99a41f6268..3db78db931ab 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -35,31 +35,29 @@ use crate::fluent_generated as fluent; use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { - /// Check for multiple relaxed bounds and relaxed bounds of non-default traits. + /// Check for duplicate relaxed bounds and relaxed bounds of non-default traits. pub(crate) fn check_and_report_invalid_relaxed_bounds( &self, relaxed_bounds: SmallVec<[&PolyTraitRef<'_>; 1]>, ) { let tcx = self.tcx(); - let mut unique_bounds = FxIndexSet::default(); - let mut seen_repeat = false; + let mut grouped_bounds = FxIndexMap::<_, Vec<_>>::default(); + for bound in &relaxed_bounds { if let Res::Def(DefKind::Trait, trait_def_id) = bound.trait_ref.path.res { - seen_repeat |= !unique_bounds.insert(trait_def_id); + grouped_bounds.entry(trait_def_id).or_default().push(bound.span); } } - if relaxed_bounds.len() > 1 { - let err = errors::MultipleRelaxedDefaultBounds { - spans: relaxed_bounds.iter().map(|ptr| ptr.span).collect(), - }; - - if seen_repeat { - tcx.dcx().emit_err(err); - } else if !tcx.features().more_maybe_bounds() { - tcx.sess.create_feature_err(err, sym::more_maybe_bounds).emit(); - }; + for (trait_def_id, spans) in grouped_bounds { + if spans.len() > 1 { + let name = tcx.item_name(trait_def_id); + self.dcx() + .struct_span_err(spans, format!("duplicate relaxed `{name}` bounds")) + .with_code(E0203) + .emit(); + } } let sized_def_id = tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP); diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs index 7c9d88462f63..9c727ae3aad4 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs @@ -8,15 +8,7 @@ trait Trait4 where Self: ?Trait1 {} //~ ERROR this relaxed bound is not permitte fn foo(_: Box) {} //~^ ERROR relaxed bounds are not permitted in trait object types fn bar(_: T) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR bound modifier `?` can only be applied to `Sized` -//~| ERROR bound modifier `?` can only be applied to `Sized` - -trait Trait {} -// Do not suggest `#![feature(more_maybe_bounds)]` for repetitions -fn baz(_ : T) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR bound modifier `?` can only be applied to `Sized` +//~^ ERROR bound modifier `?` can only be applied to `Sized` //~| ERROR bound modifier `?` can only be applied to `Sized` fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr index c6d940db57bf..da6ad5f16e20 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr @@ -18,15 +18,6 @@ error: relaxed bounds are not permitted in trait object types LL | fn foo(_: Box) {} | ^^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/feature-gate-more-maybe-bounds.rs:10:11 - | -LL | fn bar(_: T) {} - | ^^^^^^^ ^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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: bound modifier `?` can only be applied to `Sized` --> $DIR/feature-gate-more-maybe-bounds.rs:10:11 | @@ -39,24 +30,5 @@ error: bound modifier `?` can only be applied to `Sized` LL | fn bar(_: T) {} | ^^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/feature-gate-more-maybe-bounds.rs:17:11 - | -LL | fn baz(_ : T) {} - | ^^^^^^ ^^^^^^ +error: aborting due to 5 previous errors -error: bound modifier `?` can only be applied to `Sized` - --> $DIR/feature-gate-more-maybe-bounds.rs:17:11 - | -LL | fn baz(_ : T) {} - | ^^^^^^ - -error: bound modifier `?` can only be applied to `Sized` - --> $DIR/feature-gate-more-maybe-bounds.rs:17:20 - | -LL | fn baz(_ : T) {} - | ^^^^^^ - -error: aborting due to 9 previous errors - -For more information about this error, try `rustc --explain E0203`. diff --git a/tests/ui/trait-bounds/duplicate-relaxed-bounds.rs b/tests/ui/trait-bounds/duplicate-relaxed-bounds.rs new file mode 100644 index 000000000000..a1681ddec77b --- /dev/null +++ b/tests/ui/trait-bounds/duplicate-relaxed-bounds.rs @@ -0,0 +1,22 @@ +fn dupes() {} +//~^ ERROR duplicate relaxed `Sized` bounds +//~| ERROR duplicate relaxed `Iterator` bounds +//~| ERROR bound modifier `?` can only be applied to `Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` + +trait Trait { + // We used to say "type parameter has more than one relaxed default bound" + // even on *associated types* like here. Test that we no longer do that. + type Type: ?Sized + ?Sized; + //~^ ERROR duplicate relaxed `Sized` bounds + //~| ERROR duplicate relaxed `Sized` bounds +} + +// We used to emit an additional error about "multiple relaxed default bounds". +// However, multiple relaxed bounds are actually *fine* if they're distinct. +// Ultimately, we still reject this because `Sized` is +// the only (stable) default trait, so we're fine. +fn not_dupes() {} +//~^ ERROR bound modifier `?` can only be applied to `Sized` + +fn main() {} diff --git a/tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr b/tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr new file mode 100644 index 000000000000..ccc723fc7a65 --- /dev/null +++ b/tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr @@ -0,0 +1,47 @@ +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/duplicate-relaxed-bounds.rs:1:13 + | +LL | fn dupes() {} + | ^^^^^^ ^^^^^^ + +error[E0203]: duplicate relaxed `Iterator` bounds + --> $DIR/duplicate-relaxed-bounds.rs:1:31 + | +LL | fn dupes() {} + | ^^^^^^^^^ ^^^^^^^^^ + +error: bound modifier `?` can only be applied to `Sized` + --> $DIR/duplicate-relaxed-bounds.rs:1:31 + | +LL | fn dupes() {} + | ^^^^^^^^^ + +error: bound modifier `?` can only be applied to `Sized` + --> $DIR/duplicate-relaxed-bounds.rs:1:43 + | +LL | fn dupes() {} + | ^^^^^^^^^ + +error: bound modifier `?` can only be applied to `Sized` + --> $DIR/duplicate-relaxed-bounds.rs:19:26 + | +LL | fn not_dupes() {} + | ^^^^^^^^^ + +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/duplicate-relaxed-bounds.rs:10:16 + | +LL | type Type: ?Sized + ?Sized; + | ^^^^^^ ^^^^^^ + +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/duplicate-relaxed-bounds.rs:10:16 + | +LL | type Type: ?Sized + ?Sized; + | ^^^^^^ ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0203`. diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.rs similarity index 51% rename from tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs rename to tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.rs index e6d7f74880fb..1aa36207bc3e 100644 --- a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs +++ b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.rs @@ -1,39 +1,38 @@ -// Regression test for #127441 - -// Tests that we make the correct suggestion -// in case there are more than one `?Sized` -// bounds on a function parameter +// Test that we emit a correct structured suggestions for dynamically sized ("maybe unsized") +// function parameters. +// We used to emit a butchered suggestion if duplicate relaxed `Sized` bounds were present. +// issue: . use std::fmt::Debug; fn foo1(a: T) {} -//~^ ERROR he size for values of type `T` cannot be known at compilation time +//~^ ERROR the size for values of type `T` cannot be known at compilation time fn foo2(a: T) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~^ ERROR duplicate relaxed `Sized` bounds //~| ERROR the size for values of type `T` cannot be known at compilation time fn foo3(a: T) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR he size for values of type `T` cannot be known at compilation time +//~^ ERROR duplicate relaxed `Sized` bounds +//~| ERROR the size for values of type `T` cannot be known at compilation time fn foo4(a: T) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~^ ERROR duplicate relaxed `Sized` bounds //~| ERROR the size for values of type `T` cannot be known at compilation time fn foo5(_: impl ?Sized) {} //~^ ERROR the size for values of type `impl ?Sized` cannot be known at compilation time fn foo6(_: impl ?Sized + ?Sized) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~^ ERROR duplicate relaxed `Sized` bounds //~| ERROR the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation tim fn foo7(_: impl ?Sized + ?Sized + Debug) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~^ ERROR duplicate relaxed `Sized` bounds //~| ERROR the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time fn foo8(_: impl ?Sized + Debug + ?Sized ) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~^ ERROR duplicate relaxed `Sized` bounds //~| ERROR the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time fn main() {} diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.stderr similarity index 80% rename from tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr rename to tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.stderr index 363f52d6df8d..7a9c2f043ac4 100644 --- a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr +++ b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.stderr @@ -1,41 +1,41 @@ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:12 +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:11:12 | LL | fn foo2(a: T) {} | ^^^^^^ ^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:12 +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:15:12 | LL | fn foo3(a: T) {} | ^^^^^^ ^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:12 +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:19:12 | LL | fn foo4(a: T) {} | ^^^^^^ ^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:17 +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:26:17 | LL | fn foo6(_: impl ?Sized + ?Sized) {} | ^^^^^^ ^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:17 +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:30:17 | LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {} | ^^^^^^ ^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:17 +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:34:17 | LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {} | ^^^^^^ ^^^^^^ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:9:23 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:8:23 | LL | fn foo1(a: T) {} | - ^ doesn't have a size known at compile-time @@ -54,7 +54,7 @@ LL | fn foo1(a: &T) {} | + error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:32 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:11:32 | LL | fn foo2(a: T) {} | - ^ doesn't have a size known at compile-time @@ -73,7 +73,7 @@ LL | fn foo2(a: &T) {} | + error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:40 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:15:40 | LL | fn foo3(a: T) {} | - ^ doesn't have a size known at compile-time @@ -92,7 +92,7 @@ LL | fn foo3(a: &T) {} | + error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:41 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:19:41 | LL | fn foo4(a: T) {} | - ^ doesn't have a size known at compile-time @@ -111,7 +111,7 @@ LL | fn foo4(a: &T) {} | + error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:24:12 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:23:12 | LL | fn foo5(_: impl ?Sized) {} | ^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | fn foo5(_: &impl ?Sized) {} | + error[E0277]: the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:12 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:26:12 | LL | fn foo6(_: impl ?Sized + ?Sized) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -151,7 +151,7 @@ LL | fn foo6(_: &impl ?Sized + ?Sized) {} | + error[E0277]: the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:12 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:30:12 | LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -171,7 +171,7 @@ LL | fn foo7(_: &impl ?Sized + ?Sized + Debug) {} | + error[E0277]: the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:12 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:34:12 | LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/trait-bounds/more_maybe_bounds.rs b/tests/ui/trait-bounds/more_maybe_bounds.rs index 61b630479ac3..47348b0a0dd7 100644 --- a/tests/ui/trait-bounds/more_maybe_bounds.rs +++ b/tests/ui/trait-bounds/more_maybe_bounds.rs @@ -1,6 +1,6 @@ // FIXME(more_maybe_bounds): Even under `more_maybe_bounds` / `-Zexperimental-default-bounds`, // trying to relax non-default bounds should still be an error in all contexts! As you can see -// there are placed like supertrait bounds and trait object types where we currently don't perform +// there are places like supertrait bounds and trait object types where we currently don't perform // this check. #![feature(auto_traits, more_maybe_bounds, negative_impls)] diff --git a/tests/ui/traits/maybe-polarity-repeated.rs b/tests/ui/traits/maybe-polarity-repeated.rs deleted file mode 100644 index 962e3d5dbc5c..000000000000 --- a/tests/ui/traits/maybe-polarity-repeated.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(more_maybe_bounds)] - -trait Trait {} -fn foo(_: T) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR bound modifier `?` can only be applied to default traits like `Sized` -//~| ERROR bound modifier `?` can only be applied to default traits like `Sized` - -fn main() {} diff --git a/tests/ui/traits/maybe-polarity-repeated.stderr b/tests/ui/traits/maybe-polarity-repeated.stderr deleted file mode 100644 index de16c1471800..000000000000 --- a/tests/ui/traits/maybe-polarity-repeated.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/maybe-polarity-repeated.rs:4:11 - | -LL | fn foo(_: T) {} - | ^^^^^^ ^^^^^^ - -error: bound modifier `?` can only be applied to default traits like `Sized` - --> $DIR/maybe-polarity-repeated.rs:4:11 - | -LL | fn foo(_: T) {} - | ^^^^^^ - -error: bound modifier `?` can only be applied to default traits like `Sized` - --> $DIR/maybe-polarity-repeated.rs:4:20 - | -LL | fn foo(_: T) {} - | ^^^^^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0203`. diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.rs b/tests/ui/unsized/relaxed-bounds-invalid-places.rs index 64d4523ac499..b8eda1e7786b 100644 --- a/tests/ui/unsized/relaxed-bounds-invalid-places.rs +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.rs @@ -16,8 +16,7 @@ struct S4(T) where for<'a> T: ?Trait<'a>; //~| ERROR bound modifier `?` can only be applied to `Sized` struct S5(*const T) where T: ?Trait<'static> + ?Sized; -//~^ ERROR type parameter has more than one relaxed default bound -//~| ERROR bound modifier `?` can only be applied to `Sized` +//~^ ERROR bound modifier `?` can only be applied to `Sized` impl S1 { fn f() where T: ?Sized {} //~ ERROR this relaxed bound is not permitted here @@ -33,4 +32,3 @@ type O2 = dyn ?Sized + ?Sized + Tr; //~| ERROR relaxed bounds are not permitted in trait object types fn main() {} - diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr index cfa0d274b26c..30285d626936 100644 --- a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr @@ -31,7 +31,7 @@ LL | struct S4(T) where for<'a> T: ?Trait<'a>; = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item error: this relaxed bound is not permitted here - --> $DIR/relaxed-bounds-invalid-places.rs:23:21 + --> $DIR/relaxed-bounds-invalid-places.rs:22:21 | LL | fn f() where T: ?Sized {} | ^^^^^^ @@ -39,7 +39,7 @@ LL | fn f() where T: ?Sized {} = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item error: relaxed bounds are not permitted in supertrait bounds - --> $DIR/relaxed-bounds-invalid-places.rs:26:11 + --> $DIR/relaxed-bounds-invalid-places.rs:25:11 | LL | trait Tr: ?Sized {} | ^^^^^^ @@ -47,19 +47,19 @@ LL | trait Tr: ?Sized {} = note: traits are `?Sized` by default error: relaxed bounds are not permitted in trait object types - --> $DIR/relaxed-bounds-invalid-places.rs:30:20 + --> $DIR/relaxed-bounds-invalid-places.rs:29:20 | LL | type O1 = dyn Tr + ?Sized; | ^^^^^^ error: relaxed bounds are not permitted in trait object types - --> $DIR/relaxed-bounds-invalid-places.rs:31:15 + --> $DIR/relaxed-bounds-invalid-places.rs:30:15 | LL | type O2 = dyn ?Sized + ?Sized + Tr; | ^^^^^^ error: relaxed bounds are not permitted in trait object types - --> $DIR/relaxed-bounds-invalid-places.rs:31:24 + --> $DIR/relaxed-bounds-invalid-places.rs:30:24 | LL | type O2 = dyn ?Sized + ?Sized + Tr; | ^^^^^^ @@ -70,21 +70,11 @@ error: bound modifier `?` can only be applied to `Sized` LL | struct S4(T) where for<'a> T: ?Trait<'a>; | ^^^^^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/relaxed-bounds-invalid-places.rs:18:33 - | -LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; - | ^^^^^^^^^^^^^^^ ^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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: bound modifier `?` can only be applied to `Sized` --> $DIR/relaxed-bounds-invalid-places.rs:18:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors -For more information about this error, try `rustc --explain E0203`. From 82a02aefe07092c737c852daccebf49ca25507e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 20 Jun 2025 23:13:11 +0200 Subject: [PATCH 315/363] HIR ty lowering: Validate `PointeeSized` bounds --- compiler/rustc_hir_analysis/messages.ftl | 2 - compiler/rustc_hir_analysis/src/errors.rs | 7 -- .../src/hir_ty_lowering/bounds.rs | 36 ++------- .../src/hir_ty_lowering/dyn_compatibility.rs | 8 -- .../src/hir_ty_lowering/errors.rs | 6 +- .../src/hir_ty_lowering/mod.rs | 49 ++++++------ .../ui/sized-hierarchy/pointee-validation.rs | 20 +++++ .../sized-hierarchy/pointee-validation.stderr | 76 +++++++++++++++++++ .../reject-dyn-pointeesized.rs | 4 +- .../reject-dyn-pointeesized.stderr | 5 +- 10 files changed, 135 insertions(+), 78 deletions(-) create mode 100644 tests/ui/sized-hierarchy/pointee-validation.rs create mode 100644 tests/ui/sized-hierarchy/pointee-validation.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 90cb17270340..7f55f9b2303d 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -445,8 +445,6 @@ hir_analysis_parenthesized_fn_trait_expansion = hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind} .label = not allowed in type signatures -hir_analysis_pointee_sized_trait_object = `PointeeSized` cannot be used with trait objects - hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias .label = `Self` is not a generic argument, but an alias to the type of the {$what} diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 3283ce95ee05..5e75a42e8245 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -311,13 +311,6 @@ pub(crate) struct TraitObjectDeclaredWithNoTraits { pub trait_alias_span: Option, } -#[derive(Diagnostic)] -#[diag(hir_analysis_pointee_sized_trait_object)] -pub(crate) struct PointeeSizedTraitObject { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(hir_analysis_ambiguous_lifetime_bound, code = E0227)] pub(crate) struct AmbiguousLifetimeBound { 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 dbd22fabab8b..d7a827c649dd 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -6,7 +6,7 @@ use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; -use rustc_hir::{AmbigArg, LangItem, PolyTraitRef}; +use rustc_hir::{AmbigArg, PolyTraitRef}; use rustc_middle::bug; use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -124,13 +124,13 @@ fn collect_sizedness_bounds<'tcx>( self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, span: Span, ) -> CollectedSizednessBounds { - let sized_did = tcx.require_lang_item(LangItem::Sized, span); + let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span); let sized = collect_bounds(hir_bounds, self_ty_where_predicates, sized_did); - let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span); + let meta_sized_did = tcx.require_lang_item(hir::LangItem::MetaSized, span); let meta_sized = collect_bounds(hir_bounds, self_ty_where_predicates, meta_sized_did); - let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span); + let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span); let pointee_sized = collect_bounds(hir_bounds, self_ty_where_predicates, pointee_sized_did); CollectedSizednessBounds { sized, meta_sized, pointee_sized } @@ -151,24 +151,6 @@ fn add_trait_bound<'tcx>( } impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { - /// Skip `PointeeSized` bounds. - /// - /// `PointeeSized` is a "fake bound" insofar as anywhere a `PointeeSized` bound exists, there - /// is actually the absence of any bounds. This avoids limitations around non-global where - /// clauses being preferred over item bounds (where `PointeeSized` bounds would be - /// proven) - which can result in errors when a `PointeeSized` supertrait/bound/predicate is - /// added to some items. - pub(crate) fn should_skip_sizedness_bound<'hir>( - &self, - bound: &'hir hir::GenericBound<'tcx>, - ) -> bool { - bound - .trait_ref() - .and_then(|tr| tr.trait_def_id()) - .map(|did| self.tcx().is_lang_item(did, LangItem::PointeeSized)) - .unwrap_or(false) - } - /// Adds sizedness bounds to a trait, trait alias, parameter, opaque type or associated type. /// /// - On parameters, opaque type and associated types, add default `Sized` bound if no explicit @@ -193,8 +175,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return; } - let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span); - let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span); + let meta_sized_did = tcx.require_lang_item(hir::LangItem::MetaSized, span); + let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span); // If adding sizedness bounds to a trait, then there are some relevant early exits if let Some(trait_did) = trait_did { @@ -244,7 +226,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } else { // If there are no explicit sizedness bounds on a parameter then add a default // `Sized` bound. - let sized_did = tcx.require_lang_item(LangItem::Sized, span); + let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span); add_trait_bound(tcx, bounds, self_ty, sized_did, span); } } @@ -476,10 +458,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { 'tcx: 'hir, { for hir_bound in hir_bounds { - if self.should_skip_sizedness_bound(hir_bound) { - continue; - } - // In order to avoid cycles, when we're lowering `SelfTraitThatDefines`, // we skip over any traits that don't define the given associated type. if let PredicateFilter::SelfTraitThatDefines(assoc_ident) = predicate_filter { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 813353c12aa0..76bb59e3f090 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -2,7 +2,6 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; -use rustc_hir::LangItem; use rustc_hir::def::{DefKind, Res}; use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS; use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan; @@ -70,13 +69,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let guar = self.report_trait_object_addition_traits(®ular_traits); return Ty::new_error(tcx, guar); } - // We don't support `PointeeSized` principals - let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span); - if regular_traits.iter().any(|(pred, _)| pred.def_id() == pointee_sized_did) { - let guar = self.report_pointee_sized_trait_object(span); - return Ty::new_error(tcx, guar); - } - // Don't create a dyn trait if we have errors in the principal. if let Err(guar) = regular_traits.error_reported() { return Ty::new_error(tcx, guar); 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 3db78db931ab..287a5532f016 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -29,7 +29,7 @@ use tracing::debug; use super::InherentAssocCandidate; use crate::errors::{ self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams, - ParenthesizedFnTraitExpansion, PointeeSizedTraitObject, TraitObjectDeclaredWithNoTraits, + ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits, }; use crate::fluent_generated as fluent; use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer}; @@ -1405,10 +1405,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }) } - - pub(super) fn report_pointee_sized_trait_object(&self, span: Span) -> ErrorGuaranteed { - self.dcx().emit_err(PointeeSizedTraitObject { span }) - } } /// Emit an error for the given associated item constraint. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 5521f97059b8..78794cd8eb68 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -755,6 +755,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, predicate_filter: PredicateFilter, ) -> GenericArgCountResult { + let tcx = self.tcx(); + // We use the *resolved* bound vars later instead of the HIR ones since the former // also include the bound vars of the overarching predicate if applicable. let hir::PolyTraitRef { bound_generic_params: _, modifiers, ref trait_ref, span } = @@ -762,6 +764,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let hir::TraitBoundModifiers { constness, polarity } = modifiers; let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); + + // Relaxed bounds `?Trait` and `PointeeSized` bounds aren't represented in the `middle::ty` IR + // as they denote the *absence* of a default bound. However, we can't bail out early here since + // we still need to perform several validation steps (see below). Instead, simply "pour" all + // resulting bounds "down the drain", i.e., into a new `Vec` that just gets dropped at the end. + let (polarity, bounds) = match polarity { + rustc_ast::BoundPolarity::Positive + if tcx.is_lang_item(trait_def_id, hir::LangItem::PointeeSized) => + { + // To elaborate on the comment directly above, regarding `PointeeSized` specifically, + // we don't "reify" such bounds to avoid trait system limitations -- namely, + // non-global where-clauses being preferred over item bounds (where `PointeeSized` + // bounds would be proven) -- which can result in errors when a `PointeeSized` + // supertrait / bound / predicate is added to some items. + (ty::PredicatePolarity::Positive, &mut Vec::new()) + } + rustc_ast::BoundPolarity::Positive => (ty::PredicatePolarity::Positive, bounds), + rustc_ast::BoundPolarity::Negative(_) => (ty::PredicatePolarity::Negative, bounds), + rustc_ast::BoundPolarity::Maybe(_) => { + (ty::PredicatePolarity::Positive, &mut Vec::new()) + } + }; + let trait_segment = trait_ref.path.segments.last().unwrap(); let _ = self.prohibit_generic_args( @@ -778,7 +803,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(self_ty), ); - let tcx = self.tcx(); let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id); debug!(?bound_vars); @@ -789,27 +813,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?poly_trait_ref); - let polarity = match polarity { - rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive, - rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative, - rustc_ast::BoundPolarity::Maybe(_) => { - // Validate associated type at least. We may want to reject these - // outright in the future... - for constraint in trait_segment.args().constraints { - let _ = self.lower_assoc_item_constraint( - trait_ref.hir_ref_id, - poly_trait_ref, - constraint, - &mut Default::default(), - &mut Default::default(), - constraint.span, - predicate_filter, - ); - } - return arg_count; - } - }; - // We deal with const conditions later. match predicate_filter { PredicateFilter::All @@ -912,7 +915,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Don't register any associated item constraints for negative bounds, // since we should have emitted an error for them earlier, and they // would not be well-formed! - if polarity != ty::PredicatePolarity::Positive { + if polarity == ty::PredicatePolarity::Negative { self.dcx().span_delayed_bug( constraint.span, "negative trait bounds should not have assoc item constraints", diff --git a/tests/ui/sized-hierarchy/pointee-validation.rs b/tests/ui/sized-hierarchy/pointee-validation.rs new file mode 100644 index 000000000000..dfc28829e08c --- /dev/null +++ b/tests/ui/sized-hierarchy/pointee-validation.rs @@ -0,0 +1,20 @@ +// Test that despite us dropping `PointeeSized` bounds during HIR ty lowering +// we still validate it first. +// issue: +#![feature(sized_hierarchy)] + +use std::marker::PointeeSized; + +struct T where (): PointeeSized<(), Undefined = ()>; +//~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied +//~| ERROR associated type `Undefined` not found for `PointeeSized` + +const fn test() where T: const PointeeSized, U: [const] PointeeSized {} +//~^ ERROR `const` can only be applied to `const` traits +//~| ERROR `const` can only be applied to `const` traits +//~| ERROR const trait impls are experimental +//~| ERROR `[const]` can only be applied to `const` traits +//~| ERROR `[const]` can only be applied to `const` traits +//~| ERROR const trait impls are experimental + +fn main() {} diff --git a/tests/ui/sized-hierarchy/pointee-validation.stderr b/tests/ui/sized-hierarchy/pointee-validation.stderr new file mode 100644 index 000000000000..a056d5483561 --- /dev/null +++ b/tests/ui/sized-hierarchy/pointee-validation.stderr @@ -0,0 +1,76 @@ +error[E0658]: const trait impls are experimental + --> $DIR/pointee-validation.rs:12:32 + | +LL | const fn test() where T: const PointeeSized, U: [const] PointeeSized {} + | ^^^^^ + | + = note: see issue #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 + +error[E0658]: const trait impls are experimental + --> $DIR/pointee-validation.rs:12:55 + | +LL | const fn test() where T: const PointeeSized, U: [const] PointeeSized {} + | ^^^^^^^ + | + = note: see issue #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 + +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/pointee-validation.rs:8:20 + | +LL | struct T where (): PointeeSized<(), Undefined = ()>; + | ^^^^^^^^^^^^-------------------- help: remove the unnecessary generics + | | + | expected 0 generic arguments + +error[E0220]: associated type `Undefined` not found for `PointeeSized` + --> $DIR/pointee-validation.rs:8:37 + | +LL | struct T where (): PointeeSized<(), Undefined = ()>; + | ^^^^^^^^^ associated type `Undefined` not found + +error: `const` can only be applied to `const` traits + --> $DIR/pointee-validation.rs:12:32 + | +LL | const fn test() where T: const PointeeSized, U: [const] PointeeSized {} + | ^^^^^ can't be applied to `PointeeSized` + | +note: `PointeeSized` can't be used with `const` because it isn't `const` + --> $SRC_DIR/core/src/marker.rs:LL:COL + +error: `[const]` can only be applied to `const` traits + --> $DIR/pointee-validation.rs:12:55 + | +LL | const fn test() where T: const PointeeSized, U: [const] PointeeSized {} + | ^^^^^^^ can't be applied to `PointeeSized` + | +note: `PointeeSized` can't be used with `[const]` because it isn't `const` + --> $SRC_DIR/core/src/marker.rs:LL:COL + +error: `const` can only be applied to `const` traits + --> $DIR/pointee-validation.rs:12:32 + | +LL | const fn test() where T: const PointeeSized, U: [const] PointeeSized {} + | ^^^^^ can't be applied to `PointeeSized` + | +note: `PointeeSized` can't be used with `const` because it isn't `const` + --> $SRC_DIR/core/src/marker.rs:LL:COL + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `[const]` can only be applied to `const` traits + --> $DIR/pointee-validation.rs:12:55 + | +LL | const fn test() where T: const PointeeSized, U: [const] PointeeSized {} + | ^^^^^^^ can't be applied to `PointeeSized` + | +note: `PointeeSized` can't be used with `[const]` because it isn't `const` + --> $SRC_DIR/core/src/marker.rs:LL:COL + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0107, E0220, E0658. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs index ece1702679d0..89e4c15371d4 100644 --- a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs +++ b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs @@ -3,7 +3,7 @@ use std::marker::PointeeSized; type Foo = dyn PointeeSized; -//~^ ERROR `PointeeSized` cannot be used with trait objects +//~^ ERROR at least one trait is required for an object type fn foo(f: &Foo) {} @@ -12,5 +12,5 @@ fn main() { let x = main; let y: Box = x; -//~^ ERROR `PointeeSized` cannot be used with trait objects +//~^ ERROR at least one trait is required for an object type } diff --git a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr index a833c6952fdc..616b2400f865 100644 --- a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr +++ b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr @@ -1,10 +1,10 @@ -error: `PointeeSized` cannot be used with trait objects +error[E0224]: at least one trait is required for an object type --> $DIR/reject-dyn-pointeesized.rs:5:12 | LL | type Foo = dyn PointeeSized; | ^^^^^^^^^^^^^^^^ -error: `PointeeSized` cannot be used with trait objects +error[E0224]: at least one trait is required for an object type --> $DIR/reject-dyn-pointeesized.rs:14:16 | LL | let y: Box = x; @@ -12,3 +12,4 @@ LL | let y: Box = x; error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0224`. From 466d33cb5cc79b74691db619d448f80a97baff61 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 15 Jul 2025 16:34:57 +0200 Subject: [PATCH 316/363] inline CrateLoader inside of CStore --- compiler/rustc_metadata/src/creader.rs | 286 +++++++++--------- .../rustc_resolve/src/build_reduced_graph.rs | 9 +- compiler/rustc_resolve/src/diagnostics.rs | 3 +- .../rustc_resolve/src/late/diagnostics.rs | 3 +- compiler/rustc_resolve/src/lib.rs | 26 +- 5 files changed, 169 insertions(+), 158 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index e65c7a684260..438eff330548 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -12,7 +12,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::owned_slice::OwnedSlice; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard}; -use rustc_errors::DiagCtxtHandle; use rustc_expand::base::SyntaxExtension; use rustc_fs_util::try_canonicalize; use rustc_hir as hir; @@ -23,8 +22,10 @@ use rustc_middle::bug; use rustc_middle::ty::data_structures::IndexSet; use rustc_middle::ty::{TyCtxt, TyCtxtFeed}; use rustc_proc_macro::bridge::client::ProcMacro; +use rustc_session::Session; use rustc_session::config::{ - CrateType, ExtendedTargetModifierInfo, ExternLocation, OptionsTargetModifiers, TargetModifier, + CrateType, ExtendedTargetModifierInfo, ExternLocation, Externs, OptionsTargetModifiers, + TargetModifier, }; use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource}; use rustc_session::lint::{self, BuiltinLintDiag}; @@ -70,6 +71,8 @@ pub struct CStore { /// Unused externs of the crate unused_externs: Vec, + + used_extern_options: FxHashSet, } impl std::fmt::Debug for CStore { @@ -78,28 +81,6 @@ impl std::fmt::Debug for CStore { } } -pub struct CrateLoader<'a, 'tcx: 'a> { - // Immutable configuration. - tcx: TyCtxt<'tcx>, - // Mutable output. - cstore: &'a mut CStore, - used_extern_options: &'a mut FxHashSet, -} - -impl<'a, 'tcx> std::ops::Deref for CrateLoader<'a, 'tcx> { - type Target = TyCtxt<'tcx>; - - fn deref(&self) -> &Self::Target { - &self.tcx - } -} - -impl<'a, 'tcx> CrateLoader<'a, 'tcx> { - fn dcx(&self) -> DiagCtxtHandle<'tcx> { - self.tcx.dcx() - } -} - pub enum LoadedMacro { MacroDef { def: MacroDef, @@ -227,8 +208,8 @@ impl CStore { fn intern_stable_crate_id<'tcx>( &mut self, - root: &CrateRoot, tcx: TyCtxt<'tcx>, + root: &CrateRoot, ) -> Result, CrateError> { assert_eq!(self.metas.len(), tcx.untracked().stable_crate_ids.read().len()); let num = tcx.create_crate_num(root.stable_crate_id()).map_err(|existing| { @@ -495,21 +476,18 @@ impl CStore { has_global_allocator: false, has_alloc_error_handler: false, unused_externs: Vec::new(), + used_extern_options: Default::default(), } } -} -impl<'a, 'tcx> CrateLoader<'a, 'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - cstore: &'a mut CStore, - used_extern_options: &'a mut FxHashSet, - ) -> Self { - CrateLoader { tcx, cstore, used_extern_options } - } - - fn existing_match(&self, name: Symbol, hash: Option, kind: PathKind) -> Option { - for (cnum, data) in self.cstore.iter_crate_data() { + fn existing_match( + &self, + externs: &Externs, + name: Symbol, + hash: Option, + kind: PathKind, + ) -> Option { + for (cnum, data) in self.iter_crate_data() { if data.name() != name { trace!("{} did not match {}", data.name(), name); continue; @@ -533,8 +511,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // We're also sure to compare *paths*, not actual byte slices. The // `source` stores paths which are normalized which may be different // from the strings on the command line. - let source = self.cstore.get_crate_data(cnum).cdata.source(); - if let Some(entry) = self.sess.opts.externs.get(name.as_str()) { + let source = self.get_crate_data(cnum).cdata.source(); + if let Some(entry) = externs.get(name.as_str()) { // Only use `--extern crate_name=path` here, not `--extern crate_name`. if let Some(mut files) = entry.files() { if files.any(|l| { @@ -587,6 +565,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { /// command parameter is set to `public-dependency` fn is_private_dep( &self, + externs: &Externs, name: Symbol, private_dep: Option, origin: CrateOrigin<'_>, @@ -595,7 +574,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { return true; } - let extern_private = self.sess.opts.externs.get(name.as_str()).map(|e| e.is_private_dep); + let extern_private = externs.get(name.as_str()).map(|e| e.is_private_dep); match (extern_private, private_dep) { // Explicit non-private via `--extern`, explicit non-private from metadata, or // unspecified with default to public. @@ -605,8 +584,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } } - fn register_crate( + fn register_crate<'tcx>( &mut self, + tcx: TyCtxt<'tcx>, host_lib: Option, origin: CrateOrigin<'_>, lib: Library, @@ -615,15 +595,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { private_dep: Option, ) -> Result { let _prof_timer = - self.sess.prof.generic_activity_with_arg("metadata_register_crate", name.as_str()); + tcx.sess.prof.generic_activity_with_arg("metadata_register_crate", name.as_str()); let Library { source, metadata } = lib; let crate_root = metadata.get_root(); let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash()); - let private_dep = self.is_private_dep(name, private_dep, origin); + let private_dep = self.is_private_dep(&tcx.sess.opts.externs, name, private_dep, origin); // Claim this crate number and cache it - let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?; + let feed = self.intern_stable_crate_id(tcx, &crate_root)?; let cnum = feed.key(); info!( @@ -643,8 +623,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { &crate_paths }; - let cnum_map = - self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind, private_dep)?; + let cnum_map = self.resolve_crate_deps( + tcx, + dep_root, + &crate_root, + &metadata, + cnum, + dep_kind, + private_dep, + )?; let raw_proc_macros = if crate_root.is_proc_macro_crate() { let temp_root; @@ -656,14 +643,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { None => (&source, &crate_root), }; let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate"); - Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.stable_crate_id())?) + Some(self.dlsym_proc_macros(tcx.sess, &dlsym_dylib.0, dlsym_root.stable_crate_id())?) } else { None }; let crate_metadata = CrateMetadata::new( - self.sess, - self.cstore, + tcx.sess, + self, metadata, crate_root, raw_proc_macros, @@ -675,13 +662,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { host_hash, ); - self.cstore.set_crate_data(cnum, crate_metadata); + self.set_crate_data(cnum, crate_metadata); Ok(cnum) } - fn load_proc_macro<'b>( + fn load_proc_macro<'a, 'b>( &self, + sess: &'a Session, locator: &mut CrateLocator<'b>, crate_rejections: &mut CrateRejections, path_kind: PathKind, @@ -690,13 +678,13 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { where 'a: 'b, { - if self.sess.opts.unstable_opts.dual_proc_macros { + if sess.opts.unstable_opts.dual_proc_macros { // Use a new crate locator and crate rejections so trying to load a proc macro doesn't // affect the error message we emit let mut proc_macro_locator = locator.clone(); // Try to load a proc macro - proc_macro_locator.for_target_proc_macro(self.sess, path_kind); + proc_macro_locator.for_target_proc_macro(sess, path_kind); // Load the proc macro crate for the target let target_result = @@ -713,7 +701,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { *crate_rejections = CrateRejections::default(); // Load the proc macro crate for the host - locator.for_proc_macro(self.sess, path_kind); + locator.for_proc_macro(sess, path_kind); locator.hash = host_hash; @@ -734,7 +722,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { let mut proc_macro_locator = locator.clone(); // Load the proc macro crate for the host - proc_macro_locator.for_proc_macro(self.sess, path_kind); + proc_macro_locator.for_proc_macro(sess, path_kind); let Some(host_result) = self.load(&mut proc_macro_locator, &mut CrateRejections::default())? @@ -746,32 +734,39 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } } - fn resolve_crate( + fn resolve_crate<'tcx>( &mut self, + tcx: TyCtxt<'tcx>, name: Symbol, span: Span, dep_kind: CrateDepKind, origin: CrateOrigin<'_>, ) -> Option { self.used_extern_options.insert(name); - match self.maybe_resolve_crate(name, dep_kind, origin) { + match self.maybe_resolve_crate(tcx, name, dep_kind, origin) { Ok(cnum) => { - self.cstore.set_used_recursively(cnum); + self.set_used_recursively(cnum); Some(cnum) } Err(err) => { debug!("failed to resolve crate {} {:?}", name, dep_kind); let missing_core = self - .maybe_resolve_crate(sym::core, CrateDepKind::Explicit, CrateOrigin::Extern) + .maybe_resolve_crate( + tcx, + sym::core, + CrateDepKind::Explicit, + CrateOrigin::Extern, + ) .is_err(); - err.report(self.sess, span, missing_core); + err.report(tcx.sess, span, missing_core); None } } } - fn maybe_resolve_crate<'b>( + fn maybe_resolve_crate<'b, 'tcx>( &'b mut self, + tcx: TyCtxt<'tcx>, name: Symbol, mut dep_kind: CrateDepKind, origin: CrateOrigin<'b>, @@ -789,17 +784,19 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate }; let private_dep = origin.private_dep(); - let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) { + let result = if let Some(cnum) = + self.existing_match(&tcx.sess.opts.externs, name, hash, path_kind) + { (LoadResult::Previous(cnum), None) } else { info!("falling back to a load"); let mut locator = CrateLocator::new( - self.sess, - &*self.cstore.metadata_loader, + tcx.sess, + &*self.metadata_loader, name, // The all loop is because `--crate-type=rlib --crate-type=rlib` is // legal and produces both inside this type. - self.tcx.crate_types().iter().all(|c| *c == CrateType::Rlib), + tcx.crate_types().iter().all(|c| *c == CrateType::Rlib), hash, extra_filename, path_kind, @@ -812,6 +809,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { info!("falling back to loading proc_macro"); dep_kind = CrateDepKind::MacrosOnly; match self.load_proc_macro( + tcx.sess, &mut locator, &mut crate_rejections, path_kind, @@ -831,8 +829,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // not specified by `--extern` on command line parameters, it may be // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to // `public-dependency` here. - let private_dep = self.is_private_dep(name, private_dep, origin); - let data = self.cstore.get_crate_data_mut(cnum); + let private_dep = + self.is_private_dep(&tcx.sess.opts.externs, name, private_dep, origin); + let data = self.get_crate_data_mut(cnum); if data.is_proc_macro_crate() { dep_kind = CrateDepKind::MacrosOnly; } @@ -842,7 +841,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } (LoadResult::Loaded(library), host_library) => { info!("register newly loaded library for `{}`", name); - self.register_crate(host_library, origin, library, dep_kind, name, private_dep) + self.register_crate(tcx, host_library, origin, library, dep_kind, name, private_dep) } _ => panic!(), } @@ -863,7 +862,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // duplicates by just using the first crate. let root = library.metadata.get_root(); let mut result = LoadResult::Loaded(library); - for (cnum, data) in self.cstore.iter_crate_data() { + for (cnum, data) in self.iter_crate_data() { if data.name() == root.name() && root.hash() == data.hash() { assert!(locator.hash.is_none()); info!("load success, going to previous cnum: {}", cnum); @@ -877,6 +876,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { /// Go through the crate metadata and load any crates that it references. fn resolve_crate_deps( &mut self, + tcx: TyCtxt<'_>, dep_root: &CratePaths, crate_root: &CrateRoot, metadata: &MetadataBlob, @@ -913,6 +913,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { _ => dep.kind, }; let cnum = self.maybe_resolve_crate( + tcx, dep.name, dep_kind, CrateOrigin::IndirectDependency { @@ -930,10 +931,11 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { fn dlsym_proc_macros( &self, + sess: &Session, path: &Path, stable_crate_id: StableCrateId, ) -> Result<&'static [ProcMacro], CrateError> { - let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id); + let sym_name = sess.generate_proc_macro_decls_symbol(stable_crate_id); debug!("trying to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name); unsafe { @@ -955,10 +957,10 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } } - fn inject_panic_runtime(&mut self, krate: &ast::Crate) { + fn inject_panic_runtime(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) { // If we're only compiling an rlib, then there's no need to select a // panic runtime, so we just skip this section entirely. - let only_rlib = self.tcx.crate_types().iter().all(|ct| *ct == CrateType::Rlib); + let only_rlib = tcx.crate_types().iter().all(|ct| *ct == CrateType::Rlib); if only_rlib { info!("panic runtime injection skipped, only generating rlib"); return; @@ -968,7 +970,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // the same time we perform some general validation of the DAG we've got // going such as ensuring everything has a compatible panic strategy. let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime); - for (_cnum, data) in self.cstore.iter_crate_data() { + for (_cnum, data) in self.iter_crate_data() { needs_panic_runtime |= data.needs_panic_runtime(); } @@ -987,7 +989,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // Also note that we have yet to perform validation of the crate graph // in terms of everyone has a compatible panic runtime format, that's // performed later as part of the `dependency_format` module. - let desired_strategy = self.sess.panic_strategy(); + let desired_strategy = tcx.sess.panic_strategy(); let name = match desired_strategy { PanicStrategy::Unwind => sym::panic_unwind, PanicStrategy::Abort => sym::panic_abort, @@ -995,64 +997,64 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { info!("panic runtime not found -- loading {}", name); let Some(cnum) = - self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected) + self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected) else { return; }; - let data = self.cstore.get_crate_data(cnum); + let data = self.get_crate_data(cnum); // Sanity check the loaded crate to ensure it is indeed a panic runtime // and the panic strategy is indeed what we thought it was. if !data.is_panic_runtime() { - self.dcx().emit_err(errors::CrateNotPanicRuntime { crate_name: name }); + tcx.dcx().emit_err(errors::CrateNotPanicRuntime { crate_name: name }); } if data.required_panic_strategy() != Some(desired_strategy) { - self.dcx() + tcx.dcx() .emit_err(errors::NoPanicStrategy { crate_name: name, strategy: desired_strategy }); } - self.cstore.injected_panic_runtime = Some(cnum); + self.injected_panic_runtime = Some(cnum); } - fn inject_profiler_runtime(&mut self) { + fn inject_profiler_runtime(&mut self, tcx: TyCtxt<'_>) { let needs_profiler_runtime = - self.sess.instrument_coverage() || self.sess.opts.cg.profile_generate.enabled(); - if !needs_profiler_runtime || self.sess.opts.unstable_opts.no_profiler_runtime { + tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled(); + if !needs_profiler_runtime || tcx.sess.opts.unstable_opts.no_profiler_runtime { return; } info!("loading profiler"); - let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime); + let name = Symbol::intern(&tcx.sess.opts.unstable_opts.profiler_runtime); let Some(cnum) = - self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected) + self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected) else { return; }; - let data = self.cstore.get_crate_data(cnum); + let data = self.get_crate_data(cnum); // Sanity check the loaded crate to ensure it is indeed a profiler runtime if !data.is_profiler_runtime() { - self.dcx().emit_err(errors::NotProfilerRuntime { crate_name: name }); + tcx.dcx().emit_err(errors::NotProfilerRuntime { crate_name: name }); } } - fn inject_allocator_crate(&mut self, krate: &ast::Crate) { - self.cstore.has_global_allocator = + fn inject_allocator_crate(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) { + self.has_global_allocator = match &*fn_spans(krate, Symbol::intern(&global_fn_name(sym::alloc))) { [span1, span2, ..] => { - self.dcx() + tcx.dcx() .emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 }); true } spans => !spans.is_empty(), }; - self.cstore.has_alloc_error_handler = match &*fn_spans( + self.has_alloc_error_handler = match &*fn_spans( krate, Symbol::intern(alloc_error_handler_name(AllocatorKind::Global)), ) { [span1, span2, ..] => { - self.dcx() + tcx.dcx() .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 }); true } @@ -1063,7 +1065,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // about through the `#![needs_allocator]` attribute and is typically // written down in liballoc. if !attr::contains_name(&krate.attrs, sym::needs_allocator) - && !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator()) + && !self.iter_crate_data().any(|(_, data)| data.needs_allocator()) { return; } @@ -1071,7 +1073,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // At this point we've determined that we need an allocator. Let's see // if our compilation session actually needs an allocator based on what // we're emitting. - let all_rlib = self.tcx.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib)); + let all_rlib = tcx.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib)); if all_rlib { return; } @@ -1086,12 +1088,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { #[allow(rustc::symbol_intern_string_literal)] let this_crate = Symbol::intern("this crate"); - let mut global_allocator = self.cstore.has_global_allocator.then_some(this_crate); - for (_, data) in self.cstore.iter_crate_data() { + let mut global_allocator = self.has_global_allocator.then_some(this_crate); + for (_, data) in self.iter_crate_data() { if data.has_global_allocator() { match global_allocator { Some(other_crate) => { - self.dcx().emit_err(errors::ConflictingGlobalAlloc { + tcx.dcx().emit_err(errors::ConflictingGlobalAlloc { crate_name: data.name(), other_crate_name: other_crate, }); @@ -1100,12 +1102,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } } } - let mut alloc_error_handler = self.cstore.has_alloc_error_handler.then_some(this_crate); - for (_, data) in self.cstore.iter_crate_data() { + let mut alloc_error_handler = self.has_alloc_error_handler.then_some(this_crate); + for (_, data) in self.iter_crate_data() { if data.has_alloc_error_handler() { match alloc_error_handler { Some(other_crate) => { - self.dcx().emit_err(errors::ConflictingAllocErrorHandler { + tcx.dcx().emit_err(errors::ConflictingAllocErrorHandler { crate_name: data.name(), other_crate_name: other_crate, }); @@ -1116,35 +1118,36 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } if global_allocator.is_some() { - self.cstore.allocator_kind = Some(AllocatorKind::Global); + self.allocator_kind = Some(AllocatorKind::Global); } else { // Ok we haven't found a global allocator but we still need an // allocator. At this point our allocator request is typically fulfilled // by the standard library, denoted by the `#![default_lib_allocator]` // attribute. if !attr::contains_name(&krate.attrs, sym::default_lib_allocator) - && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator()) + && !self.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator()) { - self.dcx().emit_err(errors::GlobalAllocRequired); + tcx.dcx().emit_err(errors::GlobalAllocRequired); } - self.cstore.allocator_kind = Some(AllocatorKind::Default); + self.allocator_kind = Some(AllocatorKind::Default); } if alloc_error_handler.is_some() { - self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global); + self.alloc_error_handler_kind = Some(AllocatorKind::Global); } else { // The alloc crate provides a default allocation error handler if // one isn't specified. - self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default); + self.alloc_error_handler_kind = Some(AllocatorKind::Default); } } - fn inject_forced_externs(&mut self) { - for (name, entry) in self.sess.opts.externs.iter() { + fn inject_forced_externs(&mut self, tcx: TyCtxt<'_>) { + for (name, entry) in tcx.sess.opts.externs.iter() { if entry.force { let name_interned = Symbol::intern(name); if !self.used_extern_options.contains(&name_interned) { self.resolve_crate( + tcx, name_interned, DUMMY_SP, CrateDepKind::Explicit, @@ -1156,7 +1159,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } /// Inject the `compiler_builtins` crate if it is not already in the graph. - fn inject_compiler_builtins(&mut self, krate: &ast::Crate) { + fn inject_compiler_builtins(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) { // `compiler_builtins` does not get extern builtins, nor do `#![no_core]` crates if attr::contains_name(&krate.attrs, sym::compiler_builtins) || attr::contains_name(&krate.attrs, sym::no_core) @@ -1167,7 +1170,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // If a `#![compiler_builtins]` crate already exists, avoid injecting it twice. This is // the common case since usually it appears as a dependency of `std` or `alloc`. - for (cnum, cmeta) in self.cstore.iter_crate_data() { + for (cnum, cmeta) in self.iter_crate_data() { if cmeta.is_compiler_builtins() { info!("`compiler_builtins` already exists (cnum = {cnum}); skipping injection"); return; @@ -1176,6 +1179,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // `compiler_builtins` is not yet in the graph; inject it. Error on resolution failure. let Some(cnum) = self.resolve_crate( + tcx, sym::compiler_builtins, krate.spans.inner_span.shrink_to_lo(), CrateDepKind::Explicit, @@ -1186,17 +1190,17 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { }; // Sanity check that the loaded crate is `#![compiler_builtins]` - let cmeta = self.cstore.get_crate_data(cnum); + let cmeta = self.get_crate_data(cnum); if !cmeta.is_compiler_builtins() { - self.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() }); + tcx.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() }); } } - fn report_unused_deps(&mut self, krate: &ast::Crate) { + fn report_unused_deps_in_crate(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) { // Make a point span rather than covering the whole file let span = krate.spans.inner_span.shrink_to_lo(); // Complain about anything left over - for (name, entry) in self.sess.opts.externs.iter() { + for (name, entry) in tcx.sess.opts.externs.iter() { if let ExternLocation::FoundInLibrarySearchDirectories = entry.location { // Don't worry about pathless `--extern foo` sysroot references continue; @@ -1211,25 +1215,25 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } // Got a real unused --extern - if self.sess.opts.json_unused_externs.is_enabled() { - self.cstore.unused_externs.push(name_interned); + if tcx.sess.opts.json_unused_externs.is_enabled() { + self.unused_externs.push(name_interned); continue; } - self.sess.psess.buffer_lint( + tcx.sess.psess.buffer_lint( lint::builtin::UNUSED_CRATE_DEPENDENCIES, span, ast::CRATE_NODE_ID, BuiltinLintDiag::UnusedCrateDependency { extern_crate: name_interned, - local_crate: self.tcx.crate_name(LOCAL_CRATE), + local_crate: tcx.crate_name(LOCAL_CRATE), }, ); } } - fn report_future_incompatible_deps(&self, krate: &ast::Crate) { - let name = self.tcx.crate_name(LOCAL_CRATE); + fn report_future_incompatible_deps(&self, tcx: TyCtxt<'_>, krate: &ast::Crate) { + let name = tcx.crate_name(LOCAL_CRATE); if name.as_str() == "wasm_bindgen" { let major = env::var("CARGO_PKG_VERSION_MAJOR") @@ -1257,26 +1261,27 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // Make a point span rather than covering the whole file let span = krate.spans.inner_span.shrink_to_lo(); - self.sess.dcx().emit_err(errors::WasmCAbi { span }); + tcx.sess.dcx().emit_err(errors::WasmCAbi { span }); } } - pub fn postprocess(&mut self, krate: &ast::Crate) { - self.inject_compiler_builtins(krate); - self.inject_forced_externs(); - self.inject_profiler_runtime(); - self.inject_allocator_crate(krate); - self.inject_panic_runtime(krate); + pub fn postprocess(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) { + self.inject_compiler_builtins(tcx, krate); + self.inject_forced_externs(tcx); + self.inject_profiler_runtime(tcx); + self.inject_allocator_crate(tcx, krate); + self.inject_panic_runtime(tcx, krate); - self.report_unused_deps(krate); - self.report_future_incompatible_deps(krate); + self.report_unused_deps_in_crate(tcx, krate); + self.report_future_incompatible_deps(tcx, krate); - info!("{:?}", CrateDump(self.cstore)); + info!("{:?}", CrateDump(self)); } /// Process an `extern crate foo` AST node. pub fn process_extern_crate( &mut self, + tcx: TyCtxt<'_>, item: &ast::Item, def_id: LocalDefId, definitions: &Definitions, @@ -1286,7 +1291,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { debug!("resolving extern crate stmt. ident: {} orig_name: {:?}", ident, orig_name); let name = match orig_name { Some(orig_name) => { - validate_crate_name(self.sess, orig_name, Some(item.span)); + validate_crate_name(tcx.sess, orig_name, Some(item.span)); orig_name } None => ident.name, @@ -1297,10 +1302,11 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { CrateDepKind::Explicit }; - let cnum = self.resolve_crate(name, item.span, dep_kind, CrateOrigin::Extern)?; + let cnum = + self.resolve_crate(tcx, name, item.span, dep_kind, CrateOrigin::Extern)?; let path_len = definitions.def_path(def_id).data.len(); - self.cstore.update_extern_crate( + self.update_extern_crate( cnum, ExternCrate { src: ExternCrateSource::Extern(def_id.to_def_id()), @@ -1315,10 +1321,16 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } } - pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option { - let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?; + pub fn process_path_extern( + &mut self, + tcx: TyCtxt<'_>, + name: Symbol, + span: Span, + ) -> Option { + let cnum = + self.resolve_crate(tcx, name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?; - self.cstore.update_extern_crate( + self.update_extern_crate( cnum, ExternCrate { src: ExternCrateSource::Path, @@ -1332,8 +1344,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { Some(cnum) } - pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option { - self.maybe_resolve_crate(name, CrateDepKind::Explicit, CrateOrigin::Extern).ok() + pub fn maybe_process_path_extern(&mut self, tcx: TyCtxt<'_>, name: Symbol) -> Option { + self.maybe_resolve_crate(tcx, name, CrateDepKind::Explicit, CrateOrigin::Extern).ok() } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index e56aabfd4144..737577baa7ad 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -897,9 +897,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { Some(self.r.graph_root) } else { let tcx = self.r.tcx; - let crate_id = self.r.crate_loader(|c| { - c.process_extern_crate(item, local_def_id, &tcx.definitions_untracked()) - }); + let crate_id = self.r.cstore_mut().process_extern_crate( + self.r.tcx, + item, + local_def_id, + &tcx.definitions_untracked(), + ); crate_id.map(|crate_id| { self.r.extern_crate_map.insert(local_def_id, crate_id); self.r.expect_module(crate_id.as_def_id()) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index f6f45adabe98..d72fbc189e70 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1425,7 +1425,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // otherwise cause duplicate suggestions. continue; } - let Some(crate_id) = self.crate_loader(|c| c.maybe_process_path_extern(ident.name)) + let Some(crate_id) = + self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) else { continue; }; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index ee462d907649..69095942f524 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2485,7 +2485,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let extern_prelude = self.r.extern_prelude.clone(); names.extend(extern_prelude.iter().flat_map(|(ident, _)| { self.r - .crate_loader(|c| c.maybe_process_path_extern(ident.name)) + .cstore_mut() + .maybe_process_path_extern(self.r.tcx, ident.name) .and_then(|crate_id| { let crate_mod = Res::Def(DefKind::Mod, crate_id.as_def_id()); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index dae30b77ec1c..0d41a822e8a8 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -45,7 +45,7 @@ use rustc_attr_data_structures::StrippedCfgItem; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::FreezeReadGuard; +use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed}; use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; @@ -58,7 +58,7 @@ use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, use rustc_hir::definitions::DisambiguatorState; use rustc_hir::{PrimTy, TraitCandidate}; use rustc_index::bit_set::DenseBitSet; -use rustc_metadata::creader::{CStore, CrateLoader}; +use rustc_metadata::creader::CStore; use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; @@ -1110,7 +1110,6 @@ pub struct Resolver<'ra, 'tcx> { builtin_types_bindings: FxHashMap>, builtin_attrs_bindings: FxHashMap>, registered_tool_bindings: FxHashMap>, - used_extern_options: FxHashSet, macro_names: FxHashSet, builtin_macros: FxHashMap, registered_tools: &'tcx RegisteredTools, @@ -1546,7 +1545,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (*ident, binding) }) .collect(), - used_extern_options: Default::default(), macro_names: FxHashSet::default(), builtin_macros: Default::default(), registered_tools, @@ -1733,18 +1731,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { StableHashingContext::new(self.tcx.sess, self.tcx.untracked()) } - fn crate_loader(&mut self, f: impl FnOnce(&mut CrateLoader<'_, '_>) -> T) -> T { - f(&mut CrateLoader::new( - self.tcx, - &mut CStore::from_tcx_mut(self.tcx), - &mut self.used_extern_options, - )) - } - fn cstore(&self) -> FreezeReadGuard<'_, CStore> { CStore::from_tcx(self.tcx) } + fn cstore_mut(&self) -> FreezeWriteGuard<'_, CStore> { + CStore::from_tcx_mut(self.tcx) + } + fn dummy_ext(&self, macro_kind: MacroKind) -> Arc { match macro_kind { MacroKind::Bang => Arc::clone(&self.dummy_ext_bang), @@ -1790,7 +1784,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.tcx.sess.time("resolve_report_errors", || self.report_errors(krate)); self.tcx .sess - .time("resolve_postprocess", || self.crate_loader(|c| c.postprocess(krate))); + .time("resolve_postprocess", || self.cstore_mut().postprocess(self.tcx, krate)); }); // Make sure we don't mutate the cstore from here on. @@ -2156,7 +2150,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(if let Some(binding) = entry.binding { if finalize { if !entry.is_import() { - self.crate_loader(|c| c.process_path_extern(ident.name, ident.span)); + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); } else if entry.introduced_by_item { self.record_use(ident, binding, Used::Other); } @@ -2165,13 +2159,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { let crate_id = if finalize { let Some(crate_id) = - self.crate_loader(|c| c.process_path_extern(ident.name, ident.span)) + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) else { return Some(self.dummy_binding); }; crate_id } else { - self.crate_loader(|c| c.maybe_process_path_extern(ident.name))? + self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)? }; let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT) From d5411f7664161a9845edc8b80f370327397e85fd Mon Sep 17 00:00:00 2001 From: Caiweiran Date: Fri, 18 Jul 2025 12:02:43 +0000 Subject: [PATCH 317/363] Ignore tests/run-make/link-eh-frame-terminator/rmake.rs when cross-compiling --- tests/run-make/link-eh-frame-terminator/rmake.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-make/link-eh-frame-terminator/rmake.rs b/tests/run-make/link-eh-frame-terminator/rmake.rs index 6bfae386ea1a..06b77f011ece 100644 --- a/tests/run-make/link-eh-frame-terminator/rmake.rs +++ b/tests/run-make/link-eh-frame-terminator/rmake.rs @@ -9,6 +9,7 @@ //@ ignore-32bit // Reason: the usage of a large array in the test causes an out-of-memory // error on 32 bit systems. +//@ ignore-cross-compile use run_make_support::{bin_name, llvm_objdump, run, rustc}; From 181c1bda0ef33c36e59628de6dd5c6ddf95f599f Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 10 Jul 2025 16:27:40 +0800 Subject: [PATCH 318/363] Deduplicate `unmatched_delims` in `rustc_parse` to reduce confusion Signed-off-by: xizheyin --- compiler/rustc_parse/src/lexer/diagnostics.rs | 20 ++++++++++++------- compiler/rustc_parse/src/lexer/tokentrees.rs | 15 ++++++++++++-- tests/ui/parser/deli-ident-issue-2.rs | 2 +- tests/ui/parser/deli-ident-issue-2.stderr | 12 +++-------- tests/ui/parser/issues/issue-104367.stderr | 1 - tests/ui/parser/issues/issue-105209.rs | 2 +- tests/ui/parser/issues/issue-105209.stderr | 9 ++++----- tests/ui/parser/issues/issue-62973.stderr | 6 ++---- tests/ui/parser/issues/issue-63116.stderr | 5 ++--- ...invalid-syntax-in-enum-discriminant.stderr | 12 ++++------- .../issues/issue-68987-unmatch-issue-2.rs | 2 +- .../issues/issue-68987-unmatch-issue-2.stderr | 12 +++-------- .../issues/issue-68987-unmatch-issue-3.rs | 2 +- .../issues/issue-68987-unmatch-issue-3.stderr | 12 +++-------- tests/ui/parser/issues/issue-81827.stderr | 5 ++--- .../issues/unnessary-error-issue-138401.rs | 3 +-- .../unnessary-error-issue-138401.stderr | 17 +++++----------- tests/ui/suggestions/issue-94171.stderr | 4 +--- tests/ui/typeck/issue-91334.stderr | 5 ++--- 19 files changed, 62 insertions(+), 84 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index 0b97d4e6993b..6de001fc9985 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -34,9 +34,12 @@ pub(super) fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Sp // When we get a `)` or `]` for `{`, we should emit help message here // it's more friendly compared to report `unmatched error` in later phase -fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDelim]) -> bool { +pub(super) fn report_missing_open_delim( + err: &mut Diag<'_>, + unmatched_delims: &mut Vec, +) -> bool { let mut reported_missing_open = false; - for unmatch_brace in unmatched_delims.iter() { + unmatched_delims.retain(|unmatch_brace| { if let Some(delim) = unmatch_brace.found_delim && matches!(delim, Delimiter::Parenthesis | Delimiter::Bracket) { @@ -45,13 +48,20 @@ fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDe Delimiter::Bracket => "[", _ => unreachable!(), }; + + if let Some(unclosed_span) = unmatch_brace.unclosed_span { + err.span_label(unclosed_span, "the nearest open delimiter"); + } err.span_label( unmatch_brace.found_span.shrink_to_lo(), format!("missing open `{missed_open}` for this delimiter"), ); reported_missing_open = true; + false + } else { + true } - } + }); reported_missing_open } @@ -61,10 +71,6 @@ pub(super) fn report_suspicious_mismatch_block( sm: &SourceMap, delim: Delimiter, ) { - if report_missing_open_delim(err, &diag_info.unmatched_delims) { - return; - } - let mut matched_spans: Vec<(Span, bool)> = diag_info .matching_block_spans .iter() diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index fbea958dcc59..64748199f28d 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -3,7 +3,9 @@ use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, Toke use rustc_ast_pretty::pprust::token_to_string; use rustc_errors::Diag; -use super::diagnostics::{report_suspicious_mismatch_block, same_indentation_level}; +use super::diagnostics::{ + report_missing_open_delim, report_suspicious_mismatch_block, same_indentation_level, +}; use super::{Lexer, UnmatchedDelim}; impl<'psess, 'src> Lexer<'psess, 'src> { @@ -244,7 +246,16 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let msg = format!("unexpected closing delimiter: `{token_str}`"); let mut err = self.dcx().struct_span_err(self.token.span, msg); - report_suspicious_mismatch_block(&mut err, &self.diag_info, self.psess.source_map(), delim); + // if there is no missing open delim, report suspicious mismatch block + if !report_missing_open_delim(&mut err, &mut self.diag_info.unmatched_delims) { + report_suspicious_mismatch_block( + &mut err, + &self.diag_info, + self.psess.source_map(), + delim, + ); + } + err.span_label(self.token.span, "unexpected closing delimiter"); err } diff --git a/tests/ui/parser/deli-ident-issue-2.rs b/tests/ui/parser/deli-ident-issue-2.rs index 5394760df702..419933c68ad6 100644 --- a/tests/ui/parser/deli-ident-issue-2.rs +++ b/tests/ui/parser/deli-ident-issue-2.rs @@ -1,6 +1,6 @@ fn main() { if 1 < 2 { - let _a = vec!]; //~ ERROR mismatched closing delimiter + let _a = vec!]; } } //~ ERROR unexpected closing delimiter diff --git a/tests/ui/parser/deli-ident-issue-2.stderr b/tests/ui/parser/deli-ident-issue-2.stderr index e0188cdfb4af..703cbf196267 100644 --- a/tests/ui/parser/deli-ident-issue-2.stderr +++ b/tests/ui/parser/deli-ident-issue-2.stderr @@ -1,19 +1,13 @@ -error: mismatched closing delimiter: `]` - --> $DIR/deli-ident-issue-2.rs:2:14 - | -LL | if 1 < 2 { - | ^ unclosed delimiter -LL | let _a = vec!]; - | ^ mismatched closing delimiter - error: unexpected closing delimiter: `}` --> $DIR/deli-ident-issue-2.rs:5:1 | +LL | if 1 < 2 { + | - the nearest open delimiter LL | let _a = vec!]; | - missing open `[` for this delimiter LL | } LL | } | ^ unexpected closing delimiter -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-104367.stderr b/tests/ui/parser/issues/issue-104367.stderr index c067d12e2d96..f01fa4a1265f 100644 --- a/tests/ui/parser/issues/issue-104367.stderr +++ b/tests/ui/parser/issues/issue-104367.stderr @@ -18,7 +18,6 @@ LL | d: [u32; { LL | #![cfg] { | - unclosed delimiter LL | #![w,) - | - missing open `(` for this delimiter LL | | ^ diff --git a/tests/ui/parser/issues/issue-105209.rs b/tests/ui/parser/issues/issue-105209.rs index f4e331523bf4..12c902e1d809 100644 --- a/tests/ui/parser/issues/issue-105209.rs +++ b/tests/ui/parser/issues/issue-105209.rs @@ -1,3 +1,3 @@ //@ compile-flags: -Zunpretty=ast-tree #![c={#![c[)x //~ ERROR mismatched closing delimiter - //~ ERROR this file contains an unclosed delimiter + //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/parser/issues/issue-105209.stderr b/tests/ui/parser/issues/issue-105209.stderr index 72017e4327de..75643d180292 100644 --- a/tests/ui/parser/issues/issue-105209.stderr +++ b/tests/ui/parser/issues/issue-105209.stderr @@ -7,16 +7,15 @@ LL | #![c={#![c[)x | unclosed delimiter error: this file contains an unclosed delimiter - --> $DIR/issue-105209.rs:3:68 + --> $DIR/issue-105209.rs:3:56 | LL | #![c={#![c[)x - | - - - - missing open `(` for this delimiter - | | | | - | | | unclosed delimiter + | - - - unclosed delimiter + | | | | | unclosed delimiter | unclosed delimiter LL | - | ^ + | ^ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-62973.stderr b/tests/ui/parser/issues/issue-62973.stderr index ea3e2bebee40..c7fc5bc29eda 100644 --- a/tests/ui/parser/issues/issue-62973.stderr +++ b/tests/ui/parser/issues/issue-62973.stderr @@ -18,10 +18,8 @@ error: this file contains an unclosed delimiter --> $DIR/issue-62973.rs:10:2 | LL | fn p() { match s { v, E { [) {) } - | - - - - missing open `(` for this delimiter - | | | | - | | | missing open `(` for this delimiter - | | unclosed delimiter + | - - unclosed delimiter + | | | unclosed delimiter LL | LL | diff --git a/tests/ui/parser/issues/issue-63116.stderr b/tests/ui/parser/issues/issue-63116.stderr index e5bad84d1126..736a0ac2cf61 100644 --- a/tests/ui/parser/issues/issue-63116.stderr +++ b/tests/ui/parser/issues/issue-63116.stderr @@ -10,9 +10,8 @@ error: this file contains an unclosed delimiter --> $DIR/issue-63116.rs:4:18 | LL | impl W $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:23:65 | -LL | V = [PhantomData; { [ () ].len() ].len() as isize, - | - missing open `[` for this delimiter -... -LL | V = [Vec::new; { [].len() ].len() as isize, - | - missing open `[` for this delimiter -... LL | mod c { | - unclosed delimiter LL | enum Bug { -LL | V = [Vec::new; { [0].len() ].len() as isize, - | - missing open `[` for this delimiter + | - this delimiter might not be properly closed... ... +LL | } + | - ...as it matches this but it has different indentation +LL | LL | fn main() {} | ^ diff --git a/tests/ui/parser/issues/issue-68987-unmatch-issue-2.rs b/tests/ui/parser/issues/issue-68987-unmatch-issue-2.rs index 89aaa68ba409..9b4452ed2a1a 100644 --- a/tests/ui/parser/issues/issue-68987-unmatch-issue-2.rs +++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-2.rs @@ -1,7 +1,7 @@ // FIXME: this case need more work to fix // currently the TokenTree matching ')' with '{', which is not user friendly for diagnostics async fn obstest() -> Result<> { - let obs_connect = || -> Result<(), MyError) { //~ ERROR mismatched closing delimiter + let obs_connect = || -> Result<(), MyError) { async { } } diff --git a/tests/ui/parser/issues/issue-68987-unmatch-issue-2.stderr b/tests/ui/parser/issues/issue-68987-unmatch-issue-2.stderr index 0ecb748a0a4c..c29a4ff8dbe6 100644 --- a/tests/ui/parser/issues/issue-68987-unmatch-issue-2.stderr +++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-2.stderr @@ -1,19 +1,13 @@ -error: mismatched closing delimiter: `)` - --> $DIR/issue-68987-unmatch-issue-2.rs:3:32 - | -LL | async fn obstest() -> Result<> { - | ^ unclosed delimiter -LL | let obs_connect = || -> Result<(), MyError) { - | ^ mismatched closing delimiter - error: unexpected closing delimiter: `}` --> $DIR/issue-68987-unmatch-issue-2.rs:14:1 | +LL | async fn obstest() -> Result<> { + | - the nearest open delimiter LL | let obs_connect = || -> Result<(), MyError) { | - missing open `(` for this delimiter ... LL | } | ^ unexpected closing delimiter -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-68987-unmatch-issue-3.rs b/tests/ui/parser/issues/issue-68987-unmatch-issue-3.rs index e98df8d7c3c4..e71e2730980e 100644 --- a/tests/ui/parser/issues/issue-68987-unmatch-issue-3.rs +++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-3.rs @@ -3,6 +3,6 @@ fn f(i: u32, j: u32) { let res = String::new(); let mut cnt = i; while cnt < j { - write!&mut res, " "); //~ ERROR mismatched closing delimiter + write!&mut res, " "); } } //~ ERROR unexpected closing delimiter diff --git a/tests/ui/parser/issues/issue-68987-unmatch-issue-3.stderr b/tests/ui/parser/issues/issue-68987-unmatch-issue-3.stderr index dfc4407ed656..6b012af1af31 100644 --- a/tests/ui/parser/issues/issue-68987-unmatch-issue-3.stderr +++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-3.stderr @@ -1,19 +1,13 @@ -error: mismatched closing delimiter: `)` - --> $DIR/issue-68987-unmatch-issue-3.rs:5:19 - | -LL | while cnt < j { - | ^ unclosed delimiter -LL | write!&mut res, " "); - | ^ mismatched closing delimiter - error: unexpected closing delimiter: `}` --> $DIR/issue-68987-unmatch-issue-3.rs:8:1 | +LL | while cnt < j { + | - the nearest open delimiter LL | write!&mut res, " "); | - missing open `(` for this delimiter LL | } LL | } | ^ unexpected closing delimiter -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-81827.stderr b/tests/ui/parser/issues/issue-81827.stderr index 986ed6b7e70f..9737c8c90ae7 100644 --- a/tests/ui/parser/issues/issue-81827.stderr +++ b/tests/ui/parser/issues/issue-81827.stderr @@ -11,9 +11,8 @@ error: this file contains an unclosed delimiter --> $DIR/issue-81827.rs:7:27 | LL | fn r()->i{0|{#[cfg(r(0{]0 - | - - - ^ - | | | | - | | | missing open `[` for this delimiter + | - - ^ + | | | | | unclosed delimiter | unclosed delimiter diff --git a/tests/ui/parser/issues/unnessary-error-issue-138401.rs b/tests/ui/parser/issues/unnessary-error-issue-138401.rs index e5e5f1ee4e9c..208c516365a8 100644 --- a/tests/ui/parser/issues/unnessary-error-issue-138401.rs +++ b/tests/ui/parser/issues/unnessary-error-issue-138401.rs @@ -1,6 +1,5 @@ pub fn foo(x: i64) -> i64 { - x.abs) - //~^ ERROR mismatched closing delimiter + x.abs) } //~^ ERROR unexpected closing delimiter: `}` diff --git a/tests/ui/parser/issues/unnessary-error-issue-138401.stderr b/tests/ui/parser/issues/unnessary-error-issue-138401.stderr index b50f77f1247c..54c73b50a42a 100644 --- a/tests/ui/parser/issues/unnessary-error-issue-138401.stderr +++ b/tests/ui/parser/issues/unnessary-error-issue-138401.stderr @@ -1,19 +1,12 @@ -error: mismatched closing delimiter: `)` - --> $DIR/unnessary-error-issue-138401.rs:1:27 +error: unexpected closing delimiter: `}` + --> $DIR/unnessary-error-issue-138401.rs:3:1 | LL | pub fn foo(x: i64) -> i64 { - | ^ unclosed delimiter -LL | x.abs) - | ^ mismatched closing delimiter - -error: unexpected closing delimiter: `}` - --> $DIR/unnessary-error-issue-138401.rs:4:1 - | -LL | x.abs) + | - the nearest open delimiter +LL | x.abs) | - missing open `(` for this delimiter -LL | LL | } | ^ unexpected closing delimiter -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/issue-94171.stderr b/tests/ui/suggestions/issue-94171.stderr index bcbd46cd8ecd..52306a2465f1 100644 --- a/tests/ui/suggestions/issue-94171.stderr +++ b/tests/ui/suggestions/issue-94171.stderr @@ -22,9 +22,7 @@ error: this file contains an unclosed delimiter --> $DIR/issue-94171.rs:5:52 | LL | fn L(]{match - | -- unclosed delimiter - | | - | missing open `[` for this delimiter + | - unclosed delimiter LL | (; {` | - - unclosed delimiter | | diff --git a/tests/ui/typeck/issue-91334.stderr b/tests/ui/typeck/issue-91334.stderr index 01e34919ce67..a348e1ebf7e5 100644 --- a/tests/ui/typeck/issue-91334.stderr +++ b/tests/ui/typeck/issue-91334.stderr @@ -11,9 +11,8 @@ error: this file contains an unclosed delimiter --> $DIR/issue-91334.rs:7:23 | LL | fn f(){||yield(((){), - | - - - ^ - | | | | - | | | missing open `(` for this delimiter + | - - ^ + | | | | | unclosed delimiter | unclosed delimiter From c65d3ce365ecb6d6f36b413edb591d4746f52305 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 3 Jul 2025 08:00:47 +0000 Subject: [PATCH 319/363] Generalize `unsize` and `unsize_into` destinations --- compiler/rustc_const_eval/src/interpret/cast.rs | 7 ++++--- compiler/rustc_mir_transform/src/gvn.rs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 7a73d70fc85d..de4fbc7b4752 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -17,6 +17,7 @@ use super::{ throw_ub_custom, }; use crate::fluent_generated as fluent; +use crate::interpret::Writeable; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn cast( @@ -358,7 +359,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fn unsize_into_ptr( &mut self, src: &OpTy<'tcx, M::Provenance>, - dest: &PlaceTy<'tcx, M::Provenance>, + dest: &impl Writeable<'tcx, M::Provenance>, // The pointee types source_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, @@ -455,7 +456,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &mut self, src: &OpTy<'tcx, M::Provenance>, cast_ty: TyAndLayout<'tcx>, - dest: &PlaceTy<'tcx, M::Provenance>, + dest: &impl Writeable<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty); match (src.layout.ty.kind(), cast_ty.ty.kind()) { @@ -496,7 +497,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.cur_span(), "unsize_into: invalid conversion: {:?} -> {:?}", src.layout, - dest.layout + dest.layout() ) } } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 07717b7c0694..6657f89ceb59 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -579,7 +579,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) => { let src = self.evaluated[value].as_ref()?; let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; - self.ecx.unsize_into(src, ty, &dest.clone().into()).discard_err()?; + self.ecx.unsize_into(src, ty, &dest).discard_err()?; self.ecx .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) .discard_err()?; From 15acb0e0ec849453d9db928821cecc552bb51bfd Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 18 Jul 2025 13:43:24 +0000 Subject: [PATCH 320/363] unicode-table-gen: clippy fixes --- .../src/cascading_map.rs | 14 +++++------ .../src/case_mapping.rs | 2 +- src/tools/unicode-table-generator/src/main.rs | 24 +++++++++---------- .../src/raw_emitter.rs | 23 +++++++----------- 4 files changed, 28 insertions(+), 35 deletions(-) diff --git a/src/tools/unicode-table-generator/src/cascading_map.rs b/src/tools/unicode-table-generator/src/cascading_map.rs index 1eb35e819c07..78a7bba32087 100644 --- a/src/tools/unicode-table-generator/src/cascading_map.rs +++ b/src/tools/unicode-table-generator/src/cascading_map.rs @@ -21,7 +21,7 @@ impl RawEmitter { let points = ranges .iter() - .flat_map(|r| (r.start..r.end).into_iter().collect::>()) + .flat_map(|r| (r.start..r.end).collect::>()) .collect::>(); println!("there are {} points", points.len()); @@ -32,21 +32,20 @@ impl RawEmitter { // assert that there is no whitespace over the 0x3000 range. assert!(point <= 0x3000, "the highest unicode whitespace value has changed"); let high_bytes = point as usize >> 8; - let codepoints = codepoints_by_high_bytes.entry(high_bytes).or_insert_with(Vec::new); + let codepoints = codepoints_by_high_bytes.entry(high_bytes).or_default(); codepoints.push(point); } let mut bit_for_high_byte = 1u8; let mut arms = Vec::::new(); - let mut high_bytes: Vec = - codepoints_by_high_bytes.keys().map(|k| k.clone()).collect(); + let mut high_bytes: Vec = codepoints_by_high_bytes.keys().copied().collect(); high_bytes.sort(); for high_byte in high_bytes { let codepoints = codepoints_by_high_bytes.get_mut(&high_byte).unwrap(); if codepoints.len() == 1 { let ch = codepoints.pop().unwrap(); - arms.push(format!("{} => c as u32 == {:#04x}", high_byte, ch)); + arms.push(format!("{high_byte} => c as u32 == {ch:#04x}")); continue; } // more than 1 codepoint in this arm @@ -54,8 +53,7 @@ impl RawEmitter { map[(*codepoint & 0xff) as usize] |= bit_for_high_byte; } arms.push(format!( - "{} => WHITESPACE_MAP[c as usize & 0xff] & {} != 0", - high_byte, bit_for_high_byte + "{high_byte} => WHITESPACE_MAP[c as usize & 0xff] & {bit_for_high_byte} != 0" )); bit_for_high_byte <<= 1; } @@ -68,7 +66,7 @@ impl RawEmitter { writeln!(&mut self.file, "pub const fn lookup(c: char) -> bool {{").unwrap(); writeln!(&mut self.file, " match c as u32 >> 8 {{").unwrap(); for arm in arms { - writeln!(&mut self.file, " {},", arm).unwrap(); + writeln!(&mut self.file, " {arm},").unwrap(); } writeln!(&mut self.file, " _ => false,").unwrap(); writeln!(&mut self.file, " }}").unwrap(); diff --git a/src/tools/unicode-table-generator/src/case_mapping.rs b/src/tools/unicode-table-generator/src/case_mapping.rs index 00241b7ee0eb..9c6454492e7e 100644 --- a/src/tools/unicode-table-generator/src/case_mapping.rs +++ b/src/tools/unicode-table-generator/src/case_mapping.rs @@ -9,7 +9,7 @@ const INDEX_MASK: u32 = 1 << 22; pub(crate) fn generate_case_mapping(data: &UnicodeData) -> String { let mut file = String::new(); - write!(file, "const INDEX_MASK: u32 = 0x{:x};", INDEX_MASK).unwrap(); + write!(file, "const INDEX_MASK: u32 = 0x{INDEX_MASK:x};").unwrap(); file.push_str("\n\n"); file.push_str(HEADER.trim_start()); file.push('\n'); diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs index 415db2c4dbc0..00f8c1f6ec34 100644 --- a/src/tools/unicode-table-generator/src/main.rs +++ b/src/tools/unicode-table-generator/src/main.rs @@ -196,12 +196,12 @@ fn load_data() -> UnicodeData { .flat_map(|codepoints| match codepoints { Codepoints::Single(c) => c .scalar() - .map(|ch| (ch as u32..ch as u32 + 1)) + .map(|ch| ch as u32..ch as u32 + 1) .into_iter() .collect::>(), Codepoints::Range(c) => c .into_iter() - .flat_map(|c| c.scalar().map(|ch| (ch as u32..ch as u32 + 1))) + .flat_map(|c| c.scalar().map(|ch| ch as u32..ch as u32 + 1)) .collect::>(), }) .collect::>>(), @@ -236,7 +236,7 @@ fn main() { let ranges_by_property = &unicode_data.ranges; if let Some(path) = test_path { - std::fs::write(&path, generate_tests(&write_location, &ranges_by_property)).unwrap(); + std::fs::write(&path, generate_tests(&write_location, ranges_by_property)).unwrap(); } let mut total_bytes = 0; @@ -246,9 +246,9 @@ fn main() { let mut emitter = RawEmitter::new(); if property == &"White_Space" { - emit_whitespace(&mut emitter, &ranges); + emit_whitespace(&mut emitter, ranges); } else { - emit_codepoints(&mut emitter, &ranges); + emit_codepoints(&mut emitter, ranges); } modules.push((property.to_lowercase().to_string(), emitter.file)); @@ -288,7 +288,7 @@ fn main() { for line in contents.lines() { if !line.trim().is_empty() { table_file.push_str(" "); - table_file.push_str(&line); + table_file.push_str(line); } table_file.push('\n'); } @@ -312,7 +312,7 @@ fn version() -> String { let start = readme.find(prefix).unwrap() + prefix.len(); let end = readme.find(" of the Unicode Standard.").unwrap(); let version = - readme[start..end].split('.').map(|v| v.parse::().expect(&v)).collect::>(); + readme[start..end].split('.').map(|v| v.parse::().expect(v)).collect::>(); let [major, minor, micro] = [version[0], version[1], version[2]]; out.push_str(&format!("({major}, {minor}, {micro});\n")); @@ -320,7 +320,7 @@ fn version() -> String { } fn fmt_list(values: impl IntoIterator) -> String { - let pieces = values.into_iter().map(|b| format!("{:?}, ", b)).collect::>(); + let pieces = values.into_iter().map(|b| format!("{b:?}, ")).collect::>(); let mut out = String::new(); let mut line = String::from("\n "); for piece in pieces { @@ -348,7 +348,7 @@ fn generate_tests(data_path: &str, ranges: &[(&str, Vec>)]) -> String s.push_str("\nfn main() {\n"); for (property, ranges) in ranges { - s.push_str(&format!(r#" println!("Testing {}");"#, property)); + s.push_str(&format!(r#" println!("Testing {property}");"#)); s.push('\n'); s.push_str(&format!(" {}_true();\n", property.to_lowercase())); s.push_str(&format!(" {}_false();\n", property.to_lowercase())); @@ -373,7 +373,7 @@ fn generate_tests(data_path: &str, ranges: &[(&str, Vec>)]) -> String s.push_str(" }\n\n"); } - s.push_str("}"); + s.push('}'); s } @@ -388,7 +388,7 @@ fn generate_asserts(s: &mut String, property: &str, points: &[u32], truthy: bool range.start, )); } else { - s.push_str(&format!(" for chn in {:?}u32 {{\n", range)); + s.push_str(&format!(" for chn in {range:?}u32 {{\n")); s.push_str(&format!( " assert!({}unicode_data::{}::lookup(std::char::from_u32(chn).unwrap()), \"{{:?}}\", chn);\n", if truthy { "" } else { "!" }, @@ -439,7 +439,7 @@ fn merge_ranges(ranges: &mut Vec>) { let mut last_end = None; for range in ranges { if let Some(last) = last_end { - assert!(range.start > last, "{:?}", range); + assert!(range.start > last, "{range:?}"); } last_end = Some(range.end); } diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs index ee94d3c93a6c..e1e77af9283d 100644 --- a/src/tools/unicode-table-generator/src/raw_emitter.rs +++ b/src/tools/unicode-table-generator/src/raw_emitter.rs @@ -156,10 +156,10 @@ pub fn emit_codepoints(emitter: &mut RawEmitter, ranges: &[Range]) { emitter.blank_line(); let mut bitset = emitter.clone(); - let bitset_ok = bitset.emit_bitset(&ranges).is_ok(); + let bitset_ok = bitset.emit_bitset(ranges).is_ok(); let mut skiplist = emitter.clone(); - skiplist.emit_skiplist(&ranges); + skiplist.emit_skiplist(ranges); if bitset_ok && bitset.bytes_used <= skiplist.bytes_used { *emitter = bitset; @@ -174,7 +174,7 @@ pub fn emit_whitespace(emitter: &mut RawEmitter, ranges: &[Range]) { emitter.blank_line(); let mut cascading = emitter.clone(); - cascading.emit_cascading_map(&ranges); + cascading.emit_cascading_map(ranges); *emitter = cascading; emitter.desc = String::from("cascading"); } @@ -311,10 +311,9 @@ impl Canonicalized { } } } - assert!( - unique_mapping - .insert(to, UniqueMapping::Canonical(canonical_words.len())) - .is_none() + assert_eq!( + unique_mapping.insert(to, UniqueMapping::Canonical(canonical_words.len())), + None ); canonical_words.push(to); @@ -340,14 +339,10 @@ impl Canonicalized { // We'll probably always have some slack though so this loop will still // be needed. for &w in unique_words { - if !unique_mapping.contains_key(&w) { - assert!( - unique_mapping - .insert(w, UniqueMapping::Canonical(canonical_words.len())) - .is_none() - ); + unique_mapping.entry(w).or_insert_with(|| { canonical_words.push(w); - } + UniqueMapping::Canonical(canonical_words.len()) + }); } assert_eq!(canonicalized_words.len() + canonical_words.len(), unique_words.len()); assert_eq!(unique_mapping.len(), unique_words.len()); From 09593059867b066d23776e00a2ce31c370ec9277 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 18 Jul 2025 13:45:33 +0000 Subject: [PATCH 321/363] unicode-table-gen: edition 2024 --- src/tools/unicode-table-generator/Cargo.toml | 2 +- src/tools/unicode-table-generator/src/raw_emitter.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/unicode-table-generator/Cargo.toml b/src/tools/unicode-table-generator/Cargo.toml index f8a500922d05..3ca6e9e316f1 100644 --- a/src/tools/unicode-table-generator/Cargo.toml +++ b/src/tools/unicode-table-generator/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "unicode-table-generator" version = "0.1.0" -edition = "2021" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs index e1e77af9283d..e9e0efc45944 100644 --- a/src/tools/unicode-table-generator/src/raw_emitter.rs +++ b/src/tools/unicode-table-generator/src/raw_emitter.rs @@ -272,7 +272,7 @@ impl Canonicalized { // for canonical when possible. while let Some((&to, _)) = mappings .iter() - .find(|(&to, _)| to == 0) + .find(|&(&to, _)| to == 0) .or_else(|| mappings.iter().max_by_key(|m| m.1.len())) { // Get the mapping with the most entries. Currently, no mapping can From b0073d92fbb5402ff7bed69f28aab4b34b05a9df Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 18 Jul 2025 13:51:18 +0000 Subject: [PATCH 322/363] unicode-table-gen: more clippy fixes --- src/tools/unicode-table-generator/src/main.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs index 00f8c1f6ec34..6cdb82a87bdf 100644 --- a/src/tools/unicode-table-generator/src/main.rs +++ b/src/tools/unicode-table-generator/src/main.rs @@ -160,15 +160,15 @@ fn load_data() -> UnicodeData { .push(Codepoints::Single(row.codepoint)); } - if let Some(mapped) = row.simple_lowercase_mapping { - if mapped != row.codepoint { - to_lower.insert(row.codepoint.value(), (mapped.value(), 0, 0)); - } + if let Some(mapped) = row.simple_lowercase_mapping + && mapped != row.codepoint + { + to_lower.insert(row.codepoint.value(), (mapped.value(), 0, 0)); } - if let Some(mapped) = row.simple_uppercase_mapping { - if mapped != row.codepoint { - to_upper.insert(row.codepoint.value(), (mapped.value(), 0, 0)); - } + if let Some(mapped) = row.simple_uppercase_mapping + && mapped != row.codepoint + { + to_upper.insert(row.codepoint.value(), (mapped.value(), 0, 0)); } } From 4d1695103f15ec885ced2eef25cdc9fd08332b66 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 18 Jul 2025 11:26:44 -0400 Subject: [PATCH 323/363] Comment some tests in the m68k CI because we cannot run programs on architectures not supported by the object crate anymore --- .github/workflows/m68k.yml | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 176ee8628b09..759d0d59e268 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -91,7 +91,11 @@ jobs: ./y.sh prepare --only-libcore --cross ./y.sh build --sysroot --features compiler-builtins-no-f16-f128 --target-triple m68k-unknown-linux-gnu ./y.sh test --mini-tests --target-triple m68k-unknown-linux-gnu - CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu ./y.sh test --cargo-tests --target-triple m68k-unknown-linux-gnu + # FIXME: since https://github.com/rust-lang/rust/pull/140809, we cannot run programs for architectures not + # supported by the object crate, since this adds a dependency on symbols.o for the panic runtime. + # And as such, a wrong order of the object files in the linker command now fails with an undefined reference + # to some symbols like __rustc::rust_panic. + #CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu ./y.sh test --cargo-tests --target-triple m68k-unknown-linux-gnu ./y.sh clean all - name: Prepare dependencies @@ -100,21 +104,23 @@ jobs: git config --global user.name "User" ./y.sh prepare --cross - - name: Run tests - run: | - ./y.sh test --target-triple m68k-unknown-linux-gnu --release --clean --build-sysroot --sysroot-features compiler-builtins-no-f16-f128 ${{ matrix.commands }} + # FIXME: We cannot run programs for architectures not supported by the object crate. See comment above. + #- name: Run tests + #run: | + #./y.sh test --target-triple m68k-unknown-linux-gnu --release --clean --build-sysroot --sysroot-features compiler-builtins-no-f16-f128 ${{ matrix.commands }} - - name: Run Hello World! - run: | - ./y.sh build --target-triple m68k-unknown-linux-gnu + # FIXME: We cannot run programs for architectures not supported by the object crate. See comment above. + #- name: Run Hello World! + #run: | + #./y.sh build --target-triple m68k-unknown-linux-gnu - vm_dir=$(pwd)/vm - cd tests/hello-world - CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../../y.sh cargo build --target m68k-unknown-linux-gnu - sudo cp target/m68k-unknown-linux-gnu/debug/hello_world $vm_dir/home/ - sudo chroot $vm_dir qemu-m68k-static /home/hello_world > hello_world_stdout - expected_output="40" - test $(cat hello_world_stdout) == $expected_output || (echo "Output differs. Actual output: $(cat hello_world_stdout)"; exit 1) + #vm_dir=$(pwd)/vm + #cd tests/hello-world + #CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../../y.sh cargo build --target m68k-unknown-linux-gnu + #sudo cp target/m68k-unknown-linux-gnu/debug/hello_world $vm_dir/home/ + #sudo chroot $vm_dir qemu-m68k-static /home/hello_world > hello_world_stdout + #expected_output="40" + #test $(cat hello_world_stdout) == $expected_output || (echo "Output differs. Actual output: $(cat hello_world_stdout)"; exit 1) # Summary job for the merge queue. # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! From 3b9c16bc0e90e57ed4ff548a50a577ea4dd7a50c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 9 Jul 2025 20:00:59 +0000 Subject: [PATCH 324/363] Be a bit more careful around exotic cycles in in the inliner --- .../rustc_mir_transform/src/inline/cycle.rs | 44 ++++++++++------- ...ine_double_cycle.a.Inline.panic-abort.diff | 48 +++++++++++++++++++ ...ne_double_cycle.a.Inline.panic-unwind.diff | 48 +++++++++++++++++++ ...ine_double_cycle.b.Inline.panic-abort.diff | 48 +++++++++++++++++++ ...ne_double_cycle.b.Inline.panic-unwind.diff | 48 +++++++++++++++++++ tests/mir-opt/inline_double_cycle.rs | 22 +++++++++ 6 files changed, 242 insertions(+), 16 deletions(-) create mode 100644 tests/mir-opt/inline_double_cycle.a.Inline.panic-abort.diff create mode 100644 tests/mir-opt/inline_double_cycle.a.Inline.panic-unwind.diff create mode 100644 tests/mir-opt/inline_double_cycle.b.Inline.panic-abort.diff create mode 100644 tests/mir-opt/inline_double_cycle.b.Inline.panic-unwind.diff create mode 100644 tests/mir-opt/inline_double_cycle.rs diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 93a81f0dca51..7f9234d1dc89 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -64,15 +64,15 @@ fn process<'tcx>( typing_env: ty::TypingEnv<'tcx>, caller: ty::Instance<'tcx>, target: LocalDefId, - seen: &mut FxHashSet>, + seen: &mut FxHashMap, bool>, involved: &mut FxHashSet, recursion_limiter: &mut FxHashMap, recursion_limit: Limit, ) -> bool { trace!(%caller); - let mut cycle_found = false; + let mut reaches_root = false; - for &(callee, args) in tcx.mir_inliner_callees(caller.def) { + for &(callee_def_id, args) in tcx.mir_inliner_callees(caller.def) { let Ok(args) = caller.try_instantiate_mir_and_normalize_erasing_regions( tcx, typing_env, @@ -81,14 +81,17 @@ fn process<'tcx>( trace!(?caller, ?typing_env, ?args, "cannot normalize, skipping"); continue; }; - let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, typing_env, callee, args) else { - trace!(?callee, "cannot resolve, skipping"); + let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, typing_env, callee_def_id, args) + else { + trace!(?callee_def_id, "cannot resolve, skipping"); continue; }; // Found a path. if callee.def_id() == target.to_def_id() { - cycle_found = true; + reaches_root = true; + seen.insert(callee, true); + continue; } if tcx.is_constructor(callee.def_id()) { @@ -101,10 +104,17 @@ fn process<'tcx>( continue; } - if seen.insert(callee) { + let callee_reaches_root = if let Some(&c) = seen.get(&callee) { + // Even if we have seen this callee before, and thus don't need + // to recurse into it, we still need to propagate whether it reaches + // the root so that we can mark all the involved callers, in case we + // end up reaching that same recursive callee through some *other* cycle. + c + } else { + seen.insert(callee, false); let recursion = recursion_limiter.entry(callee.def_id()).or_default(); trace!(?callee, recursion = *recursion); - let found_recursion = if recursion_limit.value_within_limit(*recursion) { + let callee_reaches_root = if recursion_limit.value_within_limit(*recursion) { *recursion += 1; ensure_sufficient_stack(|| { process( @@ -122,17 +132,19 @@ fn process<'tcx>( // Pessimistically assume that there could be recursion. true }; - if found_recursion { - if let Some(callee) = callee.def_id().as_local() { - // Calling `optimized_mir` of a non-local definition cannot cycle. - involved.insert(callee); - } - cycle_found = true; + seen.insert(callee, callee_reaches_root); + callee_reaches_root + }; + if callee_reaches_root { + if let Some(callee_def_id) = callee.def_id().as_local() { + // Calling `optimized_mir` of a non-local definition cannot cycle. + involved.insert(callee_def_id); } + reaches_root = true; } } - cycle_found + reaches_root } #[instrument(level = "debug", skip(tcx), ret)] @@ -166,7 +178,7 @@ pub(crate) fn mir_callgraph_cyclic<'tcx>( typing_env, root_instance, root, - &mut FxHashSet::default(), + &mut FxHashMap::default(), &mut involved, &mut FxHashMap::default(), recursion_limit, diff --git a/tests/mir-opt/inline_double_cycle.a.Inline.panic-abort.diff b/tests/mir-opt/inline_double_cycle.a.Inline.panic-abort.diff new file mode 100644 index 000000000000..90a4a509ac12 --- /dev/null +++ b/tests/mir-opt/inline_double_cycle.a.Inline.panic-abort.diff @@ -0,0 +1,48 @@ +- // MIR for `a` before Inline ++ // MIR for `a` after Inline + + fn a() -> () { + let mut _0: (); + let _1: (); + let mut _2: (); + let _3: (); + let mut _4: (); ++ let mut _5: fn() {a}; ++ let mut _6: fn() {b}; ++ scope 1 (inlined >::call_once - shim(fn() {a})) { ++ } ++ scope 2 (inlined >::call_once - shim(fn() {b})) { ++ } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (); +- _1 = >::call_once(a, move _2) -> [return: bb1, unwind unreachable]; ++ StorageLive(_5); ++ _5 = a; ++ _1 = move _5() -> [return: bb1, unwind unreachable]; + } + + bb1: { ++ StorageDead(_5); + StorageDead(_2); + StorageDead(_1); + StorageLive(_3); + StorageLive(_4); + _4 = (); +- _3 = >::call_once(b, move _4) -> [return: bb2, unwind unreachable]; ++ StorageLive(_6); ++ _6 = b; ++ _3 = move _6() -> [return: bb2, unwind unreachable]; + } + + bb2: { ++ StorageDead(_6); + StorageDead(_4); + StorageDead(_3); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline_double_cycle.a.Inline.panic-unwind.diff b/tests/mir-opt/inline_double_cycle.a.Inline.panic-unwind.diff new file mode 100644 index 000000000000..55da685a3d43 --- /dev/null +++ b/tests/mir-opt/inline_double_cycle.a.Inline.panic-unwind.diff @@ -0,0 +1,48 @@ +- // MIR for `a` before Inline ++ // MIR for `a` after Inline + + fn a() -> () { + let mut _0: (); + let _1: (); + let mut _2: (); + let _3: (); + let mut _4: (); ++ let mut _5: fn() {a}; ++ let mut _6: fn() {b}; ++ scope 1 (inlined >::call_once - shim(fn() {a})) { ++ } ++ scope 2 (inlined >::call_once - shim(fn() {b})) { ++ } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (); +- _1 = >::call_once(a, move _2) -> [return: bb1, unwind continue]; ++ StorageLive(_5); ++ _5 = a; ++ _1 = move _5() -> [return: bb1, unwind continue]; + } + + bb1: { ++ StorageDead(_5); + StorageDead(_2); + StorageDead(_1); + StorageLive(_3); + StorageLive(_4); + _4 = (); +- _3 = >::call_once(b, move _4) -> [return: bb2, unwind continue]; ++ StorageLive(_6); ++ _6 = b; ++ _3 = move _6() -> [return: bb2, unwind continue]; + } + + bb2: { ++ StorageDead(_6); + StorageDead(_4); + StorageDead(_3); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline_double_cycle.b.Inline.panic-abort.diff b/tests/mir-opt/inline_double_cycle.b.Inline.panic-abort.diff new file mode 100644 index 000000000000..2090411276cf --- /dev/null +++ b/tests/mir-opt/inline_double_cycle.b.Inline.panic-abort.diff @@ -0,0 +1,48 @@ +- // MIR for `b` before Inline ++ // MIR for `b` after Inline + + fn b() -> () { + let mut _0: (); + let _1: (); + let mut _2: (); + let _3: (); + let mut _4: (); ++ let mut _5: fn() {b}; ++ let mut _6: fn() {a}; ++ scope 1 (inlined >::call_once - shim(fn() {b})) { ++ } ++ scope 2 (inlined >::call_once - shim(fn() {a})) { ++ } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (); +- _1 = >::call_once(b, move _2) -> [return: bb1, unwind unreachable]; ++ StorageLive(_5); ++ _5 = b; ++ _1 = move _5() -> [return: bb1, unwind unreachable]; + } + + bb1: { ++ StorageDead(_5); + StorageDead(_2); + StorageDead(_1); + StorageLive(_3); + StorageLive(_4); + _4 = (); +- _3 = >::call_once(a, move _4) -> [return: bb2, unwind unreachable]; ++ StorageLive(_6); ++ _6 = a; ++ _3 = move _6() -> [return: bb2, unwind unreachable]; + } + + bb2: { ++ StorageDead(_6); + StorageDead(_4); + StorageDead(_3); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline_double_cycle.b.Inline.panic-unwind.diff b/tests/mir-opt/inline_double_cycle.b.Inline.panic-unwind.diff new file mode 100644 index 000000000000..9e6eef1fa304 --- /dev/null +++ b/tests/mir-opt/inline_double_cycle.b.Inline.panic-unwind.diff @@ -0,0 +1,48 @@ +- // MIR for `b` before Inline ++ // MIR for `b` after Inline + + fn b() -> () { + let mut _0: (); + let _1: (); + let mut _2: (); + let _3: (); + let mut _4: (); ++ let mut _5: fn() {b}; ++ let mut _6: fn() {a}; ++ scope 1 (inlined >::call_once - shim(fn() {b})) { ++ } ++ scope 2 (inlined >::call_once - shim(fn() {a})) { ++ } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (); +- _1 = >::call_once(b, move _2) -> [return: bb1, unwind continue]; ++ StorageLive(_5); ++ _5 = b; ++ _1 = move _5() -> [return: bb1, unwind continue]; + } + + bb1: { ++ StorageDead(_5); + StorageDead(_2); + StorageDead(_1); + StorageLive(_3); + StorageLive(_4); + _4 = (); +- _3 = >::call_once(a, move _4) -> [return: bb2, unwind continue]; ++ StorageLive(_6); ++ _6 = a; ++ _3 = move _6() -> [return: bb2, unwind continue]; + } + + bb2: { ++ StorageDead(_6); + StorageDead(_4); + StorageDead(_3); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline_double_cycle.rs b/tests/mir-opt/inline_double_cycle.rs new file mode 100644 index 000000000000..cf3b87cf0ad3 --- /dev/null +++ b/tests/mir-opt/inline_double_cycle.rs @@ -0,0 +1,22 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// skip-filecheck +//@ test-mir-pass: Inline +//@ edition: 2021 +//@ compile-flags: -Zinline-mir --crate-type=lib + +// EMIT_MIR inline_double_cycle.a.Inline.diff +// EMIT_MIR inline_double_cycle.b.Inline.diff + +#![feature(fn_traits)] + +#[inline] +pub fn a() { + FnOnce::call_once(a, ()); + FnOnce::call_once(b, ()); +} + +#[inline] +pub fn b() { + FnOnce::call_once(b, ()); + FnOnce::call_once(a, ()); +} From 8a8717e971dbdc6155506a4332e9ce8ef9151caa Mon Sep 17 00:00:00 2001 From: Luigi Sartor Piucco Date: Sun, 20 Apr 2025 18:43:54 -0300 Subject: [PATCH 325/363] fix: don't panic on volatile access to null According to https://discourse.llvm.org/t/rfc-volatile-access-to-non-dereferenceable-memory-may-be-well-defined/86303/4, LLVM allows volatile operations on null and handles it correctly. This should be allowed in Rust as well, because I/O memory may be hard-coded to address 0 in some cases, like the AVR chip ATtiny1626. A test case that ensured a failure when passing null to volatile was removed, since it's now valid. Due to the addition of `maybe_is_aligned` to `ub_checks`, `maybe_is_aligned_and_not_null` was refactored to use it. docs: revise restrictions on volatile operations A distinction between usage on Rust memory vs. non-Rust memory was introduced. Documentation was reworded to explain what that means, and make explicit that: - No trapping can occur from volatile operations; - On Rust memory, all safety rules must be respected; - On Rust memory, the primary difference from regular access is that volatile always involves a memory dereference; - On Rust memory, the only data affected by an operation is the one pointed to in the argument(s) of the function; - On Rust memory, provenance follows the same rules as non-volatile access; - On non-Rust memory, any address known to not contain Rust memory is valid (including 0 and usize::MAX); - On non-Rust memory, no Rust memory may be affected (it is implicit that any other non-Rust memory may be affected, though, even if not referenced by the pointer). This should be relevant when, for example, reading register A causes a flag to change in register B, or writing to A causes B to change in some way. Everything affected mustn't be inside an allocation. - On non-Rust memory, provenance is irrelevant and a pointer with none can be used in a valid way. fix: don't lint null as UB for volatile Also remove a now-unneeded `allow` line. fix: additional wording nits --- compiler/rustc_lint/src/ptr_nulls.rs | 4 +- library/core/src/ptr/mod.rs | 146 ++++++++++-------- library/core/src/ub_checks.rs | 18 ++- tests/ui/lint/invalid_null_args.rs | 5 +- tests/ui/lint/invalid_null_args.stderr | 58 ++----- tests/ui/precondition-checks/read_volatile.rs | 6 +- .../ui/precondition-checks/write_volatile.rs | 6 +- 7 files changed, 116 insertions(+), 127 deletions(-) diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs index 826bce2c3150..b2fa0fba76d9 100644 --- a/compiler/rustc_lint/src/ptr_nulls.rs +++ b/compiler/rustc_lint/src/ptr_nulls.rs @@ -160,12 +160,10 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { let (arg_indices, are_zsts_allowed): (&[_], _) = match diag_name { sym::ptr_read | sym::ptr_read_unaligned - | sym::ptr_read_volatile | sym::ptr_replace | sym::ptr_write | sym::ptr_write_bytes - | sym::ptr_write_unaligned - | sym::ptr_write_volatile => (&[0], true), + | sym::ptr_write_unaligned => (&[0], true), sym::slice_from_raw_parts | sym::slice_from_raw_parts_mut => (&[0], false), sym::ptr_copy | sym::ptr_copy_nonoverlapping diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index fe8c6f830341..dbe3999b4a43 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -28,7 +28,8 @@ //! undefined behavior to perform two concurrent accesses to the same location from different //! threads unless both accesses only read from memory. Notice that this explicitly //! includes [`read_volatile`] and [`write_volatile`]: Volatile accesses cannot -//! be used for inter-thread synchronization. +//! be used for inter-thread synchronization, regardless of whether they are acting on +//! Rust memory or not. //! * The result of casting a reference to a pointer is valid for as long as the //! underlying allocation is live and no reference (just raw pointers) is used to //! access the same memory. That is, reference and pointer accesses cannot be @@ -114,6 +115,10 @@ //! fully contiguous (i.e., has no "holes"), there is no guarantee that this //! will not change in the future. //! +//! Allocations must behave like "normal" memory: in particular, reads must not have +//! side-effects, and writes must become visible to other threads using the usual synchronization +//! primitives. +//! //! For any allocation with `base` address, `size`, and a set of //! `addresses`, the following are guaranteed: //! - For all addresses `a` in `addresses`, `a` is in the range `base .. (base + @@ -2021,54 +2026,61 @@ pub const unsafe fn write_unaligned(dst: *mut T, src: T) { } } -/// Performs a volatile read of the value from `src` without moving it. This -/// leaves the memory in `src` unchanged. +/// Performs a volatile read of the value from `src` without moving it. /// -/// Volatile operations are intended to act on I/O memory, and are guaranteed -/// to not be elided or reordered by the compiler across other volatile -/// operations. +/// Volatile operations are intended to act on I/O memory. As such, they are considered externally +/// observable events (just like syscalls, but less opaque), and are guaranteed to not be elided or +/// reordered by the compiler across other externally observable events. With this in mind, there +/// are two cases of usage that need to be distinguished: /// -/// # Notes +/// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like +/// [`read`], except for the additional guarantee that it won't be elided or reordered (see +/// above). This implies that the operation will actually access memory and not e.g. be lowered to +/// reusing data from a previous read. Other than that, all the usual rules for memory accesses +/// apply (including provenance). In particular, just like in C, whether an operation is volatile +/// has no bearing whatsoever on questions involving concurrent accesses from multiple threads. +/// Volatile accesses behave exactly like non-atomic accesses in that regard. /// -/// Rust does not currently have a rigorously and formally defined memory model, -/// so the precise semantics of what "volatile" means here is subject to change -/// over time. That being said, the semantics will almost always end up pretty -/// similar to [C11's definition of volatile][c11]. +/// - Volatile operations, however, may also be used to access memory that is _outside_ of any Rust +/// allocation. In this use-case, the pointer does *not* have to be [valid] for reads. This is +/// typically used for CPU and peripheral registers that must be accessed via an I/O memory +/// mapping, most commonly at fixed addresses reserved by the hardware. These often have special +/// semantics associated to their manipulation, and cannot be used as general purpose memory. +/// Here, any address value is possible, including 0 and [`usize::MAX`], so long as the semantics +/// of such a read are well-defined by the target hardware. The provenance of the pointer is +/// irrelevant, and it can be created with [`without_provenance`]. The access must not trap. It +/// can cause side-effects, but those must not affect Rust-allocated memory in any way. This +/// access is still not considered [atomic], and as such it cannot be used for inter-thread +/// synchronization. /// -/// The compiler shouldn't change the relative order or number of volatile -/// memory operations. However, volatile memory operations on zero-sized types -/// (e.g., if a zero-sized type is passed to `read_volatile`) are noops -/// and may be ignored. +/// Note that volatile memory operations where T is a zero-sized type are noops and may be ignored. /// -/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf +/// [allocation]: crate::ptr#allocated-object +/// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses /// /// # Safety /// +/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of whether `T` is +/// [`Copy`]. If `T` is not [`Copy`], using both the returned value and the value at `*src` can +/// [violate memory safety][read-ownership]. However, storing non-[`Copy`] types in volatile memory +/// is almost certainly incorrect. +/// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `src` must be [valid] for reads. +/// * `src` must be either [valid] for reads, or it must point to memory outside of all Rust +/// allocations and reading from that memory must: +/// - not trap, and +/// - not cause any memory inside a Rust allocation to be modified. /// /// * `src` must be properly aligned. /// -/// * `src` must point to a properly initialized value of type `T`. -/// -/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of -/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned -/// value and the value at `*src` can [violate memory safety][read-ownership]. -/// However, storing non-[`Copy`] types in volatile memory is almost certainly -/// incorrect. +/// * Reading from `src` must produce a properly initialized value of type `T`. /// /// Note that even if `T` has size `0`, the pointer must be properly aligned. /// /// [valid]: self#safety /// [read-ownership]: read#ownership-of-the-returned-value /// -/// Just like in C, whether an operation is volatile has no bearing whatsoever -/// on questions involving concurrent access from multiple threads. Volatile -/// accesses behave exactly like non-atomic accesses in that regard. In particular, -/// a race between a `read_volatile` and any write operation to the same location -/// is undefined behavior. -/// /// # Examples /// /// Basic usage: @@ -2090,50 +2102,63 @@ pub unsafe fn read_volatile(src: *const T) -> T { unsafe { ub_checks::assert_unsafe_precondition!( check_language_ub, - "ptr::read_volatile requires that the pointer argument is aligned and non-null", + "ptr::read_volatile requires that the pointer argument is aligned", ( addr: *const () = src as *const (), align: usize = align_of::(), - is_zst: bool = T::IS_ZST, - ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned(addr, align) ); intrinsics::volatile_load(src) } } -/// Performs a volatile write of a memory location with the given value without -/// reading or dropping the old value. +/// Performs a volatile write of a memory location with the given value without reading or dropping +/// the old value. /// -/// Volatile operations are intended to act on I/O memory, and are guaranteed -/// to not be elided or reordered by the compiler across other volatile -/// operations. +/// Volatile operations are intended to act on I/O memory. As such, they are considered externally +/// observable events (just like syscalls), and are guaranteed to not be elided or reordered by the +/// compiler across other externally observable events. With this in mind, there are two cases of +/// usage that need to be distinguished: /// -/// `write_volatile` does not drop the contents of `dst`. This is safe, but it -/// could leak allocations or resources, so care should be taken not to overwrite -/// an object that should be dropped. +/// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like +/// [`write`][write()], except for the additional guarantee that it won't be elided or reordered +/// (see above). This implies that the operation will actually access memory and not e.g. be +/// lowered to a register access. Other than that, all the usual rules for memory accesses apply +/// (including provenance). In particular, just like in C, whether an operation is volatile has no +/// bearing whatsoever on questions involving concurrent access from multiple threads. Volatile +/// accesses behave exactly like non-atomic accesses in that regard. /// -/// Additionally, it does not drop `src`. Semantically, `src` is moved into the -/// location pointed to by `dst`. +/// - Volatile operations, however, may also be used to access memory that is _outside_ of any Rust +/// allocation. In this use-case, the pointer does *not* have to be [valid] for writes. This is +/// typically used for CPU and peripheral registers that must be accessed via an I/O memory +/// mapping, most commonly at fixed addresses reserved by the hardware. These often have special +/// semantics associated to their manipulation, and cannot be used as general purpose memory. +/// Here, any address value is possible, including 0 and [`usize::MAX`], so long as the semantics +/// of such a write are well-defined by the target hardware. The provenance of the pointer is +/// irrelevant, and it can be created with [`without_provenance`]. The access must not trap. It +/// can cause side-effects, but those must not affect Rust-allocated memory in any way. This +/// access is still not considered [atomic], and as such it cannot be used for inter-thread +/// synchronization. /// -/// # Notes +/// Note that volatile memory operations on zero-sized types (e.g., if a zero-sized type is passed +/// to `write_volatile`) are noops and may be ignored. /// -/// Rust does not currently have a rigorously and formally defined memory model, -/// so the precise semantics of what "volatile" means here is subject to change -/// over time. That being said, the semantics will almost always end up pretty -/// similar to [C11's definition of volatile][c11]. +/// `write_volatile` does not drop the contents of `dst`. This is safe, but it could leak +/// allocations or resources, so care should be taken not to overwrite an object that should be +/// dropped when operating on Rust memory. Additionally, it does not drop `src`. Semantically, `src` +/// is moved into the location pointed to by `dst`. /// -/// The compiler shouldn't change the relative order or number of volatile -/// memory operations. However, volatile memory operations on zero-sized types -/// (e.g., if a zero-sized type is passed to `write_volatile`) are noops -/// and may be ignored. -/// -/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf +/// [allocation]: crate::ptr#allocated-object +/// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses /// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `dst` must be [valid] for writes. +/// * `dst` must be either [valid] for writes, or it must point to memory outside of all Rust +/// allocations and writing to that memory must: +/// - not trap, and +/// - not cause any memory inside a Rust allocation to be modified. /// /// * `dst` must be properly aligned. /// @@ -2141,12 +2166,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// [valid]: self#safety /// -/// Just like in C, whether an operation is volatile has no bearing whatsoever -/// on questions involving concurrent access from multiple threads. Volatile -/// accesses behave exactly like non-atomic accesses in that regard. In particular, -/// a race between a `write_volatile` and any other operation (reading or writing) -/// on the same location is undefined behavior. -/// /// # Examples /// /// Basic usage: @@ -2170,12 +2189,11 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { unsafe { ub_checks::assert_unsafe_precondition!( check_language_ub, - "ptr::write_volatile requires that the pointer argument is aligned and non-null", + "ptr::write_volatile requires that the pointer argument is aligned", ( addr: *mut () = dst as *mut (), align: usize = align_of::(), - is_zst: bool = T::IS_ZST, - ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned(addr, align) ); intrinsics::volatile_store(dst, src); } diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index a7caaeb95cdb..b809294cfcee 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -120,13 +120,25 @@ pub(crate) const fn maybe_is_aligned_and_not_null( align: usize, is_zst: bool, ) -> bool { + // This is just for safety checks so we can const_eval_select. + maybe_is_aligned(ptr, align) && (is_zst || !ptr.is_null()) +} + +/// Checks whether `ptr` is properly aligned with respect to the given alignment. +/// +/// In `const` this is approximate and can fail spuriously. It is primarily intended +/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the +/// check is anyway not executed in `const`. +#[inline] +#[rustc_allow_const_fn_unstable(const_eval_select)] +pub(crate) const fn maybe_is_aligned(ptr: *const (), align: usize) -> bool { // This is just for safety checks so we can const_eval_select. const_eval_select!( - @capture { ptr: *const (), align: usize, is_zst: bool } -> bool: + @capture { ptr: *const (), align: usize } -> bool: if const { - is_zst || !ptr.is_null() + true } else { - ptr.is_aligned_to(align) && (is_zst || !ptr.is_null()) + ptr.is_aligned_to(align) } ) } diff --git a/tests/ui/lint/invalid_null_args.rs b/tests/ui/lint/invalid_null_args.rs index f40f06a0d362..ee29d622ad7b 100644 --- a/tests/ui/lint/invalid_null_args.rs +++ b/tests/ui/lint/invalid_null_args.rs @@ -58,10 +58,9 @@ unsafe fn null_ptr() { let _a: A = ptr::read_unaligned(ptr::null_mut()); //~^ ERROR calling this function with a null pointer is undefined behavior + // These two should *not* fire the lint. let _a: A = ptr::read_volatile(ptr::null()); - //~^ ERROR calling this function with a null pointer is undefined behavior let _a: A = ptr::read_volatile(ptr::null_mut()); - //~^ ERROR calling this function with a null pointer is undefined behavior let _a: A = ptr::replace(ptr::null_mut(), v); //~^ ERROR calling this function with a null pointer is undefined behavior @@ -82,8 +81,8 @@ unsafe fn null_ptr() { ptr::write_unaligned(ptr::null_mut(), v); //~^ ERROR calling this function with a null pointer is undefined behavior + // This one should *not* fire the lint. ptr::write_volatile(ptr::null_mut(), v); - //~^ ERROR calling this function with a null pointer is undefined behavior ptr::write_bytes::(ptr::null_mut(), 42, 0); //~^ ERROR calling this function with a null pointer is undefined behavior diff --git a/tests/ui/lint/invalid_null_args.stderr b/tests/ui/lint/invalid_null_args.stderr index 11c6270cfb78..028bd7051dcc 100644 --- a/tests/ui/lint/invalid_null_args.stderr +++ b/tests/ui/lint/invalid_null_args.stderr @@ -164,27 +164,7 @@ LL | let _a: A = ptr::read_unaligned(ptr::null_mut()); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:61:17 - | -LL | let _a: A = ptr::read_volatile(ptr::null()); - | ^^^^^^^^^^^^^^^^^^^-----------^ - | | - | null pointer originates from here - | - = help: for more information, visit and - -error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:63:17 - | -LL | let _a: A = ptr::read_volatile(ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^---------------^ - | | - | null pointer originates from here - | - = help: for more information, visit and - -error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:66:17 + --> $DIR/invalid_null_args.rs:65:17 | LL | let _a: A = ptr::replace(ptr::null_mut(), v); | ^^^^^^^^^^^^^---------------^^^^ @@ -194,7 +174,7 @@ LL | let _a: A = ptr::replace(ptr::null_mut(), v); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:69:5 + --> $DIR/invalid_null_args.rs:68:5 | LL | ptr::swap::(ptr::null_mut(), &mut v); | ^^^^^^^^^^^^^^^---------------^^^^^^^^^ @@ -204,7 +184,7 @@ LL | ptr::swap::(ptr::null_mut(), &mut v); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:71:5 + --> $DIR/invalid_null_args.rs:70:5 | LL | ptr::swap::(&mut v, ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ @@ -214,7 +194,7 @@ LL | ptr::swap::(&mut v, ptr::null_mut()); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:74:5 + --> $DIR/invalid_null_args.rs:73:5 | LL | ptr::swap_nonoverlapping::(ptr::null_mut(), &mut v, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^^^^^^^^^ @@ -224,7 +204,7 @@ LL | ptr::swap_nonoverlapping::(ptr::null_mut(), &mut v, 0); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:76:5 + --> $DIR/invalid_null_args.rs:75:5 | LL | ptr::swap_nonoverlapping::(&mut v, ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ @@ -234,7 +214,7 @@ LL | ptr::swap_nonoverlapping::(&mut v, ptr::null_mut(), 0); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:79:5 + --> $DIR/invalid_null_args.rs:78:5 | LL | ptr::write(ptr::null_mut(), v); | ^^^^^^^^^^^---------------^^^^ @@ -244,7 +224,7 @@ LL | ptr::write(ptr::null_mut(), v); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:82:5 + --> $DIR/invalid_null_args.rs:81:5 | LL | ptr::write_unaligned(ptr::null_mut(), v); | ^^^^^^^^^^^^^^^^^^^^^---------------^^^^ @@ -254,17 +234,7 @@ LL | ptr::write_unaligned(ptr::null_mut(), v); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:85:5 - | -LL | ptr::write_volatile(ptr::null_mut(), v); - | ^^^^^^^^^^^^^^^^^^^^---------------^^^^ - | | - | null pointer originates from here - | - = help: for more information, visit and - -error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:88:5 + --> $DIR/invalid_null_args.rs:87:5 | LL | ptr::write_bytes::(ptr::null_mut(), 42, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^^^^^ @@ -274,7 +244,7 @@ LL | ptr::write_bytes::(ptr::null_mut(), 42, 0); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:93:18 + --> $DIR/invalid_null_args.rs:92:18 | LL | let _a: u8 = ptr::read(const_ptr); | ^^^^^^^^^^^^^^^^^^^^ @@ -287,7 +257,7 @@ LL | let null_ptr = ptr::null_mut(); | ^^^^^^^^^^^^^^^ error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:100:5 + --> $DIR/invalid_null_args.rs:99:5 | LL | std::slice::from_raw_parts::<()>(ptr::null(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^ @@ -297,7 +267,7 @@ LL | std::slice::from_raw_parts::<()>(ptr::null(), 0); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:102:5 + --> $DIR/invalid_null_args.rs:101:5 | LL | std::slice::from_raw_parts::(ptr::null(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^ @@ -307,7 +277,7 @@ LL | std::slice::from_raw_parts::(ptr::null(), 0); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:104:5 + --> $DIR/invalid_null_args.rs:103:5 | LL | std::slice::from_raw_parts_mut::<()>(ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ @@ -317,7 +287,7 @@ LL | std::slice::from_raw_parts_mut::<()>(ptr::null_mut(), 0); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:106:5 + --> $DIR/invalid_null_args.rs:105:5 | LL | std::slice::from_raw_parts_mut::(ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ @@ -326,5 +296,5 @@ LL | std::slice::from_raw_parts_mut::(ptr::null_mut(), 0); | = help: for more information, visit and -error: aborting due to 31 previous errors +error: aborting due to 28 previous errors diff --git a/tests/ui/precondition-checks/read_volatile.rs b/tests/ui/precondition-checks/read_volatile.rs index ada8932c398c..d858e6b939ac 100644 --- a/tests/ui/precondition-checks/read_volatile.rs +++ b/tests/ui/precondition-checks/read_volatile.rs @@ -1,9 +1,7 @@ //@ run-fail //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::read_volatile requires -//@ revisions: null misaligned - -#![allow(invalid_null_arguments)] +//@ revisions: misaligned use std::ptr; @@ -11,8 +9,6 @@ fn main() { let src = [0u16; 2]; let src = src.as_ptr(); unsafe { - #[cfg(null)] - ptr::read_volatile(ptr::null::()); #[cfg(misaligned)] ptr::read_volatile(src.byte_add(1)); } diff --git a/tests/ui/precondition-checks/write_volatile.rs b/tests/ui/precondition-checks/write_volatile.rs index 0d5ecb014b3d..ddc882be4323 100644 --- a/tests/ui/precondition-checks/write_volatile.rs +++ b/tests/ui/precondition-checks/write_volatile.rs @@ -1,9 +1,7 @@ //@ run-fail //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::write_volatile requires -//@ revisions: null misaligned - -#![allow(invalid_null_arguments)] +//@ revisions: misaligned use std::ptr; @@ -11,8 +9,6 @@ fn main() { let mut dst = [0u16; 2]; let mut dst = dst.as_mut_ptr(); unsafe { - #[cfg(null)] - ptr::write_volatile(ptr::null_mut::(), 1u8); #[cfg(misaligned)] ptr::write_volatile(dst.byte_add(1), 1u16); } From 4cebbabd5ce3fdb1444cc7efdb8e07eff52b6652 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 18 Jul 2025 16:47:39 +0000 Subject: [PATCH 326/363] Add implicit sized bound to trait ascription types --- .../src/hir_ty_lowering/mod.rs | 8 ++++++++ .../impl-trait/in-bindings/implicit-sized.rs | 19 +++++++++++++++++++ .../in-bindings/implicit-sized.stderr | 11 +++++++++++ 3 files changed, 38 insertions(+) create mode 100644 tests/ui/impl-trait/in-bindings/implicit-sized.rs create mode 100644 tests/ui/impl-trait/in-bindings/implicit-sized.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index a5bd7c1a34ae..2a6ba31d5abb 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2489,6 +2489,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::List::empty(), PredicateFilter::All, ); + self.add_sizedness_bounds( + &mut bounds, + self_ty, + hir_bounds, + None, + None, + hir_ty.span, + ); self.register_trait_ascription_bounds(bounds, hir_ty.hir_id, hir_ty.span); self_ty } diff --git a/tests/ui/impl-trait/in-bindings/implicit-sized.rs b/tests/ui/impl-trait/in-bindings/implicit-sized.rs new file mode 100644 index 000000000000..2f16db941895 --- /dev/null +++ b/tests/ui/impl-trait/in-bindings/implicit-sized.rs @@ -0,0 +1,19 @@ +#![feature(impl_trait_in_bindings)] + +trait Trait {} +impl Trait for T {} + +fn doesnt_work() { + let x: &impl Trait = "hi"; + //~^ ERROR the size for values of type `str` cannot be known at compilation time +} + +fn works() { + let x: &(impl Trait + ?Sized) = "hi"; + // No implicit sized. + + let x: &impl Trait = &(); + // Is actually sized. +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-bindings/implicit-sized.stderr b/tests/ui/impl-trait/in-bindings/implicit-sized.stderr new file mode 100644 index 000000000000..465a928cf86a --- /dev/null +++ b/tests/ui/impl-trait/in-bindings/implicit-sized.stderr @@ -0,0 +1,11 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/implicit-sized.rs:7:13 + | +LL | let x: &impl Trait = "hi"; + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 664d742933e020f70032e0fd8cd9c8869848fd4f Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Fri, 18 Jul 2025 18:29:29 +0200 Subject: [PATCH 327/363] rustc_codegen_ssa: Don't skip target-features after crt-static The current behaviour introduced by commit a50a3b8e318594c41783294e440d864763e412ef would discard any target features specified after crt-static (the only member of RUSTC_SPECIFIC_FEATURES). This is because it returned instead of continuing processing the next flag. Signed-off-by: Jens Reidel --- compiler/rustc_codegen_ssa/src/target_features.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 53df99993f06..def4ec13e87b 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -149,14 +149,14 @@ fn parse_rust_feature_flag<'a>( if let Some(base_feature) = feature.strip_prefix('+') { // Skip features that are not target features, but rustc features. if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) { - return; + continue; } callback(base_feature, sess.target.implied_target_features(base_feature), true) } else if let Some(base_feature) = feature.strip_prefix('-') { // Skip features that are not target features, but rustc features. if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) { - return; + continue; } // If `f1` implies `f2`, then `!f2` implies `!f1` -- this is standard logical From 1b35d5f89c4e3c605cd455a28f00aad24de0a662 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Fri, 18 Jul 2025 18:55:33 +0200 Subject: [PATCH 328/363] tests: Add a regression test for crt-static with target features Signed-off-by: Jens Reidel --- .../crt-static-with-target-features-works.rs | 24 +++++++++++++++++++ ...t-static-with-target-features-works.stderr | 8 +++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/ui/cfg/crt-static-with-target-features-works.rs create mode 100644 tests/ui/cfg/crt-static-with-target-features-works.stderr diff --git a/tests/ui/cfg/crt-static-with-target-features-works.rs b/tests/ui/cfg/crt-static-with-target-features-works.rs new file mode 100644 index 000000000000..bce022296245 --- /dev/null +++ b/tests/ui/cfg/crt-static-with-target-features-works.rs @@ -0,0 +1,24 @@ +// Test to ensure that specifying a value for crt-static in target features +// does not result in skipping the features following it. +// This is a regression test for #144143 + +//@ add-core-stubs +//@ needs-llvm-components: x86 +//@ compile-flags: --target=x86_64-unknown-linux-gnu +//@ compile-flags: -Ctarget-feature=+crt-static,+avx2 + +#![crate_type = "rlib"] +#![feature(no_core, rustc_attrs, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[rustc_builtin_macro] +macro_rules! compile_error { + () => {}; +} + +#[cfg(target_feature = "avx2")] +compile_error!("+avx2"); +//~^ ERROR: +avx2 diff --git a/tests/ui/cfg/crt-static-with-target-features-works.stderr b/tests/ui/cfg/crt-static-with-target-features-works.stderr new file mode 100644 index 000000000000..6f265c685bb9 --- /dev/null +++ b/tests/ui/cfg/crt-static-with-target-features-works.stderr @@ -0,0 +1,8 @@ +error: +avx2 + --> $DIR/crt-static-with-target-features-works.rs:23:1 + | +LL | compile_error!("+avx2"); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From e6f283080c794609dadd2ded323d5af76c99b5e9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 18 Jul 2025 17:30:00 +0000 Subject: [PATCH 329/363] Remove pretty print hack for async blocks --- compiler/rustc_middle/src/ty/print/pretty.rs | 26 +------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2eb530f328d3..9ee64df0ad06 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1210,30 +1210,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } for (assoc_item_def_id, term) in assoc_items { - // Skip printing `<{coroutine@} as Coroutine<_>>::Return` from async blocks, - // unless we can find out what coroutine return type it comes from. - let term = if let Some(ty) = term.skip_binder().as_type() - && let ty::Alias(ty::Projection, proj) = ty.kind() - && let Some(assoc) = tcx.opt_associated_item(proj.def_id) - && assoc - .trait_container(tcx) - .is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine)) - && assoc.opt_name() == Some(rustc_span::sym::Return) - { - if let ty::Coroutine(_, args) = args.type_at(0).kind() { - let return_ty = args.as_coroutine().return_ty(); - if !return_ty.is_ty_var() { - return_ty.into() - } else { - continue; - } - } else { - continue; - } - } else { - term.skip_binder() - }; - if first { p!("<"); first = false; @@ -1243,7 +1219,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name())); - match term.kind() { + match term.skip_binder().kind() { TermKind::Ty(ty) => p!(print(ty)), TermKind::Const(c) => p!(print(c)), }; From fb1a205a559e5d8302de4c428cfab14942e520c9 Mon Sep 17 00:00:00 2001 From: Micke <155267459+reallesee@users.noreply.github.com> Date: Fri, 18 Jul 2025 19:31:37 +0200 Subject: [PATCH 330/363] docs: update link to RISC-V and Xtensa installation guide --- src/doc/rustc/src/platform-support/xtensa.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/xtensa.md b/src/doc/rustc/src/platform-support/xtensa.md index 994b3adb92e6..8592ce7eda9d 100644 --- a/src/doc/rustc/src/platform-support/xtensa.md +++ b/src/doc/rustc/src/platform-support/xtensa.md @@ -24,4 +24,4 @@ Xtensa targets that support `std` are documented in the [ESP-IDF platform suppor ## Building the targets -The targets can be built by installing the [Xtensa enabled Rust channel](https://github.com/esp-rs/rust/). See instructions in the [RISC-V and Xtensa Targets section of The Rust on ESP Book](https://docs.esp-rs.org/book/installation/riscv-and-xtensa.html). +The targets can be built by installing the [Xtensa enabled Rust channel](https://github.com/esp-rs/rust/). See instructions in the [RISC-V and Xtensa Targets section of The Rust on ESP Book](https://docs.espressif.com/projects/rust/book/installation/index.html). From 2d51acd2fbcbadb6f30709c5dd305494d413d388 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Fri, 18 Jul 2025 19:44:20 +0200 Subject: [PATCH 331/363] tests: assembly: cstring-merging: Disable GlobalMerge pass The test relies on LLVM not merging all the globals into one and would currently otherwise fail on powerpc64le. Signed-off-by: Jens Reidel --- tests/assembly/cstring-merging.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/assembly/cstring-merging.rs b/tests/assembly/cstring-merging.rs index f7d0775f7aff..03688e0068b7 100644 --- a/tests/assembly/cstring-merging.rs +++ b/tests/assembly/cstring-merging.rs @@ -2,7 +2,7 @@ // other architectures (including ARM and x86-64) use the prefix `.Lanon.` //@ only-linux //@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 +//@ compile-flags: --crate-type=lib -Copt-level=3 -Cllvm-args=-enable-global-merge=0 //@ edition: 2024 use std::ffi::CStr; From c58e0bd09368a96dbde1ec1f30e36764e1431125 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sat, 19 Jul 2025 01:49:19 +0800 Subject: [PATCH 332/363] rename `emit_unless` to `emit_unless_delay` Signed-off-by: xizheyin --- compiler/rustc_errors/src/diagnostic.rs | 2 +- .../src/check/compare_impl_item.rs | 14 +++++++------- .../src/collect/resolve_bound_vars.rs | 2 +- .../src/hir_ty_lowering/generics.rs | 2 +- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 6 +++--- compiler/rustc_resolve/src/late.rs | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index a128f8d31a13..96c7ba6ed27b 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1421,7 +1421,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// /// See `emit` and `delay_as_bug` for details. #[track_caller] - pub fn emit_unless(mut self, delay: bool) -> G::EmitResult { + pub fn emit_unless_delay(mut self, delay: bool) -> G::EmitResult { if delay { self.downgrade_to_delayed_bug(); } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 87db80f2423d..e24426f9fedc 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1173,7 +1173,7 @@ fn check_region_bounds_on_impl_item<'tcx>( bounds_span, where_span, }) - .emit_unless(delay); + .emit_unless_delay(delay); Err(reported) } @@ -1481,7 +1481,7 @@ fn compare_self_type<'tcx>( } else { err.note_trait_signature(trait_m.name(), trait_m.signature(tcx)); } - return Err(err.emit_unless(delay)); + return Err(err.emit_unless_delay(delay)); } (true, false) => { @@ -1502,7 +1502,7 @@ fn compare_self_type<'tcx>( err.note_trait_signature(trait_m.name(), trait_m.signature(tcx)); } - return Err(err.emit_unless(delay)); + return Err(err.emit_unless_delay(delay)); } } @@ -1662,7 +1662,7 @@ fn compare_number_of_generics<'tcx>( err.span_label(*span, "`impl Trait` introduces an implicit type parameter"); } - let reported = err.emit_unless(delay); + let reported = err.emit_unless_delay(delay); err_occurred = Some(reported); } } @@ -1745,7 +1745,7 @@ fn compare_number_of_method_arguments<'tcx>( ), ); - return Err(err.emit_unless(delay)); + return Err(err.emit_unless_delay(delay)); } Ok(()) @@ -1872,7 +1872,7 @@ fn compare_synthetic_generics<'tcx>( ); }; } - error_found = Some(err.emit_unless(delay)); + error_found = Some(err.emit_unless_delay(delay)); } } if let Some(reported) = error_found { Err(reported) } else { Ok(()) } @@ -1974,7 +1974,7 @@ fn compare_generic_param_kinds<'tcx>( err.span_label(impl_header_span, ""); err.span_label(param_impl_span, make_param_message("found", param_impl)); - let reported = err.emit_unless(delay); + let reported = err.emit_unless_delay(delay); return Err(reported); } } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 77e63e38c8c8..eb3492f5de6e 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -2495,7 +2495,7 @@ fn deny_non_region_late_bound( format!("late-bound {what} parameter not allowed on {where_}"), ); - let guar = diag.emit_unless(!tcx.features().non_lifetime_binders() || !first); + let guar = diag.emit_unless_delay(!tcx.features().non_lifetime_binders() || !first); first = false; *arg = ResolvedArg::Error(guar); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 8c7c3750865c..fc519c194bb9 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -570,7 +570,7 @@ pub(crate) fn check_generic_arg_count( gen_args, def_id, )) - .emit_unless(all_params_are_binded) + .emit_unless_delay(all_params_are_binded) }); Err(reported) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index b2a229ad6518..6d67535da5fb 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1775,7 +1775,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ); } - let reported = err.emit_unless(unsized_return); + let reported = err.emit_unless_delay(unsized_return); self.final_ty = Some(Ty::new_error(fcx.tcx, reported)); } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 067ee0f0eb0b..08e8164078cb 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1549,7 +1549,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the assignment expression itself is ill-formed, don't // bother emitting another error - err.emit_unless(lhs_ty.references_error() || rhs_ty.references_error()) + err.emit_unless_delay(lhs_ty.references_error() || rhs_ty.references_error()) } pub(super) fn check_expr_let( @@ -3865,7 +3865,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.dcx() .create_err(NoVariantNamed { span: ident.span, ident, ty: container }) .with_span_label(field.span, "variant not found") - .emit_unless(container.references_error()); + .emit_unless_delay(container.references_error()); break; }; let Some(&subfield) = fields.next() else { @@ -3897,7 +3897,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { enum_span: field.span, field_span: subident.span, }) - .emit_unless(container.references_error()); + .emit_unless_delay(container.references_error()); break; }; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 93cec8daa5a4..a3a770502ded 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2913,7 +2913,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.r .dcx() .create_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span }) - .emit_unless(is_raw_underscore_lifetime); + .emit_unless_delay(is_raw_underscore_lifetime); // Record lifetime res, so lowering knows there is something fishy. self.record_lifetime_param(param.id, LifetimeRes::Error); continue; From 58a05caa457738d99fcee06aaa821317ea4015fb Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 18 Jul 2025 18:33:23 +0000 Subject: [PATCH 333/363] Rename optional-mingw-check to optional-pr-check --- src/ci/github-actions/jobs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index f0c52fe3d1ca..0a6ebe44b3d7 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -172,9 +172,9 @@ try: optional: # This job is used just to test optional jobs. # It will be replaced by tier 2 and tier 3 jobs in the future. - - name: optional-mingw-check-1 + - name: optional-pr-check-1 env: - IMAGE: mingw-check-1 + IMAGE: pr-check-1 <<: *job-linux-4c # Main CI jobs that have to be green to merge a commit into master From c79f62d1ea5d210de9bc98ddc7e0588533a2b311 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 2 Jul 2025 13:27:29 +0000 Subject: [PATCH 334/363] clippy fix: bound in one place --- library/core/src/cmp.rs | 5 +++-- library/core/src/iter/traits/iterator.rs | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index b1ca3701fa5a..7abadc9124ba 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1481,13 +1481,14 @@ pub trait PartialOrd: PartialEq + PointeeSized { } } -fn default_chaining_impl( +fn default_chaining_impl( lhs: &T, rhs: &U, p: impl FnOnce(Ordering) -> bool, ) -> ControlFlow where - T: PartialOrd, + T: PartialOrd + PointeeSized, + U: PointeeSized, { // It's important that this only call `partial_cmp` once, not call `eq` then // one of the relational operators. We don't want to `bcmp`-then-`memcp` a diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f296792b1dcb..10f9d464f7d7 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3414,10 +3414,10 @@ pub trait Iterator { /// ``` #[stable(feature = "iter_copied", since = "1.36.0")] #[rustc_diagnostic_item = "iter_copied"] - fn copied<'a, T: 'a>(self) -> Copied + fn copied<'a, T>(self) -> Copied where + T: Copy + 'a, Self: Sized + Iterator, - T: Copy, { Copied::new(self) } @@ -3462,10 +3462,10 @@ pub trait Iterator { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "iter_cloned"] - fn cloned<'a, T: 'a>(self) -> Cloned + fn cloned<'a, T>(self) -> Cloned where + T: Clone + 'a, Self: Sized + Iterator, - T: Clone, { Cloned::new(self) } From f16474f7bf0419de39db82fcf2f308cb42c2997d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 18 Jul 2025 22:35:30 +0200 Subject: [PATCH 335/363] Remove forgotten git annotations --- .../rustc_codegen_gcc/example/mini_core_hello_world.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index 358f265a6b85..85489f850e24 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -198,12 +198,6 @@ fn main() { assert_eq!(intrinsics::align_of::() as u8, 2); assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); -<<<<<<< HEAD - assert!(!const { intrinsics::needs_drop::() }); - assert!(!const { intrinsics::needs_drop::<[u8]>() }); - assert!(const { intrinsics::needs_drop::() }); - assert!(const { intrinsics::needs_drop::() }); -======= /* * TODO: re-enable in the next sync. let u8_needs_drop = const { intrinsics::needs_drop::() }; @@ -215,7 +209,6 @@ fn main() { let noisy_unsized_drop = const { intrinsics::needs_drop::() }; assert!(noisy_unsized_drop); */ ->>>>>>> f682d09eefc6700b9e5851ef193847959acf4fac Unique { pointer: 0 as *const &str, From f16016ad254e864c55c8bdf88b6a5926c1fb7dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 19 Jul 2025 10:27:46 +0200 Subject: [PATCH 336/363] Fix compiler for dist LLVM bitcode linker --- src/bootstrap/src/core/build_steps/compile.rs | 2 +- src/bootstrap/src/core/build_steps/dist.rs | 15 +++++++++---- src/bootstrap/src/core/build_steps/install.rs | 2 +- src/bootstrap/src/core/build_steps/tool.rs | 21 ++++++++++++++----- src/bootstrap/src/core/builder/tests.rs | 1 - 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index d1285340cd6a..a80fdefac437 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2056,7 +2056,7 @@ impl Step for Assemble { if builder.config.llvm_bitcode_linker_enabled { trace!("llvm-bitcode-linker enabled, installing"); let llvm_bitcode_linker = builder.ensure( - crate::core::build_steps::tool::LlvmBitcodeLinker::for_use_by_compiler( + crate::core::build_steps::tool::LlvmBitcodeLinker::from_target_compiler( builder, target_compiler, ), diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index af17a69302b2..39e4fb2ac01e 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1576,7 +1576,7 @@ impl Step for Extended { backend: "cranelift".to_string(), }); add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker { - target_compiler: compiler, + build_compiler: compiler, target }); @@ -2344,9 +2344,13 @@ impl Step for LlvmTools { } } +/// Distributes the `llvm-bitcode-linker` tool so that it can be used by a compiler whose host +/// is `target`. #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct LlvmBitcodeLinker { - pub target_compiler: Compiler, + /// The linker will be compiled by this compiler. + pub build_compiler: Compiler, + /// The linker will by usable by rustc on this host. pub target: TargetSelection, } @@ -2362,7 +2366,10 @@ impl Step for LlvmBitcodeLinker { fn make_run(run: RunConfig<'_>) { run.builder.ensure(LlvmBitcodeLinker { - target_compiler: run.builder.compiler(run.builder.top_stage, run.target), + build_compiler: tool::LlvmBitcodeLinker::get_build_compiler_for_target( + run.builder, + run.target, + ), target: run.target, }); } @@ -2371,7 +2378,7 @@ impl Step for LlvmBitcodeLinker { let target = self.target; let llbc_linker = builder - .ensure(tool::LlvmBitcodeLinker::for_use_by_compiler(builder, self.target_compiler)); + .ensure(tool::LlvmBitcodeLinker::from_build_compiler(self.build_compiler, target)); let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple); diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 285624916d18..4156b49a8b33 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -287,7 +287,7 @@ install!((self, builder, _config), } }; LlvmBitcodeLinker, alias = "llvm-bitcode-linker", Self::should_build(_config), only_hosts: true, { - if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { target_compiler: self.compiler, target: self.target }) { + if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { build_compiler: self.compiler, target: self.target }) { install_sh(builder, "llvm-bitcode-linker", self.compiler.stage, Some(self.target), &tarball); } else { builder.info( diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 4d2fa177765b..f1e317ebb662 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1171,8 +1171,14 @@ pub struct LlvmBitcodeLinker { } impl LlvmBitcodeLinker { + /// Returns `LlvmBitcodeLinker` that will be **compiled** by the passed compiler, for the given + /// `target`. + pub fn from_build_compiler(build_compiler: Compiler, target: TargetSelection) -> Self { + Self { build_compiler, target } + } + /// Returns `LlvmBitcodeLinker` that should be **used** by the passed compiler. - pub fn for_use_by_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self { + pub fn from_target_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self { Self { build_compiler: get_tool_target_compiler( builder, @@ -1181,6 +1187,14 @@ impl LlvmBitcodeLinker { target: target_compiler.host, } } + + /// Return a compiler that is able to build this tool for the given `target`. + pub fn get_build_compiler_for_target( + builder: &Builder<'_>, + target: TargetSelection, + ) -> Compiler { + get_tool_target_compiler(builder, ToolTargetBuildMode::Build(target)) + } } impl Step for LlvmBitcodeLinker { @@ -1196,10 +1210,7 @@ impl Step for LlvmBitcodeLinker { fn make_run(run: RunConfig<'_>) { run.builder.ensure(LlvmBitcodeLinker { - build_compiler: get_tool_target_compiler( - run.builder, - ToolTargetBuildMode::Build(run.target), - ), + build_compiler: Self::get_build_compiler_for_target(run.builder, run.target), target: run.target, }); } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 4ca9ff98dee4..aa4995a25498 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1293,7 +1293,6 @@ mod snapshot { [build] rustc 0 -> miri 1 [build] rustc 0 -> cargo-miri 1 [build] rustc 1 -> LlvmBitcodeLinker 2 - [build] rustc 0 -> LlvmBitcodeLinker 1 "); } From 7672e4ed85916d564d38dbd3a64803a45568504d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Jul 2025 10:29:13 +0200 Subject: [PATCH 337/363] interpret: fix TypeId pointers being considered data pointers --- .../rustc_const_eval/src/interpret/memory.rs | 10 ++++------ library/core/src/any.rs | 2 +- src/tools/miri/src/alloc_addresses/mod.rs | 2 +- .../src/borrow_tracker/stacked_borrows/mod.rs | 4 ++-- .../src/borrow_tracker/tree_borrows/mod.rs | 2 +- .../miri/tests/pass/intrinsics/type-id.rs | 19 +++++++++++++++++++ 6 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 src/tools/miri/tests/pass/intrinsics/type-id.rs diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 47228de52138..20c8e983ceae 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -67,8 +67,8 @@ pub enum AllocKind { LiveData, /// A function allocation (that fn ptrs point to). Function, - /// A (symbolic) vtable allocation. - VTable, + /// A "virtual" allocation, used for vtables and TypeId. + Virtual, /// A dead allocation. Dead, } @@ -950,11 +950,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env); let mutbl = global_alloc.mutability(*self.tcx, self.typing_env); let kind = match global_alloc { - GlobalAlloc::TypeId { .. } - | GlobalAlloc::Static { .. } - | GlobalAlloc::Memory { .. } => AllocKind::LiveData, + GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData, GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"), - GlobalAlloc::VTable { .. } => AllocKind::VTable, + GlobalAlloc::VTable { .. } | GlobalAlloc::TypeId { .. } => AllocKind::Virtual, }; return AllocInfo::new(size, align, kind, mutbl); } diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 39cdf6efda07..38393379a78a 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -783,7 +783,7 @@ impl TypeId { // This is a provenance-stripping memcpy. for (i, chunk) in self.data.iter().copied().enumerate() { - let chunk = chunk.expose_provenance().to_ne_bytes(); + let chunk = chunk.addr().to_ne_bytes(); let start = i * chunk.len(); bytes[start..(start + chunk.len())].copy_from_slice(&chunk); } diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 3cc38fa087c6..10339928ac2d 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -157,7 +157,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.get_alloc_bytes_unchecked_raw(alloc_id)? } } - AllocKind::Function | AllocKind::VTable => { + AllocKind::Function | AllocKind::Virtual => { // Allocate some dummy memory to get a unique address for this function/vtable. let alloc_bytes = MiriAllocBytes::from_bytes( &[0u8; 1], diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 834a4b41f224..e834fdffdd18 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -650,7 +650,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { dcx.log_protector(); } }, - AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { + AllocKind::Function | AllocKind::Virtual | AllocKind::Dead => { // No stacked borrows on these allocations. } } @@ -1021,7 +1021,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}"); alloc_extra.borrow_tracker_sb().borrow_mut().exposed_tags.insert(tag); } - AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { + AllocKind::Function | AllocKind::Virtual | AllocKind::Dead => { // No stacked borrows on these allocations. } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index c157c69d7c84..aa92f8a8c309 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -673,7 +673,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { trace!("Tree Borrows tag {tag:?} exposed in {alloc_id:?}"); alloc_extra.borrow_tracker_tb().borrow_mut().expose_tag(tag); } - AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { + AllocKind::Function | AllocKind::Virtual | AllocKind::Dead => { // No tree borrows on these allocations. } } diff --git a/src/tools/miri/tests/pass/intrinsics/type-id.rs b/src/tools/miri/tests/pass/intrinsics/type-id.rs new file mode 100644 index 000000000000..123fdbdc9cea --- /dev/null +++ b/src/tools/miri/tests/pass/intrinsics/type-id.rs @@ -0,0 +1,19 @@ +use std::any::{Any, TypeId}; + +fn main() { + let t1 = TypeId::of::(); + let t2 = TypeId::of::(); + assert_eq!(t1, t2); + let t3 = TypeId::of::(); + assert_ne!(t1, t3); + + let _ = format!("{t1:?}"); // test that we can debug-print + + let b = Box::new(0u64) as Box; + assert_eq!(*b.downcast_ref::().unwrap(), 0); + assert!(b.downcast_ref::().is_none()); + + // Get the first pointer chunk and try to make it a ZST ref. + // This used to trigger an error because TypeId allocs got misclassified as "LiveData". + let _raw_chunk = unsafe { (&raw const t1).cast::<&()>().read() }; +} From 9613ce02c393104ba7ebd4655d004e5f6da3db18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Sat, 19 Jul 2025 09:30:39 +0000 Subject: [PATCH 338/363] Revert "resolve: Make disambiguators for underscore bindings module-local" This reverts commit 998df3a3e851908afd05c3318f16d99849af5c55. --- .../rustc_resolve/src/build_reduced_graph.rs | 30 +++++++-------- compiler/rustc_resolve/src/imports.rs | 38 +++++++------------ compiler/rustc_resolve/src/lib.rs | 33 ++++++++-------- compiler/rustc_resolve/src/macros.rs | 2 +- 4 files changed, 45 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index c3bfd759f4c0..737577baa7ad 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -49,7 +49,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, binding: NameBinding<'ra>, ) { - if let Err(old_binding) = self.try_define(parent, ident, ns, binding, false) { + let key = self.new_disambiguated_key(ident, ns); + if let Err(old_binding) = self.try_define(parent, key, binding, false) { self.report_conflict(parent, ident, ns, old_binding, binding); } } @@ -441,18 +442,16 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.indeterminate_imports.push(import); match import.kind { + // Don't add unresolved underscore imports to modules + ImportKind::Single { target: Ident { name: kw::Underscore, .. }, .. } => {} ImportKind::Single { target, type_ns_only, .. } => { - // Don't add underscore imports to `single_imports` - // because they cannot define any usable names. - if target.name != kw::Underscore { - 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); - } - }); - } + 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); + } + }); } // We don't add prelude imports to the globs since they only affect lexical scopes, // which are not relevant to import resolution. @@ -1409,12 +1408,9 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { 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); - } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) - && ident.name != kw::Underscore - { - // Don't add underscore names, they cannot be looked up anyway. + } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) { let impl_def_id = self.r.tcx.local_parent(local_def_id); - let key = BindingKey::new(ident, ns); + let key = BindingKey::new(ident.normalize_to_macros_2_0(), ns); self.r.impl_binding_keys.entry(impl_def_id).or_default().insert(key); } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index b4c15ed1ca7e..0a4c25b0eb05 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -25,7 +25,7 @@ use rustc_span::{Ident, Span, Symbol, kw, sym}; use smallvec::SmallVec; use tracing::debug; -use crate::Namespace::{self, *}; +use crate::Namespace::*; use crate::diagnostics::{DiagMode, Suggestion, import_candidates}; use crate::errors::{ CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate, @@ -338,20 +338,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn try_define( &mut self, module: Module<'ra>, - ident: Ident, - ns: Namespace, + key: BindingKey, binding: NameBinding<'ra>, warn_ambiguity: bool, ) -> Result<(), NameBinding<'ra>> { let res = binding.res(); - self.check_reserved_macro_name(ident, res); + self.check_reserved_macro_name(key.ident, res); self.set_binding_parent_module(binding, module); - // 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, || { - (module.0.0.lazy_resolutions.borrow().len() + 1).try_into().unwrap() - }); self.update_resolution(module, key, warn_ambiguity, |this, resolution| { if let Some(old_binding) = resolution.best_binding() { if res == Res::Err && old_binding.res() != Res::Err { @@ -390,7 +383,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (old_glob @ true, false) | (old_glob @ false, true) => { let (glob_binding, non_glob_binding) = if old_glob { (old_binding, binding) } else { (binding, old_binding) }; - if ns == MacroNS + if key.ns == MacroNS && non_glob_binding.expansion != LocalExpnId::ROOT && glob_binding.res() != non_glob_binding.res() { @@ -496,10 +489,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; if self.is_accessible_from(binding.vis, scope) { let imported_binding = self.import(binding, *import); + let key = BindingKey { ident, ..key }; let _ = self.try_define( import.parent_scope.module, - ident, - key.ns, + key, imported_binding, warn_ambiguity, ); @@ -521,15 +514,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let dummy_binding = self.dummy_binding; 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); - // 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| { - resolution.single_imports.swap_remove(&import); - }) - } + let key = BindingKey::new(target, ns); + let _ = this.try_define(import.parent_scope.module, key, dummy_binding, false); + this.update_resolution(import.parent_scope.module, key, false, |_, resolution| { + resolution.single_imports.swap_remove(&import); + }) }); self.record_use(target, dummy_binding, Used::Other); } else if import.imported_module.get().is_none() { @@ -906,7 +895,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { PendingBinding::Ready(Some(imported_binding)) } Err(Determinacy::Determined) => { - // Don't remove underscores from `single_imports`, they were never added. + // Don't update the resolution for underscores, because it was never added. if target.name != kw::Underscore { let key = BindingKey::new(target, ns); this.update_resolution(parent, key, false, |_, resolution| { @@ -1521,8 +1510,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .is_some_and(|binding| binding.warn_ambiguity_recursive()); let _ = self.try_define( import.parent_scope.module, - key.ident, - key.ns, + key, imported_binding, warn_ambiguity, ); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 948b67a37985..0d41a822e8a8 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -532,26 +532,15 @@ struct BindingKey { /// identifier. ident: Ident, ns: Namespace, - /// When we add an underscore binding (with ident `_`) to some module, this field has - /// a non-zero value that uniquely identifies this binding in that module. - /// For non-underscore bindings this field is zero. - /// When a key is constructed for name lookup (as opposed to name definition), this field is - /// also zero, even for underscore names, so for underscores the lookup will never succeed. + /// 0 if ident is not `_`, otherwise a value that's unique to the specific + /// `_` in the expanded AST that introduced this binding. disambiguator: u32, } impl BindingKey { fn new(ident: Ident, ns: Namespace) -> Self { - BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator: 0 } - } - - fn new_disambiguated( - ident: Ident, - ns: Namespace, - disambiguator: impl FnOnce() -> u32, - ) -> BindingKey { - let disambiguator = if ident.name == kw::Underscore { disambiguator() } else { 0 }; - BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator } + let ident = ident.normalize_to_macros_2_0(); + BindingKey { ident, ns, disambiguator: 0 } } } @@ -1098,6 +1087,8 @@ pub struct Resolver<'ra, 'tcx> { extern_module_map: RefCell>>, binding_parent_modules: FxHashMap, Module<'ra>>, + underscore_disambiguator: u32, + /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap>, glob_error: Option, @@ -1509,6 +1500,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { extern_crate_map: Default::default(), module_children: Default::default(), trait_map: NodeMap::default(), + underscore_disambiguator: 0, empty_module, local_module_map, extern_module_map: Default::default(), @@ -1889,6 +1881,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { import_ids } + fn new_disambiguated_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey { + let ident = ident.normalize_to_macros_2_0(); + let disambiguator = if ident.name == kw::Underscore { + self.underscore_disambiguator += 1; + self.underscore_disambiguator + } else { + 0 + }; + BindingKey { ident, ns, disambiguator } + } + fn resolutions(&mut self, module: Module<'ra>) -> &'ra Resolutions<'ra> { if module.populate_on_access.get() { module.populate_on_access.set(false); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 0e8904a7deab..77ef7f56c094 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -530,7 +530,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { target_trait.for_each_child(self, |this, ident, ns, _binding| { // FIXME: Adjust hygiene for idents from globs, like for glob imports. if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id) - && overriding_keys.contains(&BindingKey::new(ident, ns)) + && overriding_keys.contains(&BindingKey::new(ident.normalize_to_macros_2_0(), ns)) { // The name is overridden, do not produce it from the glob delegation. } else { From c75edc982c8cf67f30d9c082cf2670f59392ed2e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 19 Jul 2025 16:20:37 +0200 Subject: [PATCH 339/363] Fix clippy lints in librustdoc --- src/librustdoc/clean/types.rs | 4 +- src/librustdoc/clean/utils.rs | 6 +- src/librustdoc/doctest.rs | 4 +- src/librustdoc/doctest/rust.rs | 2 +- src/librustdoc/formats/renderer.rs | 4 +- src/librustdoc/html/format.rs | 12 +-- src/librustdoc/html/highlight.rs | 4 +- src/librustdoc/html/layout.rs | 1 - src/librustdoc/html/markdown.rs | 4 +- src/librustdoc/html/render/context.rs | 82 ++++++++----------- src/librustdoc/html/render/mod.rs | 39 +++++---- src/librustdoc/html/render/ordered_json.rs | 2 +- src/librustdoc/html/render/print_item.rs | 80 +++++++++--------- src/librustdoc/html/render/sidebar.rs | 2 +- src/librustdoc/html/render/sorted_template.rs | 3 +- src/librustdoc/json/conversions.rs | 20 ++--- src/librustdoc/json/mod.rs | 6 +- .../passes/collect_intra_doc_links.rs | 25 +++--- .../passes/lint/redundant_explicit_links.rs | 16 ++-- .../passes/strip_aliased_non_local.rs | 10 +-- 20 files changed, 153 insertions(+), 173 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 09647492d933..5ac5da24299f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1677,7 +1677,7 @@ impl Type { } } - pub(crate) fn generics<'a>(&'a self) -> Option> { + pub(crate) fn generics(&self) -> Option> { match self { Type::Path { path, .. } => path.generics(), _ => None, @@ -2227,7 +2227,7 @@ impl Path { self.segments.last().map(|seg| &seg.args) } - pub(crate) fn generics<'a>(&'a self) -> Option> { + pub(crate) fn generics(&self) -> Option> { self.segments.last().and_then(|seg| { if let GenericArgs::AngleBracketed { ref args, .. } = seg.args { Some(args.iter().filter_map(|arg| match arg { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index fd1b17b64765..813fdee57e17 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -343,13 +343,11 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { match n.kind() { ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args: _ }) => { - let s = if let Some(def) = def.as_local() { + if let Some(def) = def.as_local() { rendered_const(cx.tcx, cx.tcx.hir_body_owned_by(def), def) } else { inline::print_inlined_const(cx.tcx, def) - }; - - s + } } // array lengths are obviously usize ty::ConstKind::Value(cv) if *cv.ty.kind() == ty::Uint(ty::UintTy::Usize) => { diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 9b4d25339541..38ba6b4503dc 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -632,7 +632,7 @@ fn run_test( // the user to exploit nightly-only features on stable runner_compiler.env("RUSTC_BOOTSTRAP", "1"); runner_compiler.args(compiler_args); - runner_compiler.args(&["--crate-type=bin", "-o"]).arg(&output_file); + runner_compiler.args(["--crate-type=bin", "-o"]).arg(&output_file); let mut extern_path = std::ffi::OsString::from(format!( "--extern=doctest_bundle_{edition}=", edition = doctest.edition @@ -657,7 +657,7 @@ fn run_test( extern_path.push(&output_bundle_file); runner_compiler.arg(extern_path); runner_compiler.arg(&runner_input_file); - if std::fs::write(&runner_input_file, &merged_test_code).is_err() { + if std::fs::write(&runner_input_file, merged_test_code).is_err() { // If we cannot write this file for any reason, we leave. All combined tests will be // tested as standalone tests. return Err(TestFailure::CompileError); diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index 96975105ac50..f5ec828187a5 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -140,7 +140,7 @@ impl HirCollector<'_> { .iter() .filter(|a| a.has_name(sym::attr)) .flat_map(|a| a.meta_item_list().unwrap_or_default()) - .map(|i| pprust::meta_list_item_to_string(i)) + .map(pprust::meta_list_item_to_string) { // Add the additional attributes to the global_crate_attrs vector self.collector.global_crate_attrs.push(attr); diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index 79ff1fa38c38..aa4be4db9973 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -81,7 +81,7 @@ fn run_format_inner<'tcx, T: FormatRenderer<'tcx>>( let _timer = prof.generic_activity_with_arg("render_mod_item", item.name.unwrap().to_string()); - cx.mod_item_in(&item)?; + cx.mod_item_in(item)?; let (clean::StrippedItem(box clean::ModuleItem(ref module)) | clean::ModuleItem(ref module)) = item.inner.kind else { @@ -99,7 +99,7 @@ fn run_format_inner<'tcx, T: FormatRenderer<'tcx>>( } else if let Some(item_name) = item.name && !item.is_extern_crate() { - prof.generic_activity_with_arg("render_item", item_name.as_str()).run(|| cx.item(&item))?; + prof.generic_activity_with_arg("render_item", item_name.as_str()).run(|| cx.item(item))?; } Ok(()) } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index b16485107a02..be8a2d511e91 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -114,9 +114,9 @@ impl clean::Generics { let real_params = fmt::from_fn(|f| real_params.clone().map(|g| g.print(cx)).joined(", ", f)); if f.alternate() { - write!(f, "<{:#}>", real_params) + write!(f, "<{real_params:#}>") } else { - write!(f, "<{}>", real_params) + write!(f, "<{real_params}>") } }) } @@ -594,7 +594,7 @@ pub(crate) fn href_with_root_path( } } }; - let url_parts = make_href(root_path, shortty, url_parts, &fqp, is_remote); + let url_parts = make_href(root_path, shortty, url_parts, fqp, is_remote); Ok((url_parts, shortty, fqp.clone())) } @@ -1115,7 +1115,7 @@ impl clean::Impl { { let last = ty.last(); if f.alternate() { - write!(f, "{}<", last)?; + write!(f, "{last}<")?; self.print_type(inner_type, f, use_absolute, cx)?; write!(f, ">")?; } else { @@ -1219,7 +1219,7 @@ pub(crate) fn print_params(params: &[clean::Parameter], cx: &Context<'_>) -> imp .map(|param| { fmt::from_fn(|f| { if let Some(name) = param.name { - write!(f, "{}: ", name)?; + write!(f, "{name}: ")?; } param.type_.print(cx).fmt(f) }) @@ -1341,7 +1341,7 @@ impl clean::FnDecl { write!(f, "const ")?; } if let Some(name) = param.name { - write!(f, "{}: ", name)?; + write!(f, "{name}: ")?; } param.type_.print(cx).fmt(f)?; } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index b2feee36c939..272180fb9904 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -547,7 +547,7 @@ impl<'a> Iterator for TokenIter<'a> { fn get_real_ident_class(text: &str, allow_path_keywords: bool) -> Option { let ignore: &[&str] = if allow_path_keywords { &["self", "Self", "super", "crate"] } else { &["self", "Self"] }; - if ignore.iter().any(|k| *k == text) { + if ignore.contains(&text) { return None; } Some(match text { @@ -1159,7 +1159,7 @@ fn string_without_closing_tag( return Some(""); } if !open_tag { - write!(out, "{}", text_s).unwrap(); + out.write_str(&text_s).unwrap(); return None; } let klass_s = klass.as_html(); diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 50320cb231d2..1f92c521d46e 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -132,6 +132,5 @@ pub(crate) fn redirect(url: &str) -> String { "##, - url = url, ) } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e41435de29c6..4addf2c3c964 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -251,7 +251,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { if !parse_result.rust { let added_classes = parse_result.added_classes; let lang_string = if let Some(lang) = parse_result.unknown.first() { - format!("language-{}", lang) + format!("language-{lang}") } else { String::new() }; @@ -999,7 +999,7 @@ impl<'a, 'tcx> TagIterator<'a, 'tcx> { if let Some((_, c)) = self.inner.next() { if c != '=' { - self.emit_error(format!("expected `=`, found `{}`", c)); + self.emit_error(format!("expected `=`, found `{c}`")); return None; } } else { diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 7b814701a732..5ceb1fc988dc 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -193,14 +193,12 @@ impl<'tcx> Context<'tcx> { if it.is_stripped() && let Some(def_id) = it.def_id() && def_id.is_local() + && (self.info.is_inside_inlined_module + || self.shared.cache.inlined_items.contains(&def_id)) { - if self.info.is_inside_inlined_module - || self.shared.cache.inlined_items.contains(&def_id) - { - // For now we're forced to generate a redirect page for stripped items until - // `record_extern_fqn` correctly points to external items. - render_redirect_pages = true; - } + // For now we're forced to generate a redirect page for stripped items until + // `record_extern_fqn` correctly points to external items. + render_redirect_pages = true; } let mut title = String::new(); if !is_module { @@ -254,40 +252,36 @@ impl<'tcx> Context<'tcx> { &self.shared.style_files, ) } else { - if let Some(&(ref names, ty)) = self.cache().paths.get(&it.item_id.expect_def_id()) { - if self.current.len() + 1 != names.len() - || self.current.iter().zip(names.iter()).any(|(a, b)| a != b) - { - // We checked that the redirection isn't pointing to the current file, - // preventing an infinite redirection loop in the generated - // documentation. + if let Some(&(ref names, ty)) = self.cache().paths.get(&it.item_id.expect_def_id()) + && (self.current.len() + 1 != names.len() + || self.current.iter().zip(names.iter()).any(|(a, b)| a != b)) + { + // We checked that the redirection isn't pointing to the current file, + // preventing an infinite redirection loop in the generated + // documentation. - let path = fmt::from_fn(|f| { - for name in &names[..names.len() - 1] { - write!(f, "{name}/")?; - } - write!(f, "{}", print_item_path(ty, names.last().unwrap().as_str())) - }); - match self.shared.redirections { - Some(ref redirections) => { - let mut current_path = String::new(); - for name in &self.current { - current_path.push_str(name.as_str()); - current_path.push('/'); - } - let _ = write!( - current_path, - "{}", - print_item_path(ty, names.last().unwrap().as_str()) - ); - redirections.borrow_mut().insert(current_path, path.to_string()); - } - None => { - return layout::redirect(&format!( - "{root}{path}", - root = self.root_path() - )); + let path = fmt::from_fn(|f| { + for name in &names[..names.len() - 1] { + write!(f, "{name}/")?; + } + write!(f, "{}", print_item_path(ty, names.last().unwrap().as_str())) + }); + match self.shared.redirections { + Some(ref redirections) => { + let mut current_path = String::new(); + for name in &self.current { + current_path.push_str(name.as_str()); + current_path.push('/'); } + let _ = write!( + current_path, + "{}", + print_item_path(ty, names.last().unwrap().as_str()) + ); + redirections.borrow_mut().insert(current_path, path.to_string()); + } + None => { + return layout::redirect(&format!("{root}{path}", root = self.root_path())); } } } @@ -762,11 +756,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // Flush pending errors. self.shared.fs.close(); let nb_errors = self.shared.errors.iter().map(|err| self.tcx().dcx().err(err)).count(); - if nb_errors > 0 { - Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), "")) - } else { - Ok(()) - } + if nb_errors > 0 { Err(Error::new(io::Error::other("I/O error"), "")) } else { Ok(()) } } fn mod_item_in(&mut self, item: &clean::Item) -> Result<(), Error> { @@ -842,7 +832,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { self.info.render_redirect_pages = item.is_stripped(); } - let buf = self.render_item(&item, false); + let buf = self.render_item(item, false); // buf will be empty if the item is stripped and there is no redirect for it if !buf.is_empty() { let name = item.name.as_ref().unwrap(); @@ -853,7 +843,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { self.shared.fs.write(joint_dst, buf)?; if !self.info.render_redirect_pages { - self.shared.all.borrow_mut().append(full_path(self, &item), &item_type); + self.shared.all.borrow_mut().append(full_path(self, item), &item_type); } // If the item is a macro, redirect from the old macro URL (with !) // to the new one (without). diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 2cfc9af39e47..872dbbcd19e1 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1483,10 +1483,10 @@ fn render_deref_methods( } } render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs); - } else if let Some(prim) = target.primitive_type() { - if let Some(&did) = cache.primitive_locations.get(&prim) { - render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs); - } + } else if let Some(prim) = target.primitive_type() + && let Some(&did) = cache.primitive_locations.get(&prim) + { + render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs); } } @@ -2058,21 +2058,20 @@ fn render_impl( // default items which weren't overridden in the implementation block. // We don't emit documentation for default items if they appear in the // Implementations on Foreign Types or Implementors sections. - if rendering_params.show_default_items { - if let Some(t) = trait_ - && !impl_.is_negative_trait_impl() - { - render_default_items( - &mut default_impl_items, - &mut impl_items, - cx, - t, - impl_, - &i.impl_item, - render_mode, - rendering_params, - )?; - } + if rendering_params.show_default_items + && let Some(t) = trait_ + && !impl_.is_negative_trait_impl() + { + render_default_items( + &mut default_impl_items, + &mut impl_items, + cx, + t, + impl_, + &i.impl_item, + render_mode, + rendering_params, + )?; } if render_mode == RenderMode::Normal { let toggled = !(impl_items.is_empty() && default_impl_items.is_empty()); @@ -2570,7 +2569,7 @@ fn collect_paths_for_type(first_ty: &clean::Type, cache: &Cache) -> Vec match ty { clean::Type::Path { path } => process_path(path.def_id()), clean::Type::Tuple(tys) => { - work.extend(tys.into_iter()); + work.extend(tys.iter()); } clean::Type::Slice(ty) => { work.push_back(ty); diff --git a/src/librustdoc/html/render/ordered_json.rs b/src/librustdoc/html/render/ordered_json.rs index d1dddfebc83a..be51dad1c2bf 100644 --- a/src/librustdoc/html/render/ordered_json.rs +++ b/src/librustdoc/html/render/ordered_json.rs @@ -25,7 +25,7 @@ impl OrderedJson { .into_iter() .sorted_unstable_by(|a, b| a.borrow().cmp(b.borrow())) .format_with(",", |item, f| f(item.borrow())); - Self(format!("[{}]", items)) + Self(format!("[{items}]")) } pub(crate) fn array_unsorted, I: IntoIterator>(items: I) -> Self { diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 5fbda4797cc9..02ee34aaac68 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1451,7 +1451,7 @@ item_template!( impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { fn render_union(&self) -> impl Display { - render_union(self.it, Some(&self.generics), &self.fields, self.cx) + render_union(self.it, Some(self.generics), self.fields, self.cx) } fn document_field(&self, field: &'a clean::Item) -> impl Display { @@ -1982,16 +1982,14 @@ fn item_constant( w.write_str(";")?; } - if !is_literal { - if let Some(value) = &value { - let value_lowercase = value.to_lowercase(); - let expr_lowercase = expr.to_lowercase(); + if !is_literal && let Some(value) = &value { + let value_lowercase = value.to_lowercase(); + let expr_lowercase = expr.to_lowercase(); - if value_lowercase != expr_lowercase - && value_lowercase.trim_end_matches("i32") != expr_lowercase - { - write!(w, " // {value}", value = Escape(value))?; - } + if value_lowercase != expr_lowercase + && value_lowercase.trim_end_matches("i32") != expr_lowercase + { + write!(w, " // {value}", value = Escape(value))?; } } Ok::<(), fmt::Error>(()) @@ -2071,41 +2069,39 @@ fn item_fields( _ => None, }) .peekable(); - if let None | Some(CtorKind::Fn) = ctor_kind { - if fields.peek().is_some() { - let title = format!( - "{}{}", - if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, - document_non_exhaustive_header(it), - ); + if let None | Some(CtorKind::Fn) = ctor_kind + && fields.peek().is_some() + { + let title = format!( + "{}{}", + if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, + document_non_exhaustive_header(it), + ); + write!( + w, + "{}", + write_section_heading( + &title, + "fields", + Some("fields"), + document_non_exhaustive(it) + ) + )?; + for (index, (field, ty)) in fields.enumerate() { + let field_name = + field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string()); + let id = cx.derive_id(format!("{typ}.{field_name}", typ = ItemType::StructField)); write!( w, - "{}", - write_section_heading( - &title, - "fields", - Some("fields"), - document_non_exhaustive(it) - ) + "\ + §\ + {field_name}: {ty}\ + \ + {doc}", + item_type = ItemType::StructField, + ty = ty.print(cx), + doc = document(cx, field, Some(it), HeadingOffset::H3), )?; - for (index, (field, ty)) in fields.enumerate() { - let field_name = field - .name - .map_or_else(|| index.to_string(), |sym| sym.as_str().to_string()); - let id = - cx.derive_id(format!("{typ}.{field_name}", typ = ItemType::StructField)); - write!( - w, - "\ - §\ - {field_name}: {ty}\ - \ - {doc}", - item_type = ItemType::StructField, - ty = ty.print(cx), - doc = document(cx, field, Some(it), HeadingOffset::H3), - )?; - } } } Ok(()) diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 91540e06e339..b9f5ada417c7 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -541,7 +541,7 @@ fn sidebar_deref_methods<'a>( .iter() .filter(|i| { i.inner_impl().trait_.is_none() - && real_target.is_doc_subtype_of(&i.inner_impl().for_, &c) + && real_target.is_doc_subtype_of(&i.inner_impl().for_, c) }) .flat_map(|i| get_methods(i.inner_impl(), true, used_links, deref_mut, cx.tcx())) .collect::>(); diff --git a/src/librustdoc/html/render/sorted_template.rs b/src/librustdoc/html/render/sorted_template.rs index a7b954ab70ba..659c5e6093bd 100644 --- a/src/librustdoc/html/render/sorted_template.rs +++ b/src/librustdoc/html/render/sorted_template.rs @@ -63,7 +63,8 @@ impl fmt::Display for SortedTemplate { for (p, fragment) in self.fragments.iter().with_position() { let mut f = DeltaWriter { inner: &mut f, delta: 0 }; let sep = if matches!(p, Position::First | Position::Only) { "" } else { F::SEPARATOR }; - write!(f, "{}{}", sep, fragment)?; + f.write_str(sep)?; + f.write_str(fragment)?; fragment_lengths.push(f.delta); } let offset = Offset { start: self.before.len(), fragment_lengths }; diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 0a84d8caa30f..08bc0bb19505 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -50,7 +50,7 @@ impl JsonRenderer<'_> { let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); let clean::ItemInner { name, item_id, .. } = *item.inner; - let id = self.id_from_item(&item); + let id = self.id_from_item(item); let inner = match item.kind { clean::KeywordItem => return None, clean::StrippedItem(ref inner) => { @@ -86,14 +86,14 @@ impl JsonRenderer<'_> { items .iter() .filter(|i| !i.is_stripped() && !i.is_keyword()) - .map(|i| self.id_from_item(&i)) + .map(|i| self.id_from_item(i)) .collect() } fn ids_keeping_stripped(&self, items: &[clean::Item]) -> Vec> { items .iter() - .map(|i| (!i.is_stripped() && !i.is_keyword()).then(|| self.id_from_item(&i))) + .map(|i| (!i.is_stripped() && !i.is_keyword()).then(|| self.id_from_item(i))) .collect() } } @@ -358,12 +358,12 @@ impl FromClean for Struct { let clean::Struct { ctor_kind, generics, fields } = struct_; let kind = match ctor_kind { - Some(CtorKind::Fn) => StructKind::Tuple(renderer.ids_keeping_stripped(&fields)), + Some(CtorKind::Fn) => StructKind::Tuple(renderer.ids_keeping_stripped(fields)), Some(CtorKind::Const) => { assert!(fields.is_empty()); StructKind::Unit } - None => StructKind::Plain { fields: renderer.ids(&fields), has_stripped_fields }, + None => StructKind::Plain { fields: renderer.ids(fields), has_stripped_fields }, }; Struct { @@ -381,7 +381,7 @@ impl FromClean for Union { Union { generics: generics.into_json(renderer), has_stripped_fields, - fields: renderer.ids(&fields), + fields: renderer.ids(fields), impls: Vec::new(), // Added in JsonRenderer::item } } @@ -659,7 +659,7 @@ impl FromClean for FunctionSignature { let clean::FnDecl { inputs, output, c_variadic } = decl; FunctionSignature { inputs: inputs - .into_iter() + .iter() .map(|param| { // `_` is the most sensible name for missing param names. let name = param.name.unwrap_or(kw::Underscore).to_string(); @@ -684,7 +684,7 @@ impl FromClean for Trait { is_auto, is_unsafe, is_dyn_compatible, - items: renderer.ids(&items), + items: renderer.ids(items), generics: generics.into_json(renderer), bounds: bounds.into_json(renderer), implementations: Vec::new(), // Added in JsonRenderer::item @@ -727,7 +727,7 @@ impl FromClean for Impl { .collect(), trait_: trait_.into_json(renderer), for_: for_.into_json(renderer), - items: renderer.ids(&items), + items: renderer.ids(items), is_negative, is_synthetic, blanket_impl: blanket_impl.map(|x| x.into_json(renderer)), @@ -770,7 +770,7 @@ impl FromClean for Variant { let kind = match &variant.kind { CLike => VariantKind::Plain, - Tuple(fields) => VariantKind::Tuple(renderer.ids_keeping_stripped(&fields)), + Tuple(fields) => VariantKind::Tuple(renderer.ids_keeping_stripped(fields)), Struct(s) => VariantKind::Struct { has_stripped_fields: s.has_stripped_entries(), fields: renderer.ids(&s.fields), diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 600a4b429f3c..760e48baffab 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -133,7 +133,7 @@ fn target(sess: &rustc_session::Session) -> types::Target { let feature_stability: FxHashMap<&str, Stability> = sess .target .rust_target_features() - .into_iter() + .iter() .copied() .map(|(name, stability, _)| (name, stability)) .collect(); @@ -143,7 +143,7 @@ fn target(sess: &rustc_session::Session) -> types::Target { target_features: sess .target .rust_target_features() - .into_iter() + .iter() .copied() .filter(|(_, stability, _)| { // Describe only target features which the user can toggle @@ -157,7 +157,7 @@ fn target(sess: &rustc_session::Session) -> types::Target { _ => None, }, implies_features: implied_features - .into_iter() + .iter() .copied() .filter(|name| { // Imply only target features which the user can toggle diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index ca6f67eb6dfd..5a9aa2a94c8b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -274,7 +274,7 @@ impl From> for OwnedDiagnosticInfo { } impl OwnedDiagnosticInfo { - pub(crate) fn into_info(&self) -> DiagnosticInfo<'_> { + pub(crate) fn as_info(&self) -> DiagnosticInfo<'_> { DiagnosticInfo { item: &self.item, ori_link: &self.ori_link, @@ -1177,7 +1177,7 @@ impl LinkCollector<'_, '_> { // Primitive types are always valid. Res::Primitive(_) => true, }); - let diag_info = info.diag_info.into_info(); + let diag_info = info.diag_info.as_info(); match info.resolved.len() { 1 => { let (res, fragment) = info.resolved.pop().unwrap(); @@ -1243,17 +1243,16 @@ impl LinkCollector<'_, '_> { disambiguator, None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive) ) && !matches!(res, Res::Primitive(_)) + && let Some(prim) = resolve_primitive(path_str, TypeNS) { - if let Some(prim) = resolve_primitive(path_str, TypeNS) { - // `prim@char` - if matches!(disambiguator, Some(Disambiguator::Primitive)) { - res = prim; - } else { - // `[char]` when a `char` module is in scope - let candidates = &[(res, res.def_id(self.cx.tcx)), (prim, None)]; - ambiguity_error(self.cx, &diag_info, path_str, candidates, true); - return None; - } + // `prim@char` + if matches!(disambiguator, Some(Disambiguator::Primitive)) { + res = prim; + } else { + // `[char]` when a `char` module is in scope + let candidates = &[(res, res.def_id(self.cx.tcx)), (prim, None)]; + ambiguity_error(self.cx, &diag_info, path_str, candidates, true); + return None; } } @@ -2233,7 +2232,7 @@ fn ambiguity_error( // proc macro can exist in multiple namespaces at once, so we need to compare `DefIds` // to remove the candidate in the fn namespace. let mut possible_proc_macro_id = None; - let is_proc_macro_crate = cx.tcx.crate_types() == &[CrateType::ProcMacro]; + let is_proc_macro_crate = cx.tcx.crate_types() == [CrateType::ProcMacro]; let mut kinds = candidates .iter() .map(|(res, def_id)| { diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 5757b6a97408..e69cf87f9578 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -93,14 +93,14 @@ fn check_redundant_explicit_link<'md>( if let Event::Start(Tag::Link { link_type, dest_url, .. }) = event { let link_data = collect_link_data(&mut offset_iter); - if let Some(resolvable_link) = link_data.resolvable_link.as_ref() { - if &link_data.display_link.replace('`', "") != resolvable_link { - // Skips if display link does not match to actual - // resolvable link, usually happens if display link - // has several segments, e.g. - // [this is just an `Option`](Option) - continue; - } + if let Some(resolvable_link) = link_data.resolvable_link.as_ref() + && &link_data.display_link.replace('`', "") != resolvable_link + { + // Skips if display link does not match to actual + // resolvable link, usually happens if display link + // has several segments, e.g. + // [this is just an `Option`](Option) + continue; } let explicit_link = dest_url.to_string(); diff --git a/src/librustdoc/passes/strip_aliased_non_local.rs b/src/librustdoc/passes/strip_aliased_non_local.rs index b53e3b4e3d7a..bb13308e6c2a 100644 --- a/src/librustdoc/passes/strip_aliased_non_local.rs +++ b/src/librustdoc/passes/strip_aliased_non_local.rs @@ -47,13 +47,11 @@ impl DocFolder for NonLocalStripper<'_> { // FIXME(#125009): Not-local should probably consider same Cargo workspace if let Some(def_id) = i.def_id() && !def_id.is_local() - { - if i.is_doc_hidden() + && (i.is_doc_hidden() // Default to *not* stripping items with inherited visibility. - || i.visibility(self.tcx).is_some_and(|viz| viz != Visibility::Public) - { - return Some(strip_item(i)); - } + || i.visibility(self.tcx).is_some_and(|viz| viz != Visibility::Public)) + { + return Some(strip_item(i)); } Some(self.fold_item_recur(i)) From 4ef92bec5abae8cce07e587bdd6f116cfa065873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Sat, 19 Jul 2025 15:17:04 +0000 Subject: [PATCH 340/363] fix load-bearing typo --- library/coretests/tests/iter/adapters/zip.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/coretests/tests/iter/adapters/zip.rs b/library/coretests/tests/iter/adapters/zip.rs index 83279380175e..063e226a61ce 100644 --- a/library/coretests/tests/iter/adapters/zip.rs +++ b/library/coretests/tests/iter/adapters/zip.rs @@ -273,7 +273,7 @@ fn test_double_ended_zip() { #[test] #[cfg(panic = "unwind")] -/// Regresion test for #137255 +/// Regression test for #137255 /// A previous implementation of Zip TrustedRandomAccess specializations tried to do a lot of work /// to preserve side-effects of equalizing the iterator lengths during backwards iteration. /// This lead to several cases of unsoundness, twice due to being left in an inconsistent state From e1d4f2a0c297690ddfc24815de57539f532f2471 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Wed, 25 Jun 2025 07:56:40 +0200 Subject: [PATCH 341/363] tests: Require `run-fail` ui tests to have an exit code (`SIGABRT` not ok) And introduce two new directives for ui tests: * `run-crash` * `run-fail-or-crash` Normally a `run-fail` ui test like tests that panic shall not be terminated by a signal like `SIGABRT`. So begin having that as a hard requirement. Some of our current tests do terminate by a signal/crash however. Introduce and use `run-crash` for those tests. Note that Windows crashes are not handled by signals but by certain high bits set on the process exit code. Example exit code for crash on Windows: `0xc000001d`. Because of this, we define "crash" on all platforms as "not exit with success and not exit with a regular failure code in the range 1..=127". Some tests behave differently on different targets: * Targets without unwind support will abort (crash) instead of exit with failure code 101 after panicking. As a special case, allow crashes for `run-fail` tests for such targets. * Different sanitizer implementations handle detected memory problems differently. Some abort (crash) the process while others exit with failure code 1. Introduce and use `run-fail-or-crash` for such tests. --- .../rustc-dev-guide/src/tests/directives.md | 6 ++- src/doc/rustc-dev-guide/src/tests/ui.md | 18 +++++-- src/tools/compiletest/src/common.rs | 28 +++++++++- src/tools/compiletest/src/directives.rs | 12 ++++- src/tools/compiletest/src/runtest.rs | 7 +-- src/tools/compiletest/src/runtest/ui.rs | 53 ++++++++++++++++--- .../contracts/contract-attributes-generics.rs | 6 +-- .../ui/contracts/contract-attributes-nest.rs | 4 +- .../ui/contracts/contract-attributes-tail.rs | 4 +- .../contract-captures-via-closure-copy.rs | 2 +- tests/ui/contracts/contract-const-fn.rs | 4 +- .../contracts-ensures-early-fn-exit.rs | 6 +-- .../contract-ast-extensions-nest.rs | 4 +- .../contract-ast-extensions-tail.rs | 4 +- .../internal_machinery/contract-intrinsics.rs | 4 +- .../internal_machinery/contract-lang-items.rs | 2 +- tests/ui/extern/extern-types-field-offset.rs | 2 +- .../borrow_misaligned_field_projection.rs | 2 +- tests/ui/mir/alignment/misaligned_borrow.rs | 2 +- tests/ui/mir/alignment/misaligned_lhs.rs | 2 +- .../ui/mir/alignment/misaligned_mut_borrow.rs | 2 +- tests/ui/mir/alignment/misaligned_rhs.rs | 2 +- tests/ui/mir/alignment/two_pointers.rs | 2 +- .../ui/mir/enum/convert_non_integer_break.rs | 2 +- .../enum/convert_non_integer_niche_break.rs | 2 +- tests/ui/mir/enum/negative_discr_break.rs | 2 +- tests/ui/mir/enum/niche_option_tuple_break.rs | 2 +- tests/ui/mir/enum/numbered_variants_break.rs | 2 +- .../enum/option_with_bigger_niche_break.rs | 2 +- tests/ui/mir/enum/plain_no_data_break.rs | 2 +- tests/ui/mir/enum/single_with_repr_break.rs | 2 +- tests/ui/mir/enum/with_niche_int_break.rs | 2 +- tests/ui/mir/enum/wrap_break.rs | 2 +- tests/ui/mir/null/borrowed_mut_null.rs | 2 +- tests/ui/mir/null/borrowed_null.rs | 2 +- tests/ui/mir/null/borrowed_null_zst.rs | 2 +- tests/ui/mir/null/null_lhs.rs | 2 +- tests/ui/mir/null/null_rhs.rs | 2 +- tests/ui/mir/null/two_pointers.rs | 2 +- tests/ui/panics/panic-in-cleanup.rs | 2 +- tests/ui/panics/panic-in-ffi.rs | 2 +- tests/ui/panics/panic-in-message-fmt.rs | 2 +- tests/ui/panics/panic-main.rs | 9 +++- tests/ui/precondition-checks/alignment.rs | 2 +- .../ascii-char-digit_unchecked.rs | 2 +- .../precondition-checks/assert_unchecked.rs | 2 +- .../char-from_u32_unchecked.rs | 2 +- .../copy-nonoverlapping.rs | 2 +- tests/ui/precondition-checks/copy.rs | 2 +- tests/ui/precondition-checks/layout.rs | 2 +- tests/ui/precondition-checks/nonnull.rs | 2 +- .../nonzero-from_mut_unchecked.rs | 2 +- .../nonzero-new_unchecked.rs | 2 +- tests/ui/precondition-checks/read_volatile.rs | 2 +- tests/ui/precondition-checks/replace.rs | 2 +- .../slice-from-raw-parts-mut.rs | 2 +- .../slice-from-raw-parts.rs | 2 +- .../slice-get_unchecked.rs | 2 +- .../slice-get_unchecked_mut.rs | 2 +- .../precondition-checks/str-get_unchecked.rs | 2 +- .../str-get_unchecked_mut.rs | 2 +- .../swap-nonoverlapping.rs | 2 +- tests/ui/precondition-checks/unchecked_add.rs | 2 +- tests/ui/precondition-checks/unchecked_mul.rs | 2 +- tests/ui/precondition-checks/unchecked_shl.rs | 2 +- tests/ui/precondition-checks/unchecked_shr.rs | 2 +- tests/ui/precondition-checks/unchecked_sub.rs | 2 +- .../unreachable_unchecked.rs | 2 +- .../ui/precondition-checks/vec-from-parts.rs | 2 +- .../precondition-checks/vec-from-raw-parts.rs | 2 +- tests/ui/precondition-checks/vec-set-len.rs | 2 +- .../ui/precondition-checks/write_volatile.rs | 2 +- tests/ui/sanitizer/address.rs | 2 +- tests/ui/sanitizer/badfree.rs | 2 +- .../new-llvm-pass-manager-thin-lto.rs | 2 +- tests/ui/sanitizer/thread.rs | 2 +- tests/ui/sanitizer/use-after-scope.rs | 2 +- .../std/issue-81357-unsound-file-methods.rs | 2 +- 78 files changed, 195 insertions(+), 100 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 63aa08c389cc..6685add461e7 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -75,8 +75,10 @@ expectations](ui.md#controlling-passfail-expectations). | `check-fail` | Building (no codegen) should fail | `ui`, `crashes` | N/A | | `build-pass` | Building should pass | `ui`, `crashes`, `codegen`, `incremental` | N/A | | `build-fail` | Building should fail | `ui`, `crashes` | N/A | -| `run-pass` | Running the test binary should pass | `ui`, `crashes`, `incremental` | N/A | -| `run-fail` | Running the test binary should fail | `ui`, `crashes` | N/A | +| `run-pass` | Program must exit with code `0` | `ui`, `crashes`, `incremental` | N/A | +| `run-fail` | Program must exit with code `1..=127` | `ui`, `crashes` | N/A | +| `run-crash` | Program must crash | `ui` | N/A | +| `run-fail-or-crash` | Program must `run-fail` or `run-crash` | `ui` | N/A | | `ignore-pass` | Ignore `--pass` flag | `ui`, `crashes`, `codegen`, `incremental` | N/A | | `dont-check-failure-status` | Don't check exact failure status (i.e. `1`) | `ui`, `incremental` | N/A | | `failure-status` | Check | `ui`, `crashes` | Any `u16` | diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 4fce5838b6e7..9bfc60e08a6e 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -448,7 +448,7 @@ even run the resulting program. Just add one of the following - `//@ build-pass` — compilation and linking should succeed but do not run the resulting binary. - `//@ run-pass` — compilation should succeed and running the resulting - binary should also succeed. + binary should make it exit with code 0 which indicates success. - Fail directives: - `//@ check-fail` — compilation should fail (the codegen phase is skipped). This is the default for UI tests. @@ -457,10 +457,20 @@ even run the resulting program. Just add one of the following - First time is to ensure that the compile succeeds without the codegen phase - Second time is to ensure that the full compile fails - `//@ run-fail` — compilation should succeed, but running the resulting - binary should fail. + binary should make it exit with a code in the range `1..=127` which + indicates regular failure. On targets without unwind support, crashes + are also accepted. + - `//@ run-crash` — compilation should succeed, but running the resulting + binary should fail with a crash. Crashing is defined as "not exiting with + a code in the range `0..=127`". Example on Linux: Termination by `SIGABRT` + or `SIGSEGV`. Example on Windows: Exiting with the code for + `STATUS_ILLEGAL_INSTRUCTION` (`0xC000001D`). + - `//@ run-fail-or-crash` — compilation should succeed, but running the + resulting binary should either `run-fail` or `run-crash`. Useful if a test + crashes on some targets but just fails on others. -For `run-pass` and `run-fail` tests, by default the output of the program itself -is not checked. +For `run-pass`. `run-fail`, `run-crash` and `run-fail-or-crash` tests, by +default the output of the program itself is not checked. If you want to check the output of running the program, include the `check-run-results` directive. This will check for a `.run.stderr` and diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 33da1a25db17..c83070aaba7b 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -88,11 +88,37 @@ string_enum! { } } +string_enum! { + #[derive(Clone, Copy, PartialEq, Debug, Hash)] + pub enum RunResult { + Pass => "run-pass", + Fail => "run-fail", + Crash => "run-crash", + } +} + +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub enum RunFailMode { + /// Running the program must make it exit with a regular failure exit code + /// in the range `1..=127`. If the program is terminated by e.g. a signal + /// the test will fail. + Fail, + /// Running the program must result in a crash, e.g. by `SIGABRT` or + /// `SIGSEGV` on Unix or on Windows by having an appropriate NTSTATUS high + /// bit in the exit code. + Crash, + /// Running the program must either fail or crash. Useful for e.g. sanitizer + /// tests since some sanitizer implementations exit the process with code 1 + /// to in the face of memory errors while others abort (crash) the process + /// in the face of memory errors. + FailOrCrash, +} + #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] pub enum FailMode { Check, Build, - Run, + Run(RunFailMode), } string_enum! { diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 93133ea0bfd2..513716357f42 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -9,7 +9,7 @@ use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; use tracing::*; -use crate::common::{Config, Debugger, FailMode, PassMode, TestMode}; +use crate::common::{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::needs::CachedNeedsConditions; @@ -654,7 +654,13 @@ impl TestProps { Some(FailMode::Build) } else if config.parse_name_directive(ln, "run-fail") { check_ui("run"); - Some(FailMode::Run) + Some(FailMode::Run(RunFailMode::Fail)) + } else if config.parse_name_directive(ln, "run-crash") { + check_ui("run"); + Some(FailMode::Run(RunFailMode::Crash)) + } else if config.parse_name_directive(ln, "run-fail-or-crash") { + check_ui("run"); + Some(FailMode::Run(RunFailMode::FailOrCrash)) } else { None }; @@ -1007,7 +1013,9 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "regex-error-pattern", "remap-src-base", "revisions", + "run-crash", "run-fail", + "run-fail-or-crash", "run-flags", "run-pass", "run-rustfix", diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index cb8f593c9dfc..f66d4f98f1f2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -16,8 +16,8 @@ use regex::{Captures, Regex}; use tracing::*; use crate::common::{ - CompareMode, Config, Debugger, FailMode, PassMode, TestMode, TestPaths, TestSuite, - UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, + CompareMode, Config, Debugger, FailMode, PassMode, RunFailMode, RunResult, TestMode, TestPaths, + TestSuite, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, expected_output_path, incremental_dir, output_base_dir, output_base_name, output_testname_unique, }; @@ -282,7 +282,8 @@ impl<'test> TestCx<'test> { fn should_run(&self, pm: Option) -> WillExecute { let test_should_run = match self.config.mode { TestMode::Ui - if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => + if pm == Some(PassMode::Run) + || matches!(self.props.fail_mode, Some(FailMode::Run(_))) => { true } diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index f6bc85cd051a..0507c2600aed 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -6,8 +6,8 @@ use rustfix::{Filter, apply_suggestions, get_suggestions_from_json}; use tracing::debug; use super::{ - AllowUnused, Emit, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, TestOutput, - Truncated, UI_FIXED, WillExecute, + AllowUnused, Emit, FailMode, LinkToAux, PassMode, RunFailMode, RunResult, TargetLocation, + TestCx, TestOutput, Truncated, UI_FIXED, WillExecute, }; use crate::json; @@ -140,12 +140,53 @@ impl TestCx<'_> { &proc_res, ); } + let code = proc_res.status.code(); + let run_result = if proc_res.status.success() { + RunResult::Pass + } else if code.is_some_and(|c| c >= 1 && c <= 127) { + RunResult::Fail + } else { + RunResult::Crash + }; + // Help users understand why the test failed by including the actual + // exit code and actual run result in the failure message. + let pass_hint = format!("code={code:?} so test would pass with `{run_result}`"); if self.should_run_successfully(pm) { - if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); + if run_result != RunResult::Pass { + self.fatal_proc_rec( + &format!("test did not exit with success! {pass_hint}"), + &proc_res, + ); } - } else if proc_res.status.success() { - self.fatal_proc_rec("test run succeeded!", &proc_res); + } else if self.props.fail_mode == Some(FailMode::Run(RunFailMode::Fail)) { + // If the test is marked as `run-fail` but do not support + // unwinding we allow it to crash, since a panic will trigger an + // abort (crash) instead of unwind (exit with code 101). + let crash_ok = !self.config.can_unwind(); + if run_result != RunResult::Fail && !(crash_ok && run_result == RunResult::Crash) { + let err = if crash_ok { + format!( + "test did not exit with failure or crash (`{}` can't unwind)! {pass_hint}", + self.config.target + ) + } else { + format!("test did not exit with failure! {pass_hint}") + }; + self.fatal_proc_rec(&err, &proc_res); + } + } else if self.props.fail_mode == Some(FailMode::Run(RunFailMode::Crash)) { + if run_result != RunResult::Crash { + self.fatal_proc_rec(&format!("test did not crash! {pass_hint}"), &proc_res); + } + } else if self.props.fail_mode == Some(FailMode::Run(RunFailMode::FailOrCrash)) { + if run_result != RunResult::Fail && run_result != RunResult::Crash { + self.fatal_proc_rec( + &format!("test did not exit with failure or crash! {pass_hint}"), + &proc_res, + ); + } + } else { + unreachable!("run_ui_test() must not be called if the test should not run"); } self.get_output(&proc_res) diff --git a/tests/ui/contracts/contract-attributes-generics.rs b/tests/ui/contracts/contract-attributes-generics.rs index fd79c6abedd8..3763ce116f84 100644 --- a/tests/ui/contracts/contract-attributes-generics.rs +++ b/tests/ui/contracts/contract-attributes-generics.rs @@ -5,9 +5,9 @@ //@ [unchk_pass] run-pass //@ [chk_pass] run-pass // -//@ [chk_fail_pre] run-fail -//@ [chk_fail_post] run-fail -//@ [chk_const_fail] run-fail +//@ [chk_fail_pre] run-crash +//@ [chk_fail_post] run-crash +//@ [chk_const_fail] run-crash // //@ [unchk_pass] compile-flags: -Zcontract-checks=no // diff --git a/tests/ui/contracts/contract-attributes-nest.rs b/tests/ui/contracts/contract-attributes-nest.rs index e1e61b88f282..d367687b84e3 100644 --- a/tests/ui/contracts/contract-attributes-nest.rs +++ b/tests/ui/contracts/contract-attributes-nest.rs @@ -5,8 +5,8 @@ //@ [unchk_fail_post] run-pass //@ [chk_pass] run-pass // -//@ [chk_fail_pre] run-fail -//@ [chk_fail_post] run-fail +//@ [chk_fail_pre] run-crash +//@ [chk_fail_post] run-crash // //@ [unchk_pass] compile-flags: -Zcontract-checks=no //@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no diff --git a/tests/ui/contracts/contract-attributes-tail.rs b/tests/ui/contracts/contract-attributes-tail.rs index ce4a6be5b82f..43edfe5e803f 100644 --- a/tests/ui/contracts/contract-attributes-tail.rs +++ b/tests/ui/contracts/contract-attributes-tail.rs @@ -5,8 +5,8 @@ //@ [unchk_fail_post] run-pass //@ [chk_pass] run-pass // -//@ [chk_fail_pre] run-fail -//@ [chk_fail_post] run-fail +//@ [chk_fail_pre] run-crash +//@ [chk_fail_post] run-crash // //@ [unchk_pass] compile-flags: -Zcontract-checks=no //@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no diff --git a/tests/ui/contracts/contract-captures-via-closure-copy.rs b/tests/ui/contracts/contract-captures-via-closure-copy.rs index 32c6d2bf4fe1..bc7e5b9b6f10 100644 --- a/tests/ui/contracts/contract-captures-via-closure-copy.rs +++ b/tests/ui/contracts/contract-captures-via-closure-copy.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Zcontract-checks=yes #![feature(contracts)] diff --git a/tests/ui/contracts/contract-const-fn.rs b/tests/ui/contracts/contract-const-fn.rs index 733a06ae5709..fe8dd37b1f52 100644 --- a/tests/ui/contracts/contract-const-fn.rs +++ b/tests/ui/contracts/contract-const-fn.rs @@ -8,8 +8,8 @@ // //@ [all_pass] run-pass // -//@ [runtime_fail_pre] run-fail -//@ [runtime_fail_post] run-fail +//@ [runtime_fail_pre] run-crash +//@ [runtime_fail_post] run-crash // //@ [all_pass] compile-flags: -Zcontract-checks=yes //@ [runtime_fail_pre] compile-flags: -Zcontract-checks=yes diff --git a/tests/ui/contracts/contracts-ensures-early-fn-exit.rs b/tests/ui/contracts/contracts-ensures-early-fn-exit.rs index 034cead3b4e9..44ae07d8c95c 100644 --- a/tests/ui/contracts/contracts-ensures-early-fn-exit.rs +++ b/tests/ui/contracts/contracts-ensures-early-fn-exit.rs @@ -2,9 +2,9 @@ // //@ [unchk_pass] run-pass //@ [chk_pass] run-pass -//@ [chk_fail_try] run-fail -//@ [chk_fail_ret] run-fail -//@ [chk_fail_yeet] run-fail +//@ [chk_fail_try] run-crash +//@ [chk_fail_ret] run-crash +//@ [chk_fail_yeet] run-crash // //@ [unchk_pass] compile-flags: -Zcontract-checks=no //@ [chk_pass] compile-flags: -Zcontract-checks=yes diff --git a/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs b/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs index 6d8cd3949eed..4da0480f8bc1 100644 --- a/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs +++ b/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs @@ -5,8 +5,8 @@ //@ [unchk_fail_post] run-pass //@ [chk_pass] run-pass // -//@ [chk_fail_pre] run-fail -//@ [chk_fail_post] run-fail +//@ [chk_fail_pre] run-crash +//@ [chk_fail_post] run-crash // //@ [unchk_pass] compile-flags: -Zcontract-checks=no //@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no diff --git a/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs b/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs index 07ec26f921b8..f3cf5ce082c0 100644 --- a/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs +++ b/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs @@ -5,8 +5,8 @@ //@ [unchk_fail_post] run-pass //@ [chk_pass] run-pass // -//@ [chk_fail_pre] run-fail -//@ [chk_fail_post] run-fail +//@ [chk_fail_pre] run-crash +//@ [chk_fail_post] run-crash // //@ [unchk_pass] compile-flags: -Zcontract-checks=no //@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no diff --git a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs index c62b8cca75ab..6e613b53fc9b 100644 --- a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs +++ b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs @@ -3,8 +3,8 @@ //@ [default] run-pass //@ [unchk_pass] run-pass //@ [chk_pass] run-pass -//@ [chk_fail_requires] run-fail -//@ [chk_fail_ensures] run-fail +//@ [chk_fail_requires] run-crash +//@ [chk_fail_ensures] run-crash // //@ [unchk_pass] compile-flags: -Zcontract-checks=no //@ [chk_pass] compile-flags: -Zcontract-checks=yes diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.rs b/tests/ui/contracts/internal_machinery/contract-lang-items.rs index 73c591945310..ac72d233bf6b 100644 --- a/tests/ui/contracts/internal_machinery/contract-lang-items.rs +++ b/tests/ui/contracts/internal_machinery/contract-lang-items.rs @@ -4,7 +4,7 @@ //@ [unchk_fail_post] run-pass //@ [chk_pass] run-pass // -//@ [chk_fail_post] run-fail +//@ [chk_fail_post] run-crash // //@ [unchk_pass] compile-flags: -Zcontract-checks=no //@ [unchk_fail_post] compile-flags: -Zcontract-checks=no diff --git a/tests/ui/extern/extern-types-field-offset.rs b/tests/ui/extern/extern-types-field-offset.rs index 75f3eab3e275..035f063cd502 100644 --- a/tests/ui/extern/extern-types-field-offset.rs +++ b/tests/ui/extern/extern-types-field-offset.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ check-run-results //@ exec-env:RUST_BACKTRACE=0 //@ normalize-stderr: "(core/src/panicking\.rs):[0-9]+:[0-9]+" -> "$1:$$LINE:$$COL" diff --git a/tests/ui/mir/alignment/borrow_misaligned_field_projection.rs b/tests/ui/mir/alignment/borrow_misaligned_field_projection.rs index a22965ce1d87..6ba895f172d9 100644 --- a/tests/ui/mir/alignment/borrow_misaligned_field_projection.rs +++ b/tests/ui/mir/alignment/borrow_misaligned_field_projection.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ ignore-i686-pc-windows-msvc: #112480 //@ compile-flags: -C debug-assertions //@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is diff --git a/tests/ui/mir/alignment/misaligned_borrow.rs b/tests/ui/mir/alignment/misaligned_borrow.rs index de8912c70382..60c21deaba5a 100644 --- a/tests/ui/mir/alignment/misaligned_borrow.rs +++ b/tests/ui/mir/alignment/misaligned_borrow.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ ignore-i686-pc-windows-msvc: #112480 //@ compile-flags: -C debug-assertions //@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is diff --git a/tests/ui/mir/alignment/misaligned_lhs.rs b/tests/ui/mir/alignment/misaligned_lhs.rs index b169823bc081..e8ddb10fd9c4 100644 --- a/tests/ui/mir/alignment/misaligned_lhs.rs +++ b/tests/ui/mir/alignment/misaligned_lhs.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ ignore-i686-pc-windows-msvc: #112480 //@ compile-flags: -C debug-assertions //@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is diff --git a/tests/ui/mir/alignment/misaligned_mut_borrow.rs b/tests/ui/mir/alignment/misaligned_mut_borrow.rs index bba20edecfdd..c066cc0efcd9 100644 --- a/tests/ui/mir/alignment/misaligned_mut_borrow.rs +++ b/tests/ui/mir/alignment/misaligned_mut_borrow.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ ignore-i686-pc-windows-msvc: #112480 //@ compile-flags: -C debug-assertions //@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is diff --git a/tests/ui/mir/alignment/misaligned_rhs.rs b/tests/ui/mir/alignment/misaligned_rhs.rs index 55da30a2fd75..6bdc39c9d914 100644 --- a/tests/ui/mir/alignment/misaligned_rhs.rs +++ b/tests/ui/mir/alignment/misaligned_rhs.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ ignore-i686-pc-windows-msvc: #112480 //@ compile-flags: -C debug-assertions //@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is diff --git a/tests/ui/mir/alignment/two_pointers.rs b/tests/ui/mir/alignment/two_pointers.rs index 198a1c9853d9..fd8b2f543aa6 100644 --- a/tests/ui/mir/alignment/two_pointers.rs +++ b/tests/ui/mir/alignment/two_pointers.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ ignore-i686-pc-windows-msvc: #112480 //@ compile-flags: -C debug-assertions //@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is diff --git a/tests/ui/mir/enum/convert_non_integer_break.rs b/tests/ui/mir/enum/convert_non_integer_break.rs index 29795190bf6a..b0778e2024f5 100644 --- a/tests/ui/mir/enum/convert_non_integer_break.rs +++ b/tests/ui/mir/enum/convert_non_integer_break.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: trying to construct an enum from an invalid value diff --git a/tests/ui/mir/enum/convert_non_integer_niche_break.rs b/tests/ui/mir/enum/convert_non_integer_niche_break.rs index 9ff4849c5b1f..d26a3aeb5063 100644 --- a/tests/ui/mir/enum/convert_non_integer_niche_break.rs +++ b/tests/ui/mir/enum/convert_non_integer_niche_break.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: trying to construct an enum from an invalid value 0x5 diff --git a/tests/ui/mir/enum/negative_discr_break.rs b/tests/ui/mir/enum/negative_discr_break.rs index fa1284f72a07..35ee8aa3fc85 100644 --- a/tests/ui/mir/enum/negative_discr_break.rs +++ b/tests/ui/mir/enum/negative_discr_break.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: trying to construct an enum from an invalid value 0xfd diff --git a/tests/ui/mir/enum/niche_option_tuple_break.rs b/tests/ui/mir/enum/niche_option_tuple_break.rs index affdc4784a3f..0a933afa1535 100644 --- a/tests/ui/mir/enum/niche_option_tuple_break.rs +++ b/tests/ui/mir/enum/niche_option_tuple_break.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: trying to construct an enum from an invalid value diff --git a/tests/ui/mir/enum/numbered_variants_break.rs b/tests/ui/mir/enum/numbered_variants_break.rs index e3e71dc8aec4..fbe7d6627a3e 100644 --- a/tests/ui/mir/enum/numbered_variants_break.rs +++ b/tests/ui/mir/enum/numbered_variants_break.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: trying to construct an enum from an invalid value 0x3 diff --git a/tests/ui/mir/enum/option_with_bigger_niche_break.rs b/tests/ui/mir/enum/option_with_bigger_niche_break.rs index c66614b845b5..675d27f0ec2a 100644 --- a/tests/ui/mir/enum/option_with_bigger_niche_break.rs +++ b/tests/ui/mir/enum/option_with_bigger_niche_break.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: trying to construct an enum from an invalid value 0x0 diff --git a/tests/ui/mir/enum/plain_no_data_break.rs b/tests/ui/mir/enum/plain_no_data_break.rs index db68e752479d..966dd641873e 100644 --- a/tests/ui/mir/enum/plain_no_data_break.rs +++ b/tests/ui/mir/enum/plain_no_data_break.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: trying to construct an enum from an invalid value 0x1 diff --git a/tests/ui/mir/enum/single_with_repr_break.rs b/tests/ui/mir/enum/single_with_repr_break.rs index 5a4ec85a9b55..53e4932d5fd7 100644 --- a/tests/ui/mir/enum/single_with_repr_break.rs +++ b/tests/ui/mir/enum/single_with_repr_break.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: trying to construct an enum from an invalid value 0x1 diff --git a/tests/ui/mir/enum/with_niche_int_break.rs b/tests/ui/mir/enum/with_niche_int_break.rs index 6a97eaa8f4f5..d363dc7568a4 100644 --- a/tests/ui/mir/enum/with_niche_int_break.rs +++ b/tests/ui/mir/enum/with_niche_int_break.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: trying to construct an enum from an invalid value diff --git a/tests/ui/mir/enum/wrap_break.rs b/tests/ui/mir/enum/wrap_break.rs index 4491394ca5a3..5c410afa511c 100644 --- a/tests/ui/mir/enum/wrap_break.rs +++ b/tests/ui/mir/enum/wrap_break.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: trying to construct an enum from an invalid value 0x0 #![feature(never_type)] diff --git a/tests/ui/mir/null/borrowed_mut_null.rs b/tests/ui/mir/null/borrowed_mut_null.rs index d26452b9dac2..a4660f4bf573 100644 --- a/tests/ui/mir/null/borrowed_mut_null.rs +++ b/tests/ui/mir/null/borrowed_mut_null.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: null pointer dereference occurred diff --git a/tests/ui/mir/null/borrowed_null.rs b/tests/ui/mir/null/borrowed_null.rs index fefac3a7212c..2a50058a4820 100644 --- a/tests/ui/mir/null/borrowed_null.rs +++ b/tests/ui/mir/null/borrowed_null.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: null pointer dereference occurred diff --git a/tests/ui/mir/null/borrowed_null_zst.rs b/tests/ui/mir/null/borrowed_null_zst.rs index 835727c068b3..106fa00b1db5 100644 --- a/tests/ui/mir/null/borrowed_null_zst.rs +++ b/tests/ui/mir/null/borrowed_null_zst.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: null pointer dereference occurred diff --git a/tests/ui/mir/null/null_lhs.rs b/tests/ui/mir/null/null_lhs.rs index 238d350d1bda..b59338588a5c 100644 --- a/tests/ui/mir/null/null_lhs.rs +++ b/tests/ui/mir/null/null_lhs.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: null pointer dereference occurred diff --git a/tests/ui/mir/null/null_rhs.rs b/tests/ui/mir/null/null_rhs.rs index 18eafb618698..18fdad759fd5 100644 --- a/tests/ui/mir/null/null_rhs.rs +++ b/tests/ui/mir/null/null_rhs.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: null pointer dereference occurred diff --git a/tests/ui/mir/null/two_pointers.rs b/tests/ui/mir/null/two_pointers.rs index 52b9510be12e..b2aa7cf0384d 100644 --- a/tests/ui/mir/null/two_pointers.rs +++ b/tests/ui/mir/null/two_pointers.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -C debug-assertions //@ error-pattern: null pointer dereference occurred diff --git a/tests/ui/panics/panic-in-cleanup.rs b/tests/ui/panics/panic-in-cleanup.rs index 8cddeb37348d..2e307de43939 100644 --- a/tests/ui/panics/panic-in-cleanup.rs +++ b/tests/ui/panics/panic-in-cleanup.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ exec-env:RUST_BACKTRACE=0 //@ check-run-results //@ error-pattern: panic in a destructor during cleanup diff --git a/tests/ui/panics/panic-in-ffi.rs b/tests/ui/panics/panic-in-ffi.rs index 6068e4fdc59b..b926d0fa7761 100644 --- a/tests/ui/panics/panic-in-ffi.rs +++ b/tests/ui/panics/panic-in-ffi.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ exec-env:RUST_BACKTRACE=0 //@ check-run-results //@ error-pattern: panic in a function that cannot unwind diff --git a/tests/ui/panics/panic-in-message-fmt.rs b/tests/ui/panics/panic-in-message-fmt.rs index 1e9bbaf45c54..4d539f17a0af 100644 --- a/tests/ui/panics/panic-in-message-fmt.rs +++ b/tests/ui/panics/panic-in-message-fmt.rs @@ -1,6 +1,6 @@ // Checks what happens when formatting the panic message panics. -//@ run-fail +//@ run-crash //@ exec-env:RUST_BACKTRACE=0 //@ check-run-results //@ error-pattern: panicked while processing panic diff --git a/tests/ui/panics/panic-main.rs b/tests/ui/panics/panic-main.rs index 2395f68241f5..2009f69e19e1 100644 --- a/tests/ui/panics/panic-main.rs +++ b/tests/ui/panics/panic-main.rs @@ -1,30 +1,37 @@ //@ revisions: default abort-zero abort-one abort-full unwind-zero unwind-one unwind-full +//@[default] run-fail + //@[abort-zero] compile-flags: -Cpanic=abort //@[abort-zero] no-prefer-dynamic //@[abort-zero] exec-env:RUST_BACKTRACE=0 +//@[abort-zero] run-crash //@[abort-one] compile-flags: -Cpanic=abort //@[abort-one] no-prefer-dynamic //@[abort-one] exec-env:RUST_BACKTRACE=1 +//@[abort-one] run-crash //@[abort-full] compile-flags: -Cpanic=abort //@[abort-full] no-prefer-dynamic //@[abort-full] exec-env:RUST_BACKTRACE=full +//@[abort-full] run-crash //@[unwind-zero] compile-flags: -Cpanic=unwind //@[unwind-zero] exec-env:RUST_BACKTRACE=0 //@[unwind-zero] needs-unwind +//@[unwind-zero] run-fail //@[unwind-one] compile-flags: -Cpanic=unwind //@[unwind-one] exec-env:RUST_BACKTRACE=1 //@[unwind-one] needs-unwind +//@[unwind-one] run-fail //@[unwind-full] compile-flags: -Cpanic=unwind //@[unwind-full] exec-env:RUST_BACKTRACE=full //@[unwind-full] needs-unwind +//@[unwind-full] run-fail -//@ run-fail //@ error-pattern:moop //@ needs-subprocess diff --git a/tests/ui/precondition-checks/alignment.rs b/tests/ui/precondition-checks/alignment.rs index 92400528fa07..038a625bed7e 100644 --- a/tests/ui/precondition-checks/alignment.rs +++ b/tests/ui/precondition-checks/alignment.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: Alignment::new_unchecked requires diff --git a/tests/ui/precondition-checks/ascii-char-digit_unchecked.rs b/tests/ui/precondition-checks/ascii-char-digit_unchecked.rs index 30c6f79fb08f..41ba2c5254a4 100644 --- a/tests/ui/precondition-checks/ascii-char-digit_unchecked.rs +++ b/tests/ui/precondition-checks/ascii-char-digit_unchecked.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: `ascii::Char::digit_unchecked` input cannot exceed 9 diff --git a/tests/ui/precondition-checks/assert_unchecked.rs b/tests/ui/precondition-checks/assert_unchecked.rs index 22b2b4145502..da5383cdea02 100644 --- a/tests/ui/precondition-checks/assert_unchecked.rs +++ b/tests/ui/precondition-checks/assert_unchecked.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: hint::assert_unchecked must never be called when the condition is false diff --git a/tests/ui/precondition-checks/char-from_u32_unchecked.rs b/tests/ui/precondition-checks/char-from_u32_unchecked.rs index d950f20c7720..7c34d926d3e9 100644 --- a/tests/ui/precondition-checks/char-from_u32_unchecked.rs +++ b/tests/ui/precondition-checks/char-from_u32_unchecked.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: invalid value for `char` diff --git a/tests/ui/precondition-checks/copy-nonoverlapping.rs b/tests/ui/precondition-checks/copy-nonoverlapping.rs index eacaa63e543a..1d584ddef4c2 100644 --- a/tests/ui/precondition-checks/copy-nonoverlapping.rs +++ b/tests/ui/precondition-checks/copy-nonoverlapping.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::copy_nonoverlapping requires //@ revisions: null_src null_dst misaligned_src misaligned_dst overlapping diff --git a/tests/ui/precondition-checks/copy.rs b/tests/ui/precondition-checks/copy.rs index 1fadd90bf70b..8faa56a880ea 100644 --- a/tests/ui/precondition-checks/copy.rs +++ b/tests/ui/precondition-checks/copy.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::copy requires //@ revisions: null_src null_dst misaligned_src misaligned_dst diff --git a/tests/ui/precondition-checks/layout.rs b/tests/ui/precondition-checks/layout.rs index 4ee66cc93288..6755ebce854e 100644 --- a/tests/ui/precondition-checks/layout.rs +++ b/tests/ui/precondition-checks/layout.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: Layout::from_size_align_unchecked requires //@ revisions: toolarge badalign diff --git a/tests/ui/precondition-checks/nonnull.rs b/tests/ui/precondition-checks/nonnull.rs index 6b8edd4e5825..75bbd65b4868 100644 --- a/tests/ui/precondition-checks/nonnull.rs +++ b/tests/ui/precondition-checks/nonnull.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: NonNull::new_unchecked requires diff --git a/tests/ui/precondition-checks/nonzero-from_mut_unchecked.rs b/tests/ui/precondition-checks/nonzero-from_mut_unchecked.rs index 46ce7dc356fe..d55707fdd0be 100644 --- a/tests/ui/precondition-checks/nonzero-from_mut_unchecked.rs +++ b/tests/ui/precondition-checks/nonzero-from_mut_unchecked.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: NonZero::from_mut_unchecked requires diff --git a/tests/ui/precondition-checks/nonzero-new_unchecked.rs b/tests/ui/precondition-checks/nonzero-new_unchecked.rs index 7827a42844fd..978f01f150f0 100644 --- a/tests/ui/precondition-checks/nonzero-new_unchecked.rs +++ b/tests/ui/precondition-checks/nonzero-new_unchecked.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: NonZero::new_unchecked requires diff --git a/tests/ui/precondition-checks/read_volatile.rs b/tests/ui/precondition-checks/read_volatile.rs index ada8932c398c..fa1c2c827d74 100644 --- a/tests/ui/precondition-checks/read_volatile.rs +++ b/tests/ui/precondition-checks/read_volatile.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::read_volatile requires //@ revisions: null misaligned diff --git a/tests/ui/precondition-checks/replace.rs b/tests/ui/precondition-checks/replace.rs index 44afbd8174c0..447a00c65723 100644 --- a/tests/ui/precondition-checks/replace.rs +++ b/tests/ui/precondition-checks/replace.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::replace requires //@ revisions: null misaligned diff --git a/tests/ui/precondition-checks/slice-from-raw-parts-mut.rs b/tests/ui/precondition-checks/slice-from-raw-parts-mut.rs index 9b9ded69a83b..b6397ab2a12b 100644 --- a/tests/ui/precondition-checks/slice-from-raw-parts-mut.rs +++ b/tests/ui/precondition-checks/slice-from-raw-parts-mut.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts_mut requires //@ revisions: null misaligned toolarge diff --git a/tests/ui/precondition-checks/slice-from-raw-parts.rs b/tests/ui/precondition-checks/slice-from-raw-parts.rs index 96578c1eae58..a317e3d41a0f 100644 --- a/tests/ui/precondition-checks/slice-from-raw-parts.rs +++ b/tests/ui/precondition-checks/slice-from-raw-parts.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts requires //@ revisions: null misaligned toolarge diff --git a/tests/ui/precondition-checks/slice-get_unchecked.rs b/tests/ui/precondition-checks/slice-get_unchecked.rs index 1d8188fb9531..7bcb8442540a 100644 --- a/tests/ui/precondition-checks/slice-get_unchecked.rs +++ b/tests/ui/precondition-checks/slice-get_unchecked.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: slice::get_unchecked requires //@ revisions: usize range range_to range_from backwards_range diff --git a/tests/ui/precondition-checks/slice-get_unchecked_mut.rs b/tests/ui/precondition-checks/slice-get_unchecked_mut.rs index 34c1454af438..2ba3227f39ea 100644 --- a/tests/ui/precondition-checks/slice-get_unchecked_mut.rs +++ b/tests/ui/precondition-checks/slice-get_unchecked_mut.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: slice::get_unchecked_mut requires //@ revisions: usize range range_to range_from backwards_range diff --git a/tests/ui/precondition-checks/str-get_unchecked.rs b/tests/ui/precondition-checks/str-get_unchecked.rs index 14d17f997ec9..2273190e9f4c 100644 --- a/tests/ui/precondition-checks/str-get_unchecked.rs +++ b/tests/ui/precondition-checks/str-get_unchecked.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: str::get_unchecked requires //@ revisions: range range_to range_from backwards_range diff --git a/tests/ui/precondition-checks/str-get_unchecked_mut.rs b/tests/ui/precondition-checks/str-get_unchecked_mut.rs index ca1b16900555..53e6ee64d470 100644 --- a/tests/ui/precondition-checks/str-get_unchecked_mut.rs +++ b/tests/ui/precondition-checks/str-get_unchecked_mut.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: str::get_unchecked_mut requires //@ revisions: range range_to range_from backwards_range diff --git a/tests/ui/precondition-checks/swap-nonoverlapping.rs b/tests/ui/precondition-checks/swap-nonoverlapping.rs index ea1f6f36ad78..81ba72382c0d 100644 --- a/tests/ui/precondition-checks/swap-nonoverlapping.rs +++ b/tests/ui/precondition-checks/swap-nonoverlapping.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::swap_nonoverlapping requires //@ revisions: null_src null_dst misaligned_src misaligned_dst overlapping diff --git a/tests/ui/precondition-checks/unchecked_add.rs b/tests/ui/precondition-checks/unchecked_add.rs index f44a6ea32ad8..b7727aeb9682 100644 --- a/tests/ui/precondition-checks/unchecked_add.rs +++ b/tests/ui/precondition-checks/unchecked_add.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: u8::unchecked_add cannot overflow diff --git a/tests/ui/precondition-checks/unchecked_mul.rs b/tests/ui/precondition-checks/unchecked_mul.rs index 66655dda136e..3eea8b66abba 100644 --- a/tests/ui/precondition-checks/unchecked_mul.rs +++ b/tests/ui/precondition-checks/unchecked_mul.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: u8::unchecked_add cannot overflow diff --git a/tests/ui/precondition-checks/unchecked_shl.rs b/tests/ui/precondition-checks/unchecked_shl.rs index 1c96db0b1ec7..57c617e08455 100644 --- a/tests/ui/precondition-checks/unchecked_shl.rs +++ b/tests/ui/precondition-checks/unchecked_shl.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: u8::unchecked_shl cannot overflow diff --git a/tests/ui/precondition-checks/unchecked_shr.rs b/tests/ui/precondition-checks/unchecked_shr.rs index 4a6d9ffb1d35..18502d2b6459 100644 --- a/tests/ui/precondition-checks/unchecked_shr.rs +++ b/tests/ui/precondition-checks/unchecked_shr.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: u8::unchecked_shr cannot overflow diff --git a/tests/ui/precondition-checks/unchecked_sub.rs b/tests/ui/precondition-checks/unchecked_sub.rs index 545dde0e2780..bfe8f5849f59 100644 --- a/tests/ui/precondition-checks/unchecked_sub.rs +++ b/tests/ui/precondition-checks/unchecked_sub.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: u8::unchecked_sub cannot overflow diff --git a/tests/ui/precondition-checks/unreachable_unchecked.rs b/tests/ui/precondition-checks/unreachable_unchecked.rs index 2435450c4b5a..f2855d03a3e7 100644 --- a/tests/ui/precondition-checks/unreachable_unchecked.rs +++ b/tests/ui/precondition-checks/unreachable_unchecked.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: hint::unreachable_unchecked must never be reached diff --git a/tests/ui/precondition-checks/vec-from-parts.rs b/tests/ui/precondition-checks/vec-from-parts.rs index 0bafb5aa715e..ace90770360e 100644 --- a/tests/ui/precondition-checks/vec-from-parts.rs +++ b/tests/ui/precondition-checks/vec-from-parts.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Cdebug-assertions=yes //@ error-pattern: unsafe precondition(s) violated: Vec::from_parts_in requires that length <= capacity #![feature(allocator_api)] diff --git a/tests/ui/precondition-checks/vec-from-raw-parts.rs b/tests/ui/precondition-checks/vec-from-raw-parts.rs index 884d34c0a564..1bc8e6ada10d 100644 --- a/tests/ui/precondition-checks/vec-from-raw-parts.rs +++ b/tests/ui/precondition-checks/vec-from-raw-parts.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Cdebug-assertions=yes //@ error-pattern: unsafe precondition(s) violated: Vec::from_raw_parts_in requires that length <= capacity //@ revisions: vec_from_raw_parts vec_from_raw_parts_in string_from_raw_parts diff --git a/tests/ui/precondition-checks/vec-set-len.rs b/tests/ui/precondition-checks/vec-set-len.rs index 0987e7fe0282..c6bdee7dc67e 100644 --- a/tests/ui/precondition-checks/vec-set-len.rs +++ b/tests/ui/precondition-checks/vec-set-len.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Cdebug-assertions=yes //@ error-pattern: unsafe precondition(s) violated: Vec::set_len requires that new_len <= capacity() diff --git a/tests/ui/precondition-checks/write_volatile.rs b/tests/ui/precondition-checks/write_volatile.rs index 0d5ecb014b3d..25107871c39c 100644 --- a/tests/ui/precondition-checks/write_volatile.rs +++ b/tests/ui/precondition-checks/write_volatile.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::write_volatile requires //@ revisions: null misaligned diff --git a/tests/ui/sanitizer/address.rs b/tests/ui/sanitizer/address.rs index 7a5e767687cf..704d84764c16 100644 --- a/tests/ui/sanitizer/address.rs +++ b/tests/ui/sanitizer/address.rs @@ -4,7 +4,7 @@ // //@ compile-flags: -Z sanitizer=address -O -g // -//@ run-fail +//@ run-fail-or-crash //@ error-pattern: AddressSanitizer: stack-buffer-overflow //@ error-pattern: 'xs' (line 14) <== Memory access at offset diff --git a/tests/ui/sanitizer/badfree.rs b/tests/ui/sanitizer/badfree.rs index ecbb58eba00d..6b3aea7239c2 100644 --- a/tests/ui/sanitizer/badfree.rs +++ b/tests/ui/sanitizer/badfree.rs @@ -4,7 +4,7 @@ // //@ compile-flags: -Z sanitizer=address -O // -//@ run-fail +//@ run-fail-or-crash //@ regex-error-pattern: AddressSanitizer: (SEGV|attempting free on address which was not malloc) use std::ffi::c_void; diff --git a/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs b/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs index b7dd4a437821..c1a2c2f26ace 100644 --- a/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs +++ b/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs @@ -11,7 +11,7 @@ //@ compile-flags: -Zsanitizer=address -Clto=thin //@[opt0]compile-flags: -Copt-level=0 //@[opt1]compile-flags: -Copt-level=1 -//@ run-fail +//@ run-fail-or-crash //@ error-pattern: ERROR: AddressSanitizer: stack-use-after-scope static mut P: *mut usize = std::ptr::null_mut(); diff --git a/tests/ui/sanitizer/thread.rs b/tests/ui/sanitizer/thread.rs index 566774d6b1d6..9073124d1bd3 100644 --- a/tests/ui/sanitizer/thread.rs +++ b/tests/ui/sanitizer/thread.rs @@ -15,7 +15,7 @@ // //@ compile-flags: -Z sanitizer=thread -O // -//@ run-fail +//@ run-fail-or-crash //@ error-pattern: WARNING: ThreadSanitizer: data race //@ error-pattern: Location is heap block of size 4 //@ error-pattern: allocated by main thread diff --git a/tests/ui/sanitizer/use-after-scope.rs b/tests/ui/sanitizer/use-after-scope.rs index 4d7f6f6c2f2b..106dc6466d6a 100644 --- a/tests/ui/sanitizer/use-after-scope.rs +++ b/tests/ui/sanitizer/use-after-scope.rs @@ -3,7 +3,7 @@ //@ ignore-cross-compile // //@ compile-flags: -Zsanitizer=address -//@ run-fail +//@ run-fail-or-crash //@ error-pattern: ERROR: AddressSanitizer: stack-use-after-scope static mut P: *mut usize = std::ptr::null_mut(); diff --git a/tests/ui/std/issue-81357-unsound-file-methods.rs b/tests/ui/std/issue-81357-unsound-file-methods.rs index 838df40c32d7..99bd31aa2608 100644 --- a/tests/ui/std/issue-81357-unsound-file-methods.rs +++ b/tests/ui/std/issue-81357-unsound-file-methods.rs @@ -1,4 +1,4 @@ -//@ run-fail +//@ run-crash //@ only-windows fn main() { From ca01e7de6fae15337df4b612869353523b3c947d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nurzhan=20Sak=C3=A9n?= Date: Mon, 7 Jul 2025 22:48:18 +0400 Subject: [PATCH 342/363] Stabilize `const_float_round_methods` --- library/core/src/num/f128.rs | 6 ------ library/core/src/num/f16.rs | 6 ------ library/core/src/num/f32.rs | 6 ------ library/core/src/num/f64.rs | 6 ------ library/coretests/tests/lib.rs | 1 - library/std/src/lib.rs | 1 - library/std/src/num/f32.rs | 12 ++++++------ library/std/src/num/f64.rs | 12 ++++++------ 8 files changed, 12 insertions(+), 38 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 4c09c930c796..69e6c100e763 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1448,7 +1448,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(self) -> f128 { // SAFETY: intrinsic with no preconditions @@ -1478,7 +1477,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn ceil(self) -> f128 { // SAFETY: intrinsic with no preconditions @@ -1514,7 +1512,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round(self) -> f128 { // SAFETY: intrinsic with no preconditions @@ -1548,7 +1545,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round_ties_even(self) -> f128 { intrinsics::round_ties_even_f128(self) @@ -1580,7 +1576,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn trunc(self) -> f128 { // SAFETY: intrinsic with no preconditions @@ -1611,7 +1606,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn fract(self) -> f128 { self - self.trunc() diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 1d98a485c4f7..b66cef03d200 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1424,7 +1424,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(self) -> f16 { // SAFETY: intrinsic with no preconditions @@ -1454,7 +1453,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn ceil(self) -> f16 { // SAFETY: intrinsic with no preconditions @@ -1490,7 +1488,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round(self) -> f16 { // SAFETY: intrinsic with no preconditions @@ -1524,7 +1521,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round_ties_even(self) -> f16 { intrinsics::round_ties_even_f16(self) @@ -1556,7 +1552,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn trunc(self) -> f16 { // SAFETY: intrinsic with no preconditions @@ -1587,7 +1582,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn fract(self) -> f16 { self - self.trunc() diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index b460c7d0205b..f8344da79ad4 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1591,7 +1591,6 @@ pub mod math { /// [`f32::floor`]: ../../../std/primitive.f32.html#method.floor #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions @@ -1622,7 +1621,6 @@ pub mod math { #[doc(alias = "ceiling")] #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] pub const fn ceil(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::ceilf32(x) } @@ -1657,7 +1655,6 @@ pub mod math { #[inline] #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] pub const fn round(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::roundf32(x) } @@ -1691,7 +1688,6 @@ pub mod math { #[inline] #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] pub const fn round_ties_even(x: f32) -> f32 { intrinsics::round_ties_even_f32(x) } @@ -1722,7 +1718,6 @@ pub mod math { #[doc(alias = "truncate")] #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] pub const fn trunc(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::truncf32(x) } @@ -1752,7 +1747,6 @@ pub mod math { /// [`f32::fract`]: ../../../std/primitive.f32.html#method.fract #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn fract(x: f32) -> f32 { x - trunc(x) diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 3cd079b84eb4..93da63c896e2 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1589,7 +1589,6 @@ pub mod math { /// [`f64::floor`]: ../../../std/primitive.f64.html#method.floor #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions @@ -1619,7 +1618,6 @@ pub mod math { #[inline] #[doc(alias = "ceiling")] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn ceil(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions @@ -1654,7 +1652,6 @@ pub mod math { /// [`f64::round`]: ../../../std/primitive.f64.html#method.round #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions @@ -1688,7 +1685,6 @@ pub mod math { /// [`f64::round_ties_even`]: ../../../std/primitive.f64.html#method.round_ties_even #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round_ties_even(x: f64) -> f64 { intrinsics::round_ties_even_f64(x) @@ -1719,7 +1715,6 @@ pub mod math { #[inline] #[doc(alias = "truncate")] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn trunc(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions @@ -1750,7 +1745,6 @@ pub mod math { /// [`f64::fract`]: ../../../std/primitive.f64.html#method.fract #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn fract(x: f64) -> f64 { x - trunc(x) diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index e2249bd7f6a1..4cfac9ecc2ab 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -19,7 +19,6 @@ #![feature(const_deref)] #![feature(const_destruct)] #![feature(const_eval_select)] -#![feature(const_float_round_methods)] #![feature(const_ops)] #![feature(const_ref_cell)] #![feature(const_trait_impl)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 311b2cb93239..323742a75b05 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -329,7 +329,6 @@ #![feature(bstr_internals)] #![feature(char_internals)] #![feature(clone_to_uninit)] -#![feature(const_float_round_methods)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(duration_constants)] diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index e79ec2ae966f..2bff73add33d 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -44,7 +44,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn floor(self) -> f32 { core::f32::math::floor(self) @@ -67,7 +67,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn ceil(self) -> f32 { core::f32::math::ceil(self) @@ -96,7 +96,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn round(self) -> f32 { core::f32::math::round(self) @@ -123,7 +123,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "round_ties_even", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn round_ties_even(self) -> f32 { core::f32::math::round_ties_even(self) @@ -149,7 +149,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn trunc(self) -> f32 { core::f32::math::trunc(self) @@ -173,7 +173,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn fract(self) -> f32 { core::f32::math::fract(self) diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 853417825f97..b71e319f4074 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -44,7 +44,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn floor(self) -> f64 { core::f64::math::floor(self) @@ -67,7 +67,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn ceil(self) -> f64 { core::f64::math::ceil(self) @@ -96,7 +96,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn round(self) -> f64 { core::f64::math::round(self) @@ -123,7 +123,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "round_ties_even", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn round_ties_even(self) -> f64 { core::f64::math::round_ties_even(self) @@ -149,7 +149,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn trunc(self) -> f64 { core::f64::math::trunc(self) @@ -173,7 +173,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn fract(self) -> f64 { core::f64::math::fract(self) From caf4f111bc371d148eb6b2e01dcadc90b4a8b877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nurzhan=20Sak=C3=A9n?= Date: Mon, 7 Jul 2025 23:23:11 +0400 Subject: [PATCH 343/363] Add `#[rustc_intrinsic_const_stable_indirect]` to float rounding intrinsics --- library/core/src/intrinsics/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index f90e6851d1f5..106cc725fee2 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1379,6 +1379,7 @@ pub unsafe fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::floor`](../../std/primitive.f16.html#method.floor) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn floorf16(x: f16) -> f16; @@ -1386,6 +1387,7 @@ pub const unsafe fn floorf16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::floor`](../../std/primitive.f32.html#method.floor) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn floorf32(x: f32) -> f32; @@ -1393,6 +1395,7 @@ pub const unsafe fn floorf32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::floor`](../../std/primitive.f64.html#method.floor) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn floorf64(x: f64) -> f64; @@ -1400,6 +1403,7 @@ pub const unsafe fn floorf64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::floor`](../../std/primitive.f128.html#method.floor) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn floorf128(x: f128) -> f128; @@ -1408,6 +1412,7 @@ pub const unsafe fn floorf128(x: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::ceil`](../../std/primitive.f16.html#method.ceil) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn ceilf16(x: f16) -> f16; @@ -1415,6 +1420,7 @@ pub const unsafe fn ceilf16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::ceil`](../../std/primitive.f32.html#method.ceil) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn ceilf32(x: f32) -> f32; @@ -1422,6 +1428,7 @@ pub const unsafe fn ceilf32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn ceilf64(x: f64) -> f64; @@ -1429,6 +1436,7 @@ pub const unsafe fn ceilf64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::ceil`](../../std/primitive.f128.html#method.ceil) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn ceilf128(x: f128) -> f128; @@ -1437,6 +1445,7 @@ pub const unsafe fn ceilf128(x: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::trunc`](../../std/primitive.f16.html#method.trunc) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn truncf16(x: f16) -> f16; @@ -1444,6 +1453,7 @@ pub const unsafe fn truncf16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::trunc`](../../std/primitive.f32.html#method.trunc) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn truncf32(x: f32) -> f32; @@ -1451,6 +1461,7 @@ pub const unsafe fn truncf32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn truncf64(x: f64) -> f64; @@ -1458,6 +1469,7 @@ pub const unsafe fn truncf64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::trunc`](../../std/primitive.f128.html#method.trunc) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn truncf128(x: f128) -> f128; @@ -1467,6 +1479,7 @@ pub const unsafe fn truncf128(x: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn round_ties_even_f16(x: f16) -> f16; @@ -1476,6 +1489,7 @@ pub const fn round_ties_even_f16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn round_ties_even_f32(x: f32) -> f32; @@ -1485,6 +1499,7 @@ pub const fn round_ties_even_f32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn round_ties_even_f64(x: f64) -> f64; @@ -1494,6 +1509,7 @@ pub const fn round_ties_even_f64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn round_ties_even_f128(x: f128) -> f128; @@ -1502,6 +1518,7 @@ pub const fn round_ties_even_f128(x: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::round`](../../std/primitive.f16.html#method.round) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn roundf16(x: f16) -> f16; @@ -1509,6 +1526,7 @@ pub const unsafe fn roundf16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::round`](../../std/primitive.f32.html#method.round) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn roundf32(x: f32) -> f32; @@ -1516,6 +1534,7 @@ pub const unsafe fn roundf32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::round`](../../std/primitive.f64.html#method.round) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn roundf64(x: f64) -> f64; @@ -1523,6 +1542,7 @@ pub const unsafe fn roundf64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::round`](../../std/primitive.f128.html#method.round) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn roundf128(x: f128) -> f128; From 2f14d0a65d7ec8ee35e7f25ddd996ae40615a2a3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 19 Jul 2025 22:29:13 +0200 Subject: [PATCH 344/363] Add code comment explaining better what `Row.name` is for doc aliases --- src/librustdoc/html/static/js/rustdoc.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index 9ce24d1c06f6..a95897645478 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -219,6 +219,8 @@ declare namespace rustdoc { crate: string, descShard: SearchDescShard, id: number, + // This is the name of the item. For doc aliases, if you want the name of the aliased + // item, take a look at `Row.original.name`. name: string, normalizedName: string, word: string, From 14d097f6418eacf58e300abfb1531111192e9767 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 18 Jul 2025 17:19:33 -0700 Subject: [PATCH 345/363] Give a message with a span on validation error --- compiler/rustc_mir_transform/src/validate.rs | 18 ++++++++++-------- .../miri/tests/panic/mir-validation.stderr | 14 ++++++++++---- tests/ui/mir/validate/critical-edge.rs | 4 ++-- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index cbb9bbfd12f9..659ca4df159d 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -119,14 +119,16 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { #[track_caller] fn fail(&self, location: Location, msg: impl AsRef) { // We might see broken MIR when other errors have already occurred. - assert!( - self.tcx.dcx().has_errors().is_some(), - "broken MIR in {:?} ({}) at {:?}:\n{}", - self.body.source.instance, - self.when, - location, - msg.as_ref(), - ); + if self.tcx.dcx().has_errors().is_none() { + span_bug!( + self.body.source_info(location).span, + "broken MIR in {:?} ({}) at {:?}:\n{}", + self.body.source.instance, + self.when, + location, + msg.as_ref(), + ); + } } fn check_edge(&mut self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) { diff --git a/src/tools/miri/tests/panic/mir-validation.stderr b/src/tools/miri/tests/panic/mir-validation.stderr index dc70d129da3c..f801ac907e6b 100644 --- a/src/tools/miri/tests/panic/mir-validation.stderr +++ b/src/tools/miri/tests/panic/mir-validation.stderr @@ -1,11 +1,15 @@ +error: internal compiler error: compiler/rustc_mir_transform/src/validate.rs:LL:CC: broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]: + place (*(_2.0: *mut i32)) has deref as a later projection (it is only permitted as the first projection) + --> tests/panic/mir-validation.rs:LL:CC + | +LL | *(tuple.0) = 1; + | ^^^^^^^^^^^^^^ + thread 'rustc' panicked at compiler/rustc_mir_transform/src/validate.rs:LL:CC: -broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]: -place (*(_2.0: *mut i32)) has deref as a later projection (it is only permitted as the first projection) +Box stack backtrace: -error: the compiler unexpectedly panicked. this is a bug. - @@ -20,3 +24,5 @@ LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | +error: aborting due to 1 previous error + diff --git a/tests/ui/mir/validate/critical-edge.rs b/tests/ui/mir/validate/critical-edge.rs index 2a3bf6a6181b..7fe3891d6424 100644 --- a/tests/ui/mir/validate/critical-edge.rs +++ b/tests/ui/mir/validate/critical-edge.rs @@ -21,6 +21,8 @@ pub fn f(a: u32) -> u32 { } bb1 = { Call(RET = f(1), ReturnTo(bb2), UnwindTerminate(ReasonAbi)) +//~^ ERROR broken MIR in Item +//~| ERROR encountered critical edge in `Call` terminator } bb2 = { @@ -29,5 +31,3 @@ pub fn f(a: u32) -> u32 { } } } - -//~? RAW encountered critical edge in `Call` terminator From db1449aed549ea8f7f4b1809cf262e70dbf00eeb Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 19 Jul 2025 22:05:25 +0000 Subject: [PATCH 346/363] Initialize mingw for the runner's user --- .github/workflows/ci.yml | 5 ----- src/ci/scripts/install-mingw.sh | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc8ac539a3a0..e92afc14c20d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -182,11 +182,6 @@ jobs: - name: install MinGW run: src/ci/scripts/install-mingw.sh - # Workaround for spurious ci failures after mingw install - # see https://rust-lang.zulipchat.com/#narrow/channel/242791-t-infra/topic/Spurious.20bors.20CI.20failures/near/528915775 - - name: ensure home dir exists - run: mkdir -p ~ - - name: install ninja run: src/ci/scripts/install-ninja.sh diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index ad852071f295..ed87628659b4 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -43,4 +43,9 @@ if isWindows && isKnownToBeMingwBuild; then curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" 7z x -y mingw.7z > /dev/null ciCommandAddPath "$(cygpath -m "$(pwd)/${mingw_dir}/bin")" + + # Initialize mingw for the user. + # This should be done by github but isn't for some reason. + # (see https://github.com/actions/runner-images/issues/12600) + /c/msys64/usr/bin/bash -lc ' ' fi From 3e5cf9ab86273df68a50e1069555ac74f5e74661 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 20 Jul 2025 00:27:45 +0000 Subject: [PATCH 347/363] cargo update compiler & tools dependencies: Locking 15 packages to latest compatible versions Updating chrono-tz v0.10.3 -> v0.10.4 Removing chrono-tz-build v0.4.1 Updating clap v4.5.40 -> v4.5.41 Updating clap_builder v4.5.40 -> v4.5.41 Updating clap_derive v4.5.40 -> v4.5.41 Updating crc32fast v1.4.2 -> v1.5.0 Updating derive_setters v0.1.7 -> v0.1.8 Updating libredox v0.1.4 -> v0.1.6 Updating measureme v12.0.1 -> v12.0.3 Removing parse-zoneinfo v0.3.1 Adding phf v0.12.1 Adding phf_shared v0.12.1 Updating rustix v1.0.7 -> v1.0.8 Updating serde_json v1.0.140 -> v1.0.141 Updating sysinfo v0.36.0 -> v0.36.1 Updating wasi-preview1-component-adapter-provider v34.0.1 -> v34.0.2 Updating winnow v0.7.11 -> v0.7.12 note: pass `--verbose` to see 39 unchanged dependencies behind latest library dependencies: Locking 0 packages to latest compatible versions note: pass `--verbose` to see 3 unchanged dependencies behind latest rustbook dependencies: Locking 13 packages to latest compatible versions Updating ammonia v4.1.0 -> v4.1.1 Updating cc v1.2.29 -> v1.2.30 Updating clap v4.5.40 -> v4.5.41 Updating clap_builder v4.5.40 -> v4.5.41 Updating clap_complete v4.5.54 -> v4.5.55 Updating clap_derive v4.5.40 -> v4.5.41 Updating crc32fast v1.4.2 -> v1.5.0 Updating html5ever v0.31.0 -> v0.35.0 Updating markup5ever v0.16.2 -> v0.35.0 Updating match_token v0.1.0 -> v0.35.0 Updating rustix v1.0.7 -> v1.0.8 Updating serde_json v1.0.140 -> v1.0.141 Updating winnow v0.7.11 -> v0.7.12 --- Cargo.lock | 110 +++++++++++++++++----------------- src/tools/rustbook/Cargo.lock | 55 +++++++++-------- 2 files changed, 81 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7d2fca8bb3f4..1f7470e96c51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -216,7 +216,7 @@ dependencies = [ "memchr", "serde", "serde_derive", - "winnow 0.7.11", + "winnow 0.7.12", ] [[package]] @@ -470,23 +470,12 @@ dependencies = [ [[package]] name = "chrono-tz" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efdce149c370f133a071ca8ef6ea340b7b88748ab0810097a9e2976eaa34b4f3" +checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" dependencies = [ "chrono", - "chrono-tz-build", - "phf", -] - -[[package]] -name = "chrono-tz-build" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f10f8c9340e31fc120ff885fcdb54a0b48e474bbd77cab557f0c30a3e569402" -dependencies = [ - "parse-zoneinfo", - "phf_codegen", + "phf 0.12.1", ] [[package]] @@ -501,9 +490,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.40" +version = "4.5.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" dependencies = [ "clap_builder", "clap_derive", @@ -521,9 +510,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.40" +version = "4.5.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" +checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" dependencies = [ "anstream", "anstyle", @@ -533,9 +522,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.40" +version = "4.5.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" +checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -798,9 +787,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -989,9 +978,9 @@ dependencies = [ [[package]] name = "derive_setters" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c848e86c87e5cc305313041c5677d4d95d60baa71cf95e5f6ea2554bb629ff" +checksum = "ae5c625eda104c228c06ecaf988d1c60e542176bd7a490e60eeda3493244c0c9" dependencies = [ "darling", "proc-macro2", @@ -2045,9 +2034,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" +checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0" dependencies = [ "bitflags", "libc", @@ -2157,7 +2146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" dependencies = [ "log", - "phf", + "phf 0.11.3", "phf_codegen", "string_cache", "string_cache_codegen", @@ -2196,9 +2185,9 @@ dependencies = [ [[package]] name = "measureme" -version = "12.0.1" +version = "12.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "570a507d8948a66a97f42cbbaf8a6bb9516a51017d4ee949502ad7a10a864395" +checksum = "6ebd1ebda747ae161a4a377bf93f87e18d46faad2331cc0c7d25b84b1d445f49" dependencies = [ "log", "memmap2", @@ -2632,15 +2621,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "parse-zoneinfo" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" -dependencies = [ - "regex", -] - [[package]] name = "pathdiff" version = "0.2.3" @@ -2712,7 +2692,16 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "phf_shared", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +dependencies = [ + "phf_shared 0.12.1", ] [[package]] @@ -2722,7 +2711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ "phf_generator", - "phf_shared", + "phf_shared 0.11.3", ] [[package]] @@ -2731,7 +2720,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ - "phf_shared", + "phf_shared 0.11.3", "rand 0.8.5", ] @@ -2744,6 +2733,15 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -4752,15 +4750,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -4860,9 +4858,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" dependencies = [ "itoa", "memchr", @@ -5027,7 +5025,7 @@ checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" dependencies = [ "new_debug_unreachable", "parking_lot", - "phf_shared", + "phf_shared 0.11.3", "precomputed-hash", "serde", ] @@ -5039,7 +5037,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" dependencies = [ "phf_generator", - "phf_shared", + "phf_shared 0.11.3", "proc-macro2", "quote", ] @@ -5104,9 +5102,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.36.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aab138f5c1bb35231de19049060a87977ad23e04f2303e953bc5c2947ac7dec4" +checksum = "252800745060e7b9ffb7b2badbd8b31cfa4aa2e61af879d0a3bf2a317c20217d" dependencies = [ "libc", "objc2-core-foundation", @@ -5411,7 +5409,7 @@ dependencies = [ "serde_spanned", "toml_datetime", "toml_write", - "winnow 0.7.11", + "winnow 0.7.12", ] [[package]] @@ -5829,9 +5827,9 @@ dependencies = [ [[package]] name = "wasi-preview1-component-adapter-provider" -version = "34.0.1" +version = "34.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafa1e6af9a954a4bcf6ef420c33355d0ce84ddc6afbcba7bb6f05126f9120ae" +checksum = "33696c5f1ff1e083de9f36c3da471abd736362bc173e093f8b0b1ed5a387e39b" [[package]] name = "wasm-bindgen" @@ -6475,9 +6473,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" dependencies = [ "memchr", ] diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 27798d6aeb0b..e363668d4620 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -19,9 +19,9 @@ dependencies = [ [[package]] name = "ammonia" -version = "4.1.0" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ada2ee439075a3e70b6992fce18ac4e407cd05aea9ca3f75d2c0b0c20bbb364" +checksum = "d6b346764dd0814805de8abf899fe03065bcee69bb1a4771c785817e39f3978f" dependencies = [ "cssparser", "html5ever", @@ -156,9 +156,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.29" +version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ "shlex", ] @@ -185,9 +185,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.40" +version = "4.5.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" dependencies = [ "clap_builder", "clap_derive", @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.40" +version = "4.5.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" +checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" dependencies = [ "anstream", "anstyle", @@ -208,18 +208,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.54" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aad5b1b4de04fead402672b48897030eec1f3bfe1550776322f59f6d6e6a5677" +checksum = "a5abde44486daf70c5be8b8f8f1b66c49f86236edf6fa2abadb4d961c4c6229a" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.40" +version = "4.5.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" +checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" dependencies = [ "heck", "proc-macro2", @@ -256,9 +256,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -582,12 +582,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "html5ever" -version = "0.31.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953cbbe631aae7fc0a112702ad5d3aaf09da38beaf45ea84610d6e1c358f569c" +checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4" dependencies = [ "log", - "mac", "markup5ever", "match_token", ] @@ -863,9 +862,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "markup5ever" -version = "0.16.2" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e4cd8c02f18a011991a039855480c64d74291c5792fcc160d55d77dc4de4a39" +checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3" dependencies = [ "log", "tendril", @@ -874,9 +873,9 @@ dependencies = [ [[package]] name = "match_token" -version = "0.1.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf" dependencies = [ "proc-macro2", "quote", @@ -1394,15 +1393,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ "bitflags 2.9.1", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1460,9 +1459,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" dependencies = [ "itoa", "memchr", @@ -2103,9 +2102,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" dependencies = [ "memchr", ] From 56288857d880bf8fc28a7bd49ba8ed99cb8bd318 Mon Sep 17 00:00:00 2001 From: ltdk Date: Thu, 17 Jul 2025 23:22:12 -0400 Subject: [PATCH 348/363] Remove deprecated MaybeUninit slice methods --- library/core/src/mem/maybe_uninit.rs | 114 +-------------------------- 1 file changed, 2 insertions(+), 112 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index fc35e54bb0dc..34d8370da7ec 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1005,28 +1005,6 @@ impl MaybeUninit { } } - /// Deprecated version of [`slice::assume_init_ref`]. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[deprecated( - note = "replaced by inherent assume_init_ref method; will eventually be removed", - since = "1.83.0" - )] - pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { - // SAFETY: Same for both methods. - unsafe { slice.assume_init_ref() } - } - - /// Deprecated version of [`slice::assume_init_mut`]. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[deprecated( - note = "replaced by inherent assume_init_mut method; will eventually be removed", - since = "1.83.0" - )] - pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { - // SAFETY: Same for both methods. - unsafe { slice.assume_init_mut() } - } - /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] @@ -1040,94 +1018,6 @@ impl MaybeUninit { pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } - - /// Deprecated version of [`slice::write_copy_of_slice`]. - #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] - #[deprecated( - note = "replaced by inherent write_copy_of_slice method; will eventually be removed", - since = "1.83.0" - )] - pub fn copy_from_slice<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] - where - T: Copy, - { - this.write_copy_of_slice(src) - } - - /// Deprecated version of [`slice::write_clone_of_slice`]. - #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] - #[deprecated( - note = "replaced by inherent write_clone_of_slice method; will eventually be removed", - since = "1.83.0" - )] - pub fn clone_from_slice<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] - where - T: Clone, - { - this.write_clone_of_slice(src) - } - - /// Deprecated version of [`slice::write_filled`]. - #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - #[deprecated( - note = "replaced by inherent write_filled method; will eventually be removed", - since = "1.83.0" - )] - pub fn fill<'a>(this: &'a mut [MaybeUninit], value: T) -> &'a mut [T] - where - T: Clone, - { - this.write_filled(value) - } - - /// Deprecated version of [`slice::write_with`]. - #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - #[deprecated( - note = "replaced by inherent write_with method; will eventually be removed", - since = "1.83.0" - )] - pub fn fill_with<'a, F>(this: &'a mut [MaybeUninit], mut f: F) -> &'a mut [T] - where - F: FnMut() -> T, - { - this.write_with(|_| f()) - } - - /// Deprecated version of [`slice::write_iter`]. - #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - #[deprecated( - note = "replaced by inherent write_iter method; will eventually be removed", - since = "1.83.0" - )] - pub fn fill_from<'a, I>( - this: &'a mut [MaybeUninit], - it: I, - ) -> (&'a mut [T], &'a mut [MaybeUninit]) - where - I: IntoIterator, - { - this.write_iter(it) - } - - /// Deprecated version of [`slice::as_bytes`]. - #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] - #[deprecated( - note = "replaced by inherent as_bytes method; will eventually be removed", - since = "1.83.0" - )] - pub fn slice_as_bytes(this: &[MaybeUninit]) -> &[MaybeUninit] { - this.as_bytes() - } - - /// Deprecated version of [`slice::as_bytes_mut`]. - #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] - #[deprecated( - note = "replaced by inherent as_bytes_mut method; will eventually be removed", - since = "1.83.0" - )] - pub fn slice_as_bytes_mut(this: &mut [MaybeUninit]) -> &mut [MaybeUninit] { - this.as_bytes_mut() - } } impl [MaybeUninit] { @@ -1304,7 +1194,7 @@ impl [MaybeUninit] { /// Fills a slice with elements returned by calling a closure for each index. /// /// This method uses a closure to create new values. If you'd rather `Clone` a given value, use - /// [`MaybeUninit::fill`]. If you want to use the `Default` trait to generate values, you can + /// [slice::write_filled]. If you want to use the `Default` trait to generate values, you can /// pass [`|_| Default::default()`][Default::default] as the argument. /// /// # Panics @@ -1463,7 +1353,7 @@ impl [MaybeUninit] { /// use std::mem::MaybeUninit; /// /// let mut uninit = [MaybeUninit::::uninit(), MaybeUninit::::uninit()]; - /// let uninit_bytes = MaybeUninit::slice_as_bytes_mut(&mut uninit); + /// let uninit_bytes = uninit.as_bytes_mut(); /// uninit_bytes.write_copy_of_slice(&[0x12, 0x34, 0x56, 0x78]); /// let vals = unsafe { uninit.assume_init_ref() }; /// if cfg!(target_endian = "little") { From 0586c63e070981af7df53e2f778d3e50293d8103 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 9 Jul 2025 23:59:00 -0700 Subject: [PATCH 349/363] Allow `Rvalue::Repeat` to return true in `rvalue_creates_operand` too The conversation in 143502 made be realize how easy this is to handle, since the only possibilty is ZSTs -- everything else ends up with the destination being `LocalKind::Memory` and thus doesn't call `codegen_rvalue_operand` at all. This gets us perilously close to a world where `rvalue_creates_operand` only ever returns true. I'll try out such a world next :) --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 16 ++++++-- tests/codegen/repeat-operand.rs | 39 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 tests/codegen/repeat-operand.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 2587e89417a6..e872f8434e56 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -630,7 +630,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandRef { val: OperandValue::Immediate(static_), layout } } mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand), - mir::Rvalue::Repeat(..) => bug!("{rvalue:?} in codegen_rvalue_operand"), + mir::Rvalue::Repeat(ref elem, len_const) => { + // All arrays have `BackendRepr::Memory`, so only the ZST cases + // end up here. Anything else forces the destination local to be + // `Memory`, and thus ends up handled in `codegen_rvalue` instead. + let operand = self.codegen_operand(bx, elem); + let array_ty = Ty::new_array_with_const_len(bx.tcx(), operand.layout.ty, len_const); + let array_ty = self.monomorphize(array_ty); + let array_layout = bx.layout_of(array_ty); + assert!(array_layout.is_zst()); + OperandRef { val: OperandValue::ZeroSized, layout: array_layout } + } mir::Rvalue::Aggregate(ref kind, ref fields) => { let (variant_index, active_field_index) = match **kind { mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => { @@ -1000,12 +1010,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::NullaryOp(..) | mir::Rvalue::ThreadLocalRef(_) | mir::Rvalue::Use(..) | + mir::Rvalue::Repeat(..) | // (*) mir::Rvalue::Aggregate(..) | // (*) mir::Rvalue::WrapUnsafeBinder(..) => // (*) true, - // Arrays are always aggregates, so it's not worth checking anything here. - // (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.) - mir::Rvalue::Repeat(..) => false, } // (*) this is only true if the type is suitable diff --git a/tests/codegen/repeat-operand.rs b/tests/codegen/repeat-operand.rs new file mode 100644 index 000000000000..6464b35ddcad --- /dev/null +++ b/tests/codegen/repeat-operand.rs @@ -0,0 +1,39 @@ +//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes + +// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`. +// It only applies when the resulting array is a ZST, so the test is written in +// such a way as to keep MIR optimizations from seeing that fact and removing +// the local and statement altogether. (At the time of writing, no other codegen +// test hit that code path, nor did a stage 2 build of the compiler.) + +#![crate_type = "lib"] + +#[repr(transparent)] +pub struct Wrapper([T; N]); + +// CHECK-LABEL: define {{.+}}do_repeat{{.+}}() +// CHECK-NEXT: start: +// CHECK-NOT: alloca +// CHECK-NEXT: ret void +// CHECK-LABEL: define {{.+}}do_repeat{{.+}}(i32 noundef %x) +// CHECK-NEXT: start: +// CHECK-NOT: alloca +// CHECK-NEXT: ret void +#[inline(never)] +pub fn do_repeat(x: T) -> Wrapper { + Wrapper([x; N]) +} + +// CHECK-LABEL: @trigger_repeat_zero_len +#[no_mangle] +pub fn trigger_repeat_zero_len() -> Wrapper { + // CHECK: call void {{.+}}do_repeat{{.+}}(i32 noundef 4) + do_repeat(4) +} + +// CHECK-LABEL: @trigger_repeat_zst +#[no_mangle] +pub fn trigger_repeat_zst() -> Wrapper<(), 8> { + // CHECK: call void {{.+}}do_repeat{{.+}}() + do_repeat(()) +} From 4b8f869c638e6d5090420ff46bd14e7b7d909690 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 19 Jul 2025 20:49:52 -0700 Subject: [PATCH 350/363] Split repeat-operand codegen test Looks like the output it's looking for can be in different orders, so separate tests will fix that. --- ...-operand.rs => repeat-operand-zero-len.rs} | 11 -------- tests/codegen/repeat-operand-zst-elem.rs | 28 +++++++++++++++++++ 2 files changed, 28 insertions(+), 11 deletions(-) rename tests/codegen/{repeat-operand.rs => repeat-operand-zero-len.rs} (77%) create mode 100644 tests/codegen/repeat-operand-zst-elem.rs diff --git a/tests/codegen/repeat-operand.rs b/tests/codegen/repeat-operand-zero-len.rs similarity index 77% rename from tests/codegen/repeat-operand.rs rename to tests/codegen/repeat-operand-zero-len.rs index 6464b35ddcad..b4cec42a07c5 100644 --- a/tests/codegen/repeat-operand.rs +++ b/tests/codegen/repeat-operand-zero-len.rs @@ -11,10 +11,6 @@ #[repr(transparent)] pub struct Wrapper([T; N]); -// CHECK-LABEL: define {{.+}}do_repeat{{.+}}() -// CHECK-NEXT: start: -// CHECK-NOT: alloca -// CHECK-NEXT: ret void // CHECK-LABEL: define {{.+}}do_repeat{{.+}}(i32 noundef %x) // CHECK-NEXT: start: // CHECK-NOT: alloca @@ -30,10 +26,3 @@ pub fn trigger_repeat_zero_len() -> Wrapper { // CHECK: call void {{.+}}do_repeat{{.+}}(i32 noundef 4) do_repeat(4) } - -// CHECK-LABEL: @trigger_repeat_zst -#[no_mangle] -pub fn trigger_repeat_zst() -> Wrapper<(), 8> { - // CHECK: call void {{.+}}do_repeat{{.+}}() - do_repeat(()) -} diff --git a/tests/codegen/repeat-operand-zst-elem.rs b/tests/codegen/repeat-operand-zst-elem.rs new file mode 100644 index 000000000000..c3637759afa3 --- /dev/null +++ b/tests/codegen/repeat-operand-zst-elem.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes + +// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`. +// It only applies when the resulting array is a ZST, so the test is written in +// such a way as to keep MIR optimizations from seeing that fact and removing +// the local and statement altogether. (At the time of writing, no other codegen +// test hit that code path, nor did a stage 2 build of the compiler.) + +#![crate_type = "lib"] + +#[repr(transparent)] +pub struct Wrapper([T; N]); + +// CHECK-LABEL: define {{.+}}do_repeat{{.+}}() +// CHECK-NEXT: start: +// CHECK-NOT: alloca +// CHECK-NEXT: ret void +#[inline(never)] +pub fn do_repeat(x: T) -> Wrapper { + Wrapper([x; N]) +} + +// CHECK-LABEL: @trigger_repeat_zst_elem +#[no_mangle] +pub fn trigger_repeat_zst_elem() -> Wrapper<(), 8> { + // CHECK: call void {{.+}}do_repeat{{.+}}() + do_repeat(()) +} From 9944139f70f2423f572ce48675458ccb67bb8d46 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 18 Jul 2025 11:52:54 +0200 Subject: [PATCH 351/363] Add new `ignore-backends` tests annotations --- src/bootstrap/src/core/build_steps/test.rs | 4 +++ .../rustc-dev-guide/src/tests/directives.md | 1 + src/tools/compiletest/src/common.rs | 34 +++++++++++++++++++ src/tools/compiletest/src/directives.rs | 24 ++++++++++++- src/tools/compiletest/src/lib.rs | 19 ++++++++++- 5 files changed, 80 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 98f111162794..44bcdeacc1ec 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1757,6 +1757,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--host").arg(&*compiler.host.triple); cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.host_target)); + if let Some(codegen_backend) = builder.config.default_codegen_backend(compiler.host) { + cmd.arg("--codegen-backend").arg(&codegen_backend); + } + if builder.build.config.llvm_enzyme { cmd.arg("--has-enzyme"); } diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 6685add461e7..15655d1bb2c9 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -205,6 +205,7 @@ settings: on `wasm32-unknown-unknown` target because the target does not support the `proc-macro` crate type. - `needs-target-std` — ignores if target platform does not have std support. +- `ignore-backends` — ignores the listed backends, separated by whitespace characters. The following directives will check LLVM support: diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index c83070aaba7b..12084fa0b15d 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -175,6 +175,36 @@ pub enum Sanitizer { Hwaddress, } +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum CodegenBackend { + Cranelift, + Gcc, + Llvm, +} + +impl<'a> TryFrom<&'a str> for CodegenBackend { + type Error = &'static str; + + fn try_from(value: &'a str) -> Result { + match value.to_lowercase().as_str() { + "cranelift" => Ok(Self::Cranelift), + "gcc" => Ok(Self::Gcc), + "llvm" => Ok(Self::Llvm), + _ => Err("unknown backend"), + } + } +} + +impl CodegenBackend { + pub fn as_str(self) -> &'static str { + match self { + Self::Cranelift => "cranelift", + Self::Gcc => "gcc", + Self::Llvm => "llvm", + } + } +} + /// Configuration for `compiletest` *per invocation*. /// /// In terms of `bootstrap`, this means that `./x test tests/ui tests/run-make` actually correspond @@ -651,6 +681,9 @@ pub struct Config { /// need `core` stubs in cross-compilation scenarios that do not otherwise want/need to /// `-Zbuild-std`. Used in e.g. ABI tests. pub minicore_path: Utf8PathBuf, + + /// Current codegen backend used. + pub codegen_backend: CodegenBackend, } impl Config { @@ -753,6 +786,7 @@ impl Config { profiler_runtime: Default::default(), diff_command: Default::default(), minicore_path: Default::default(), + codegen_backend: CodegenBackend::Llvm, } } diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 513716357f42..b773956c69fc 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -9,7 +9,7 @@ use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; use tracing::*; -use crate::common::{Config, Debugger, FailMode, PassMode, RunFailMode, TestMode}; +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::needs::CachedNeedsConditions; @@ -818,6 +818,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-arm-unknown-linux-musleabihf", "ignore-auxiliary", "ignore-avr", + "ignore-backends", "ignore-beta", "ignore-cdb", "ignore-compare-mode-next-solver", @@ -1669,6 +1670,7 @@ pub(crate) fn make_test_description( 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!(ignore_cdb(config, ln)); decision!(ignore_gdb(config, ln)); decision!(ignore_lldb(config, ln)); @@ -1795,6 +1797,26 @@ 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") { + for backend in backends_to_ignore.split_whitespace().map(|backend| { + match CodegenBackend::try_from(backend) { + Ok(backend) => backend, + Err(error) => { + panic!("Invalid ignore-backends value `{backend}` in `{path}`: {error}") + } + } + }) { + if config.codegen_backend == backend { + return IgnoreDecision::Ignore { + reason: format!("{} backend is marked as ignore", backend.as_str()), + }; + } + } + } + IgnoreDecision::Continue +} + fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision { if let Some(needed_components) = config.parse_name_value_directive(line, "needs-llvm-components") diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index f3b3605a120d..41bed8ed8a0a 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -39,7 +39,7 @@ use walkdir::WalkDir; use self::directives::{EarlyProps, make_test_description}; use crate::common::{ - CompareMode, Config, Debugger, PassMode, TestMode, TestPaths, UI_EXTENSIONS, + CodegenBackend, CompareMode, Config, Debugger, PassMode, TestMode, TestPaths, UI_EXTENSIONS, expected_output_path, output_base_dir, output_relative_path, }; use crate::directives::DirectivesCache; @@ -203,6 +203,12 @@ pub fn parse_config(args: Vec) -> Config { "debugger", "only test a specific debugger in debuginfo tests", "gdb | lldb | cdb", + ) + .optopt( + "", + "codegen-backend", + "the codegen backend currently used", + "CODEGEN BACKEND NAME", ); let (argv0, args_) = args.split_first().unwrap(); @@ -264,6 +270,15 @@ pub fn parse_config(args: Vec) -> Config { || directives::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), ); + let codegen_backend = match matches.opt_str("codegen-backend").as_deref() { + Some(backend) => match CodegenBackend::try_from(backend) { + Ok(backend) => backend, + Err(error) => panic!("invalid value `{backend}` for `--codegen-backend`: {error}"), + }, + // By default, it's always llvm. + None => CodegenBackend::Llvm, + }; + let run_ignored = matches.opt_present("ignored"); let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions"); let with_std_debug_assertions = matches.opt_present("with-std-debug-assertions"); @@ -449,6 +464,8 @@ pub fn parse_config(args: Vec) -> Config { diff_command: matches.opt_str("compiletest-diff-tool"), minicore_path: opt_path(matches, "minicore-path"), + + codegen_backend, } } From 4a35a9f074f5df8ce0d1f14d8569da3b6badfc01 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 18 Jul 2025 12:05:08 +0200 Subject: [PATCH 352/363] Add new `needs-backends` tests annotations --- .../rustc-dev-guide/src/tests/directives.md | 1 + src/tools/compiletest/src/directives.rs | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 15655d1bb2c9..5c3ae359ba0b 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -206,6 +206,7 @@ settings: `proc-macro` crate type. - `needs-target-std` — ignores if target platform does not have std support. - `ignore-backends` — ignores the listed backends, separated by whitespace characters. +- `needs-backends` — only runs the test if current codegen backend is listed. The following directives will check LLVM support: diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index b773956c69fc..1397c87ab075 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -908,6 +908,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "min-llvm-version", "min-system-llvm-version", "needs-asm-support", + "needs-backends", "needs-crate-type", "needs-deterministic-layouts", "needs-dlltool", @@ -1671,6 +1672,7 @@ pub(crate) fn make_test_description( 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_cdb(config, ln)); decision!(ignore_gdb(config, ln)); decision!(ignore_lldb(config, ln)); @@ -1817,6 +1819,29 @@ 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") { + if !needed_backends + .split_whitespace() + .map(|backend| match CodegenBackend::try_from(backend) { + Ok(backend) => backend, + Err(error) => { + panic!("Invalid needs-backends value `{backend}` in `{path}`: {error}") + } + }) + .any(|backend| config.codegen_backend == backend) + { + return IgnoreDecision::Ignore { + reason: format!( + "{} backend is not part of required backends", + config.codegen_backend.as_str() + ), + }; + } + } + IgnoreDecision::Continue +} + fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision { if let Some(needed_components) = config.parse_name_value_directive(line, "needs-llvm-components") From 08b816ff18347031b1160f1257cde2008c3c366e Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 12 Jul 2025 02:33:42 -0700 Subject: [PATCH 353/363] So many test updates x_x --- tests/auxiliary/minisimd.rs | 160 ++++++++++++++ tests/codegen/const-vector.rs | 38 ++-- .../simd-intrinsic-float-abs.rs | 32 +-- .../simd-intrinsic-float-ceil.rs | 32 +-- .../simd-intrinsic-float-cos.rs | 32 +-- .../simd-intrinsic-float-exp.rs | 32 +-- .../simd-intrinsic-float-exp2.rs | 32 +-- .../simd-intrinsic-float-floor.rs | 32 +-- .../simd-intrinsic-float-fma.rs | 32 +-- .../simd-intrinsic-float-fsqrt.rs | 32 +-- .../simd-intrinsic-float-log.rs | 32 +-- .../simd-intrinsic-float-log10.rs | 32 +-- .../simd-intrinsic-float-log2.rs | 32 +-- .../simd-intrinsic-float-minmax.rs | 8 +- .../simd-intrinsic-float-sin.rs | 32 +-- ...intrinsic-generic-arithmetic-saturating.rs | 63 +----- .../simd-intrinsic-generic-bitmask.rs | 16 +- .../simd-intrinsic-generic-gather.rs | 13 +- .../simd-intrinsic-generic-masked-load.rs | 13 +- .../simd-intrinsic-generic-masked-store.rs | 13 +- .../simd-intrinsic-generic-scatter.rs | 13 +- .../simd-intrinsic-generic-select.rs | 24 +- .../simd-intrinsic-mask-reduce.rs | 13 +- .../simd-intrinsic-transmute-array.rs | 15 +- tests/codegen/simd/aggregate-simd.rs | 10 +- tests/codegen/simd/packed-simd.rs | 12 +- tests/codegen/simd/simd_arith_offset.rs | 12 +- tests/ui/simd/generics.rs | 60 ++--- tests/ui/simd/intrinsic/float-math-pass.rs | 22 +- tests/ui/simd/intrinsic/float-minmax-pass.rs | 16 +- .../simd/intrinsic/generic-arithmetic-pass.rs | 206 ++++++++++-------- .../generic-arithmetic-saturating-pass.rs | 82 ++++--- tests/ui/simd/intrinsic/generic-as.rs | 38 ++-- tests/ui/simd/intrinsic/generic-bswap-byte.rs | 16 +- tests/ui/simd/intrinsic/generic-cast-pass.rs | 38 ++-- .../intrinsic/generic-cast-pointer-width.rs | 16 +- .../simd/intrinsic/generic-comparison-pass.rs | 43 ++-- .../simd/intrinsic/generic-elements-pass.rs | 112 +++++----- .../intrinsic/generic-gather-scatter-pass.rs | 34 +-- .../ui/simd/intrinsic/generic-select-pass.rs | 94 ++++---- .../ui/simd/intrinsic/inlining-issue67557.rs | 20 +- tests/ui/simd/intrinsic/ptr-cast.rs | 16 +- tests/ui/simd/issue-39720.rs | 14 +- tests/ui/simd/issue-85915-simd-ptrs.rs | 32 +-- tests/ui/simd/issue-89193.rs | 22 +- tests/ui/simd/masked-load-store.rs | 10 +- tests/ui/simd/monomorphize-shuffle-index.rs | 12 +- tests/ui/simd/repr_packed.rs | 28 ++- tests/ui/simd/shuffle.rs | 10 +- tests/ui/simd/simd-bitmask-notpow2.rs | 21 +- tests/ui/simd/simd-bitmask.rs | 16 +- tests/ui/simd/target-feature-mixup.rs | 41 ++-- 52 files changed, 797 insertions(+), 1029 deletions(-) create mode 100644 tests/auxiliary/minisimd.rs diff --git a/tests/auxiliary/minisimd.rs b/tests/auxiliary/minisimd.rs new file mode 100644 index 000000000000..ff0c996de1c8 --- /dev/null +++ b/tests/auxiliary/minisimd.rs @@ -0,0 +1,160 @@ +//! Auxiliary crate for tests that need SIMD types. +//! +//! Historically the tests just made their own, but projections into simd types +//! was banned by , which +//! breaks `derive(Clone)`, so this exists to give easily-usable types that can +//! be used without copy-pasting the definitions of the helpers everywhere. +//! +//! This makes no attempt to guard against ICEs. Using it with proper types +//! and such is your responsibility in the tests you write. + +#![allow(unused)] +#![allow(non_camel_case_types)] + +// The field is currently left `pub` for convenience in porting tests, many of +// which attempt to just construct it directly. That still works; it's just the +// `.0` projection that doesn't. +#[repr(simd)] +#[derive(Copy, Eq)] +pub struct Simd(pub [T; N]); + +impl Clone for Simd { + fn clone(&self) -> Self { + *self + } +} + +impl PartialEq for Simd { + fn eq(&self, other: &Self) -> bool { + self.as_array() == other.as_array() + } +} + +impl core::fmt::Debug for Simd { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + <[T; N] as core::fmt::Debug>::fmt(self.as_array(), f) + } +} + +impl core::ops::Index for Simd { + type Output = T; + fn index(&self, i: usize) -> &T { + &self.as_array()[i] + } +} + +impl Simd { + pub const fn from_array(a: [T; N]) -> Self { + Simd(a) + } + pub fn as_array(&self) -> &[T; N] { + let p: *const Self = self; + unsafe { &*p.cast::<[T; N]>() } + } + pub fn into_array(self) -> [T; N] + where + T: Copy, + { + *self.as_array() + } +} + +pub type u8x2 = Simd; +pub type u8x4 = Simd; +pub type u8x8 = Simd; +pub type u8x16 = Simd; +pub type u8x32 = Simd; +pub type u8x64 = Simd; + +pub type u16x2 = Simd; +pub type u16x4 = Simd; +pub type u16x8 = Simd; +pub type u16x16 = Simd; +pub type u16x32 = Simd; + +pub type u32x2 = Simd; +pub type u32x4 = Simd; +pub type u32x8 = Simd; +pub type u32x16 = Simd; + +pub type u64x2 = Simd; +pub type u64x4 = Simd; +pub type u64x8 = Simd; + +pub type u128x2 = Simd; +pub type u128x4 = Simd; + +pub type i8x2 = Simd; +pub type i8x4 = Simd; +pub type i8x8 = Simd; +pub type i8x16 = Simd; +pub type i8x32 = Simd; +pub type i8x64 = Simd; + +pub type i16x2 = Simd; +pub type i16x4 = Simd; +pub type i16x8 = Simd; +pub type i16x16 = Simd; +pub type i16x32 = Simd; + +pub type i32x2 = Simd; +pub type i32x4 = Simd; +pub type i32x8 = Simd; +pub type i32x16 = Simd; + +pub type i64x2 = Simd; +pub type i64x4 = Simd; +pub type i64x8 = Simd; + +pub type i128x2 = Simd; +pub type i128x4 = Simd; + +pub type f32x2 = Simd; +pub type f32x4 = Simd; +pub type f32x8 = Simd; +pub type f32x16 = Simd; + +pub type f64x2 = Simd; +pub type f64x4 = Simd; +pub type f64x8 = Simd; + +// The field is currently left `pub` for convenience in porting tests, many of +// which attempt to just construct it directly. That still works; it's just the +// `.0` projection that doesn't. +#[repr(simd, packed)] +#[derive(Copy)] +pub struct PackedSimd(pub [T; N]); + +impl Clone for PackedSimd { + fn clone(&self) -> Self { + *self + } +} + +impl PartialEq for PackedSimd { + fn eq(&self, other: &Self) -> bool { + self.as_array() == other.as_array() + } +} + +impl core::fmt::Debug for PackedSimd { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + <[T; N] as core::fmt::Debug>::fmt(self.as_array(), f) + } +} + +impl PackedSimd { + pub const fn from_array(a: [T; N]) -> Self { + PackedSimd(a) + } + pub fn as_array(&self) -> &[T; N] { + let p: *const Self = self; + unsafe { &*p.cast::<[T; N]>() } + } + pub fn into_array(self) -> [T; N] + where + T: Copy, + { + *self.as_array() + } +} diff --git a/tests/codegen/const-vector.rs b/tests/codegen/const-vector.rs index 42921442e039..a2249f4fff7b 100644 --- a/tests/codegen/const-vector.rs +++ b/tests/codegen/const-vector.rs @@ -16,18 +16,9 @@ #![feature(mips_target_feature)] #![allow(non_camel_case_types)] -// Setting up structs that can be used as const vectors -#[repr(simd)] -#[derive(Clone)] -pub struct i8x2([i8; 2]); - -#[repr(simd)] -#[derive(Clone)] -pub struct f32x2([f32; 2]); - -#[repr(simd, packed)] -#[derive(Copy, Clone)] -pub struct Simd([T; N]); +#[path = "../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::{PackedSimd as Simd, f32x2, i8x2}; // The following functions are required for the tests to ensure // that they are called with a const vector @@ -45,7 +36,7 @@ extern "unadjusted" { // Ensure the packed variant of the simd struct does not become a const vector // if the size is not a power of 2 -// CHECK: %"Simd" = type { [3 x i32] } +// CHECK: %"minisimd::PackedSimd" = type { [3 x i32] } #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] @@ -54,27 +45,34 @@ extern "unadjusted" { pub fn do_call() { unsafe { // CHECK: call void @test_i8x2(<2 x i8> - test_i8x2(const { i8x2([32, 64]) }); + test_i8x2(const { i8x2::from_array([32, 64]) }); // CHECK: call void @test_i8x2_two_args(<2 x i8> , <2 x i8> - test_i8x2_two_args(const { i8x2([32, 64]) }, const { i8x2([8, 16]) }); + test_i8x2_two_args( + const { i8x2::from_array([32, 64]) }, + const { i8x2::from_array([8, 16]) }, + ); // CHECK: call void @test_i8x2_mixed_args(<2 x i8> , i32 43, <2 x i8> - test_i8x2_mixed_args(const { i8x2([32, 64]) }, 43, const { i8x2([8, 16]) }); + test_i8x2_mixed_args( + const { i8x2::from_array([32, 64]) }, + 43, + const { i8x2::from_array([8, 16]) }, + ); // CHECK: call void @test_i8x2_arr(<2 x i8> - test_i8x2_arr(const { i8x2([32, 64]) }); + test_i8x2_arr(const { i8x2::from_array([32, 64]) }); // CHECK: call void @test_f32x2(<2 x float> - test_f32x2(const { f32x2([0.32, 0.64]) }); + test_f32x2(const { f32x2::from_array([0.32, 0.64]) }); // CHECK: void @test_f32x2_arr(<2 x float> - test_f32x2_arr(const { f32x2([0.32, 0.64]) }); + test_f32x2_arr(const { f32x2::from_array([0.32, 0.64]) }); // CHECK: call void @test_simd(<4 x i32> test_simd(const { Simd::([2, 4, 6, 8]) }); - // CHECK: call void @test_simd_unaligned(%"Simd" %1 + // CHECK: call void @test_simd_unaligned(%"minisimd::PackedSimd" %1 test_simd_unaligned(const { Simd::([2, 4, 6]) }); } } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs index 485ba92272dd..baf445d0a1b3 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs @@ -4,24 +4,12 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_fabs; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); - // CHECK-LABEL: @fabs_32x2 #[no_mangle] pub unsafe fn fabs_32x2(a: f32x2) -> f32x2 { @@ -50,18 +38,6 @@ pub unsafe fn fabs_32x16(a: f32x16) -> f32x16 { simd_fabs(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @fabs_64x4 #[no_mangle] pub unsafe fn fabs_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs index e8bda7c29c4b..096de5692742 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs @@ -4,24 +4,12 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_ceil; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); - // CHECK-LABEL: @ceil_32x2 #[no_mangle] pub unsafe fn ceil_32x2(a: f32x2) -> f32x2 { @@ -50,18 +38,6 @@ pub unsafe fn ceil_32x16(a: f32x16) -> f32x16 { simd_ceil(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @ceil_64x4 #[no_mangle] pub unsafe fn ceil_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs index 8dc967bc3adc..5b2197924bc7 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs @@ -4,24 +4,12 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_fcos; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); - // CHECK-LABEL: @fcos_32x2 #[no_mangle] pub unsafe fn fcos_32x2(a: f32x2) -> f32x2 { @@ -50,18 +38,6 @@ pub unsafe fn fcos_32x16(a: f32x16) -> f32x16 { simd_fcos(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @fcos_64x4 #[no_mangle] pub unsafe fn fcos_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs index 00caca2f2949..d4eadb36c65f 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs @@ -4,24 +4,12 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_fexp; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); - // CHECK-LABEL: @exp_32x2 #[no_mangle] pub unsafe fn exp_32x2(a: f32x2) -> f32x2 { @@ -50,18 +38,6 @@ pub unsafe fn exp_32x16(a: f32x16) -> f32x16 { simd_fexp(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @exp_64x4 #[no_mangle] pub unsafe fn exp_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs index eda4053189cb..d32015b79901 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs @@ -4,24 +4,12 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_fexp2; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); - // CHECK-LABEL: @exp2_32x2 #[no_mangle] pub unsafe fn exp2_32x2(a: f32x2) -> f32x2 { @@ -50,18 +38,6 @@ pub unsafe fn exp2_32x16(a: f32x16) -> f32x16 { simd_fexp2(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @exp2_64x4 #[no_mangle] pub unsafe fn exp2_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs index ad69d4cdd88c..1e1c8ce0c352 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs @@ -4,24 +4,12 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_floor; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); - // CHECK-LABEL: @floor_32x2 #[no_mangle] pub unsafe fn floor_32x2(a: f32x2) -> f32x2 { @@ -50,18 +38,6 @@ pub unsafe fn floor_32x16(a: f32x16) -> f32x16 { simd_floor(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @floor_64x4 #[no_mangle] pub unsafe fn floor_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs index cbeefdc31c0d..982077d81f9a 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs @@ -4,24 +4,12 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_fma; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); - // CHECK-LABEL: @fma_32x2 #[no_mangle] pub unsafe fn fma_32x2(a: f32x2, b: f32x2, c: f32x2) -> f32x2 { @@ -50,18 +38,6 @@ pub unsafe fn fma_32x16(a: f32x16, b: f32x16, c: f32x16) -> f32x16 { simd_fma(a, b, c) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @fma_64x4 #[no_mangle] pub unsafe fn fma_64x4(a: f64x4, b: f64x4, c: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs index 618daa4b44d0..e20a591f573b 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs @@ -4,24 +4,12 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_fsqrt; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); - // CHECK-LABEL: @fsqrt_32x2 #[no_mangle] pub unsafe fn fsqrt_32x2(a: f32x2) -> f32x2 { @@ -50,18 +38,6 @@ pub unsafe fn fsqrt_32x16(a: f32x16) -> f32x16 { simd_fsqrt(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @fsqrt_64x4 #[no_mangle] pub unsafe fn fsqrt_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs index 98a481e4004e..bf1ffc763309 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs @@ -4,24 +4,12 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_flog; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); - // CHECK-LABEL: @log_32x2 #[no_mangle] pub unsafe fn log_32x2(a: f32x2) -> f32x2 { @@ -50,18 +38,6 @@ pub unsafe fn log_32x16(a: f32x16) -> f32x16 { simd_flog(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @log_64x4 #[no_mangle] pub unsafe fn log_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs index 9108cd963f02..ccf484e0e415 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs @@ -4,24 +4,12 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_flog10; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); - // CHECK-LABEL: @log10_32x2 #[no_mangle] pub unsafe fn log10_32x2(a: f32x2) -> f32x2 { @@ -50,18 +38,6 @@ pub unsafe fn log10_32x16(a: f32x16) -> f32x16 { simd_flog10(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @log10_64x4 #[no_mangle] pub unsafe fn log10_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs index 2b20850dbd9a..677d8b01e848 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs @@ -4,24 +4,12 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_flog2; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); - // CHECK-LABEL: @log2_32x2 #[no_mangle] pub unsafe fn log2_32x2(a: f32x2) -> f32x2 { @@ -50,18 +38,6 @@ pub unsafe fn log2_32x16(a: f32x16) -> f32x16 { simd_flog2(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @log2_64x4 #[no_mangle] pub unsafe fn log2_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs index ce07b212e846..8dd464a1bffb 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs @@ -4,11 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::{simd_fmax, simd_fmin}; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); +use std::intrinsics::simd::{simd_fmax, simd_fmin}; // CHECK-LABEL: @fmin #[no_mangle] diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs index 7de26b415bbb..48becc72c0be 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs @@ -4,24 +4,12 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_fsin; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); - // CHECK-LABEL: @fsin_32x2 #[no_mangle] pub unsafe fn fsin_32x2(a: f32x2) -> f32x2 { @@ -50,18 +38,6 @@ pub unsafe fn fsin_32x16(a: f32x16) -> f32x16 { simd_fsin(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @fsin_64x4 #[no_mangle] pub unsafe fn fsin_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs index ecf5eb24ee5b..06d468897152 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs @@ -5,67 +5,12 @@ #![allow(non_camel_case_types)] #![deny(unused)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub}; -#[rustfmt::skip] -mod types { - // signed integer types - - #[repr(simd)] #[derive(Copy, Clone)] pub struct i8x2([i8; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i8x4([i8; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i8x8([i8; 8]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i8x16([i8; 16]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i8x32([i8; 32]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i8x64([i8; 64]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct i16x2([i16; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i16x4([i16; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i16x8([i16; 8]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i16x16([i16; 16]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i16x32([i16; 32]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct i32x2([i32; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i32x4([i32; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i32x8([i32; 8]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i32x16([i32; 16]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct i64x2([i64; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i64x4([i64; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i64x8([i64; 8]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct i128x2([i128; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i128x4([i128; 4]); - - // unsigned integer types - - #[repr(simd)] #[derive(Copy, Clone)] pub struct u8x2([u8; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u8x4([u8; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u8x8([u8; 8]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u8x16([u8; 16]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u8x32([u8; 32]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u8x64([u8; 64]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct u16x2([u16; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u16x4([u16; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u16x8([u16; 8]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u16x16([u16; 16]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u16x32([u16; 32]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct u32x2([u32; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u32x4([u32; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u32x8([u32; 8]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u32x16([u32; 16]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct u64x2([u64; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u64x4([u64; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u64x8([u64; 8]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct u128x2([u128; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u128x4([u128; 4]); -} - -use types::*; - // NOTE(eddyb) `%{{x|0}}` is used because on some targets (e.g. WASM) // SIMD vectors are passed directly, resulting in `%x` being a vector, // while on others they're passed indirectly, resulting in `%x` being diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs index a2c40aa91b51..294262d81526 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs @@ -5,20 +5,12 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_bitmask; -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct u32x2([u32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct i32x2([i32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct i8x16([i8; 16]); - // NOTE(eddyb) `%{{x|1}}` is used because on some targets (e.g. WASM) // SIMD vectors are passed directly, resulting in `%x` being a vector, // while on others they're passed indirectly, resulting in `%x` being diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs index c06b36d68b90..690bfb432f9b 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs @@ -6,15 +6,14 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_gather; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec2(pub [T; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec4(pub [T; 4]); +pub type Vec2 = Simd; +pub type Vec4 = Simd; // CHECK-LABEL: @gather_f32x2 #[no_mangle] diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs index 21578e67cffc..fda315dc66ca 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs @@ -4,15 +4,14 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_masked_load; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec2(pub [T; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec4(pub [T; 4]); +pub type Vec2 = Simd; +pub type Vec4 = Simd; // CHECK-LABEL: @load_f32x2 #[no_mangle] diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs index 22a8f7e54bd3..6ca7388d464b 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs @@ -4,15 +4,14 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_masked_store; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec2(pub [T; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec4(pub [T; 4]); +pub type Vec2 = Simd; +pub type Vec4 = Simd; // CHECK-LABEL: @store_f32x2 #[no_mangle] diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs index 0cc9e6ae59ad..743652966e16 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs @@ -6,15 +6,14 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_scatter; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec2(pub [T; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec4(pub [T; 4]); +pub type Vec2 = Simd; +pub type Vec4 = Simd; // CHECK-LABEL: @scatter_f32x2 #[no_mangle] diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs index f6531c1b23ae..2c0bad21f44b 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs @@ -4,27 +4,13 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{simd_select, simd_select_bitmask}; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8([f32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct b8x4(pub [i8; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct i32x4([i32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct u32x4([u32; 4]); +pub type b8x4 = i8x4; // CHECK-LABEL: @select_m8 #[no_mangle] diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs index 269fe41225ef..79f00a6ed603 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs @@ -4,15 +4,14 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{simd_reduce_all, simd_reduce_any}; -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct mask32x2([i32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct mask8x16([i8; 16]); +pub type mask32x2 = Simd; +pub type mask8x16 = Simd; // NOTE(eddyb) `%{{x|1}}` is used because on some targets (e.g. WASM) // SIMD vectors are passed directly, resulting in `%x` being a vector, diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs index 301f06c2d74a..05c2f7e1bdfc 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -8,13 +8,12 @@ #![allow(non_camel_case_types)] #![feature(repr_simd, core_intrinsics)] -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct S([f32; N]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct T([f32; 4]); +pub type S = Simd; +pub type T = Simd; // CHECK-LABEL: @array_align( #[no_mangle] @@ -34,7 +33,7 @@ pub fn vector_align() -> usize { #[no_mangle] pub fn build_array_s(x: [f32; 4]) -> S<4> { // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) - S::<4>(x) + Simd(x) } // CHECK-LABEL: @build_array_transmute_s @@ -48,7 +47,7 @@ pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> { #[no_mangle] pub fn build_array_t(x: [f32; 4]) -> T { // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) - T(x) + Simd(x) } // CHECK-LABEL: @build_array_transmute_t diff --git a/tests/codegen/simd/aggregate-simd.rs b/tests/codegen/simd/aggregate-simd.rs index 065e429a4c78..57a301d634c8 100644 --- a/tests/codegen/simd/aggregate-simd.rs +++ b/tests/codegen/simd/aggregate-simd.rs @@ -5,15 +5,11 @@ #![no_std] #![crate_type = "lib"] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; use core::intrinsics::simd::{simd_add, simd_extract}; -#[repr(simd)] -#[derive(Clone, Copy)] -pub struct Simd([T; N]); - -#[repr(simd, packed)] -#[derive(Clone, Copy)] -pub struct PackedSimd([T; N]); +use minisimd::*; #[repr(transparent)] pub struct Transparent(T); diff --git a/tests/codegen/simd/packed-simd.rs b/tests/codegen/simd/packed-simd.rs index 73e0d29d7d67..70c03fcc9557 100644 --- a/tests/codegen/simd/packed-simd.rs +++ b/tests/codegen/simd/packed-simd.rs @@ -9,18 +9,14 @@ use core::intrinsics::simd as intrinsics; use core::{mem, ptr}; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::{PackedSimd, Simd as FullSimd}; + // Test codegen for not only "packed" but also "fully aligned" SIMD types, and conversion between // them. A repr(packed,simd) type with 3 elements can't exceed its element alignment, whereas the // same type as repr(simd) will instead have padding. -#[repr(simd, packed)] -#[derive(Copy, Clone)] -pub struct PackedSimd([T; N]); - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct FullSimd([T; N]); - // non-powers-of-two have padding and need to be expanded to full vectors fn load(v: PackedSimd) -> FullSimd { unsafe { diff --git a/tests/codegen/simd/simd_arith_offset.rs b/tests/codegen/simd/simd_arith_offset.rs index b8af6fce3326..210b4e9bb50e 100644 --- a/tests/codegen/simd/simd_arith_offset.rs +++ b/tests/codegen/simd/simd_arith_offset.rs @@ -5,16 +5,14 @@ #![crate_type = "lib"] #![feature(repr_simd, core_intrinsics)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; use std::intrinsics::simd::simd_arith_offset; -/// A vector of *const T. -#[derive(Debug, Copy, Clone)] -#[repr(simd)] -pub struct SimdConstPtr([*const T; LANES]); +use minisimd::*; -#[derive(Debug, Copy, Clone)] -#[repr(simd)] -pub struct Simd([T; LANES]); +/// A vector of *const T. +pub type SimdConstPtr = Simd<*const T, LANES>; // CHECK-LABEL: smoke #[no_mangle] diff --git a/tests/ui/simd/generics.rs b/tests/ui/simd/generics.rs index 1ae08fef7cdf..54e76f7bc5d8 100644 --- a/tests/ui/simd/generics.rs +++ b/tests/ui/simd/generics.rs @@ -2,24 +2,18 @@ #![allow(non_camel_case_types)] #![feature(repr_simd, core_intrinsics)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_add; use std::ops; -#[repr(simd)] -#[derive(Copy, Clone)] -struct f32x4([f32; 4]); +type A = Simd; -#[repr(simd)] -#[derive(Copy, Clone)] -struct A([f32; N]); +type B = Simd; -#[repr(simd)] -#[derive(Copy, Clone)] -struct B([T; 4]); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct C([T; N]); +type C = Simd; fn add>(lhs: T, rhs: T) -> T { lhs + rhs @@ -33,48 +27,24 @@ impl ops::Add for f32x4 { } } -impl ops::Add for A<4> { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - unsafe { simd_add(self, rhs) } - } -} - -impl ops::Add for B { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - unsafe { simd_add(self, rhs) } - } -} - -impl ops::Add for C { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - unsafe { simd_add(self, rhs) } - } -} - pub fn main() { let x = [1.0f32, 2.0f32, 3.0f32, 4.0f32]; let y = [2.0f32, 4.0f32, 6.0f32, 8.0f32]; // lame-o - let a = f32x4([1.0f32, 2.0f32, 3.0f32, 4.0f32]); - let f32x4([a0, a1, a2, a3]) = add(a, a); + let a = f32x4::from_array([1.0f32, 2.0f32, 3.0f32, 4.0f32]); + let [a0, a1, a2, a3] = add(a, a).into_array(); assert_eq!(a0, 2.0f32); assert_eq!(a1, 4.0f32); assert_eq!(a2, 6.0f32); assert_eq!(a3, 8.0f32); - let a = A(x); - assert_eq!(add(a, a).0, y); + let a = A::from_array(x); + assert_eq!(add(a, a).into_array(), y); - let b = B(x); - assert_eq!(add(b, b).0, y); + let b = B::from_array(x); + assert_eq!(add(b, b).into_array(), y); - let c = C(x); - assert_eq!(add(c, c).0, y); + let c = C::from_array(x); + assert_eq!(add(c, c).into_array(), y); } diff --git a/tests/ui/simd/intrinsic/float-math-pass.rs b/tests/ui/simd/intrinsic/float-math-pass.rs index 01fed8537d0b..743aae8d1c31 100644 --- a/tests/ui/simd/intrinsic/float-math-pass.rs +++ b/tests/ui/simd/intrinsic/float-math-pass.rs @@ -11,9 +11,9 @@ #![feature(repr_simd, intrinsics, core_intrinsics)] #![allow(non_camel_case_types)] -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub [f32; 4]); +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; use std::intrinsics::simd::*; @@ -27,19 +27,19 @@ macro_rules! assert_approx_eq { ($a:expr, $b:expr) => {{ let a = $a; let b = $b; - assert_approx_eq_f32!(a.0[0], b.0[0]); - assert_approx_eq_f32!(a.0[1], b.0[1]); - assert_approx_eq_f32!(a.0[2], b.0[2]); - assert_approx_eq_f32!(a.0[3], b.0[3]); + assert_approx_eq_f32!(a[0], b[0]); + assert_approx_eq_f32!(a[1], b[1]); + assert_approx_eq_f32!(a[2], b[2]); + assert_approx_eq_f32!(a[3], b[3]); }}; } fn main() { - let x = f32x4([1.0, 1.0, 1.0, 1.0]); - let y = f32x4([-1.0, -1.0, -1.0, -1.0]); - let z = f32x4([0.0, 0.0, 0.0, 0.0]); + let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]); + let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]); + let z = f32x4::from_array([0.0, 0.0, 0.0, 0.0]); - let h = f32x4([0.5, 0.5, 0.5, 0.5]); + let h = f32x4::from_array([0.5, 0.5, 0.5, 0.5]); unsafe { let r = simd_fabs(y); diff --git a/tests/ui/simd/intrinsic/float-minmax-pass.rs b/tests/ui/simd/intrinsic/float-minmax-pass.rs index 00c0d8cea3fa..12210ba0ad12 100644 --- a/tests/ui/simd/intrinsic/float-minmax-pass.rs +++ b/tests/ui/simd/intrinsic/float-minmax-pass.rs @@ -6,15 +6,15 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub [f32; 4]); +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; use std::intrinsics::simd::*; fn main() { - let x = f32x4([1.0, 2.0, 3.0, 4.0]); - let y = f32x4([2.0, 1.0, 4.0, 3.0]); + let x = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); + let y = f32x4::from_array([2.0, 1.0, 4.0, 3.0]); #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] let nan = f32::NAN; @@ -23,13 +23,13 @@ fn main() { #[cfg(any(target_arch = "mips", target_arch = "mips64"))] let nan = f32::from_bits(f32::NAN.to_bits() - 1); - let n = f32x4([nan, nan, nan, nan]); + let n = f32x4::from_array([nan, nan, nan, nan]); unsafe { let min0 = simd_fmin(x, y); let min1 = simd_fmin(y, x); assert_eq!(min0, min1); - let e = f32x4([1.0, 1.0, 3.0, 3.0]); + let e = f32x4::from_array([1.0, 1.0, 3.0, 3.0]); assert_eq!(min0, e); let minn = simd_fmin(x, n); assert_eq!(minn, x); @@ -39,7 +39,7 @@ fn main() { let max0 = simd_fmax(x, y); let max1 = simd_fmax(y, x); assert_eq!(max0, max1); - let e = f32x4([2.0, 2.0, 4.0, 4.0]); + let e = f32x4::from_array([2.0, 2.0, 4.0, 4.0]); assert_eq!(max0, e); let maxn = simd_fmax(x, n); assert_eq!(maxn, x); diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs index 4c97fb2141d0..bf38a8b17202 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs @@ -2,80 +2,77 @@ #![allow(non_camel_case_types)] #![feature(repr_simd, core_intrinsics)] -#[repr(simd)] -#[derive(Copy, Clone)] -struct i32x4(pub [i32; 4]); +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone)] -struct U32([u32; N]); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct f32x4(pub [f32; 4]); +type U32 = Simd; macro_rules! all_eq { - ($a: expr, $b: expr) => {{ + ($a: expr, $b: expr $(,)?) => {{ let a = $a; let b = $b; - assert!(a.0 == b.0); + assert!(a == b); }}; } use std::intrinsics::simd::*; fn main() { - let x1 = i32x4([1, 2, 3, 4]); - let y1 = U32::<4>([1, 2, 3, 4]); - let z1 = f32x4([1.0, 2.0, 3.0, 4.0]); - let x2 = i32x4([2, 3, 4, 5]); - let y2 = U32::<4>([2, 3, 4, 5]); - let z2 = f32x4([2.0, 3.0, 4.0, 5.0]); - let x3 = i32x4([0, i32::MAX, i32::MIN, -1_i32]); - let y3 = U32::<4>([0, i32::MAX as _, i32::MIN as _, -1_i32 as _]); + let x1 = i32x4::from_array([1, 2, 3, 4]); + let y1 = U32::<4>::from_array([1, 2, 3, 4]); + let z1 = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); + let x2 = i32x4::from_array([2, 3, 4, 5]); + let y2 = U32::<4>::from_array([2, 3, 4, 5]); + let z2 = f32x4::from_array([2.0, 3.0, 4.0, 5.0]); + let x3 = i32x4::from_array([0, i32::MAX, i32::MIN, -1_i32]); + let y3 = U32::<4>::from_array([0, i32::MAX as _, i32::MIN as _, -1_i32 as _]); unsafe { - all_eq!(simd_add(x1, x2), i32x4([3, 5, 7, 9])); - all_eq!(simd_add(x2, x1), i32x4([3, 5, 7, 9])); - all_eq!(simd_add(y1, y2), U32::<4>([3, 5, 7, 9])); - all_eq!(simd_add(y2, y1), U32::<4>([3, 5, 7, 9])); - all_eq!(simd_add(z1, z2), f32x4([3.0, 5.0, 7.0, 9.0])); - all_eq!(simd_add(z2, z1), f32x4([3.0, 5.0, 7.0, 9.0])); + all_eq!(simd_add(x1, x2), i32x4::from_array([3, 5, 7, 9])); + all_eq!(simd_add(x2, x1), i32x4::from_array([3, 5, 7, 9])); + all_eq!(simd_add(y1, y2), U32::<4>::from_array([3, 5, 7, 9])); + all_eq!(simd_add(y2, y1), U32::<4>::from_array([3, 5, 7, 9])); + all_eq!(simd_add(z1, z2), f32x4::from_array([3.0, 5.0, 7.0, 9.0])); + all_eq!(simd_add(z2, z1), f32x4::from_array([3.0, 5.0, 7.0, 9.0])); - all_eq!(simd_mul(x1, x2), i32x4([2, 6, 12, 20])); - all_eq!(simd_mul(x2, x1), i32x4([2, 6, 12, 20])); - all_eq!(simd_mul(y1, y2), U32::<4>([2, 6, 12, 20])); - all_eq!(simd_mul(y2, y1), U32::<4>([2, 6, 12, 20])); - all_eq!(simd_mul(z1, z2), f32x4([2.0, 6.0, 12.0, 20.0])); - all_eq!(simd_mul(z2, z1), f32x4([2.0, 6.0, 12.0, 20.0])); + all_eq!(simd_mul(x1, x2), i32x4::from_array([2, 6, 12, 20])); + all_eq!(simd_mul(x2, x1), i32x4::from_array([2, 6, 12, 20])); + all_eq!(simd_mul(y1, y2), U32::<4>::from_array([2, 6, 12, 20])); + all_eq!(simd_mul(y2, y1), U32::<4>::from_array([2, 6, 12, 20])); + all_eq!(simd_mul(z1, z2), f32x4::from_array([2.0, 6.0, 12.0, 20.0])); + all_eq!(simd_mul(z2, z1), f32x4::from_array([2.0, 6.0, 12.0, 20.0])); - all_eq!(simd_sub(x2, x1), i32x4([1, 1, 1, 1])); - all_eq!(simd_sub(x1, x2), i32x4([-1, -1, -1, -1])); - all_eq!(simd_sub(y2, y1), U32::<4>([1, 1, 1, 1])); - all_eq!(simd_sub(y1, y2), U32::<4>([!0, !0, !0, !0])); - all_eq!(simd_sub(z2, z1), f32x4([1.0, 1.0, 1.0, 1.0])); - all_eq!(simd_sub(z1, z2), f32x4([-1.0, -1.0, -1.0, -1.0])); + all_eq!(simd_sub(x2, x1), i32x4::from_array([1, 1, 1, 1])); + all_eq!(simd_sub(x1, x2), i32x4::from_array([-1, -1, -1, -1])); + all_eq!(simd_sub(y2, y1), U32::<4>::from_array([1, 1, 1, 1])); + all_eq!(simd_sub(y1, y2), U32::<4>::from_array([!0, !0, !0, !0])); + all_eq!(simd_sub(z2, z1), f32x4::from_array([1.0, 1.0, 1.0, 1.0])); + all_eq!(simd_sub(z1, z2), f32x4::from_array([-1.0, -1.0, -1.0, -1.0])); - all_eq!(simd_div(x1, x1), i32x4([1, 1, 1, 1])); - all_eq!(simd_div(i32x4([2, 4, 6, 8]), i32x4([2, 2, 2, 2])), x1); - all_eq!(simd_div(y1, y1), U32::<4>([1, 1, 1, 1])); - all_eq!(simd_div(U32::<4>([2, 4, 6, 8]), U32::<4>([2, 2, 2, 2])), y1); - all_eq!(simd_div(z1, z1), f32x4([1.0, 1.0, 1.0, 1.0])); - all_eq!(simd_div(z1, z2), f32x4([1.0 / 2.0, 2.0 / 3.0, 3.0 / 4.0, 4.0 / 5.0])); - all_eq!(simd_div(z2, z1), f32x4([2.0 / 1.0, 3.0 / 2.0, 4.0 / 3.0, 5.0 / 4.0])); + all_eq!(simd_div(x1, x1), i32x4::from_array([1, 1, 1, 1])); + all_eq!(simd_div(i32x4::from_array([2, 4, 6, 8]), i32x4::from_array([2, 2, 2, 2])), x1); + all_eq!(simd_div(y1, y1), U32::<4>::from_array([1, 1, 1, 1])); + all_eq!( + simd_div(U32::<4>::from_array([2, 4, 6, 8]), U32::<4>::from_array([2, 2, 2, 2])), + y1, + ); + all_eq!(simd_div(z1, z1), f32x4::from_array([1.0, 1.0, 1.0, 1.0])); + all_eq!(simd_div(z1, z2), f32x4::from_array([1.0 / 2.0, 2.0 / 3.0, 3.0 / 4.0, 4.0 / 5.0])); + all_eq!(simd_div(z2, z1), f32x4::from_array([2.0 / 1.0, 3.0 / 2.0, 4.0 / 3.0, 5.0 / 4.0])); - all_eq!(simd_rem(x1, x1), i32x4([0, 0, 0, 0])); - all_eq!(simd_rem(x2, x1), i32x4([0, 1, 1, 1])); - all_eq!(simd_rem(y1, y1), U32::<4>([0, 0, 0, 0])); - all_eq!(simd_rem(y2, y1), U32::<4>([0, 1, 1, 1])); - all_eq!(simd_rem(z1, z1), f32x4([0.0, 0.0, 0.0, 0.0])); + all_eq!(simd_rem(x1, x1), i32x4::from_array([0, 0, 0, 0])); + all_eq!(simd_rem(x2, x1), i32x4::from_array([0, 1, 1, 1])); + all_eq!(simd_rem(y1, y1), U32::<4>::from_array([0, 0, 0, 0])); + all_eq!(simd_rem(y2, y1), U32::<4>::from_array([0, 1, 1, 1])); + all_eq!(simd_rem(z1, z1), f32x4::from_array([0.0, 0.0, 0.0, 0.0])); all_eq!(simd_rem(z1, z2), z1); - all_eq!(simd_rem(z2, z1), f32x4([0.0, 1.0, 1.0, 1.0])); + all_eq!(simd_rem(z2, z1), f32x4::from_array([0.0, 1.0, 1.0, 1.0])); - all_eq!(simd_shl(x1, x2), i32x4([1 << 2, 2 << 3, 3 << 4, 4 << 5])); - all_eq!(simd_shl(x2, x1), i32x4([2 << 1, 3 << 2, 4 << 3, 5 << 4])); - all_eq!(simd_shl(y1, y2), U32::<4>([1 << 2, 2 << 3, 3 << 4, 4 << 5])); - all_eq!(simd_shl(y2, y1), U32::<4>([2 << 1, 3 << 2, 4 << 3, 5 << 4])); + all_eq!(simd_shl(x1, x2), i32x4::from_array([1 << 2, 2 << 3, 3 << 4, 4 << 5])); + all_eq!(simd_shl(x2, x1), i32x4::from_array([2 << 1, 3 << 2, 4 << 3, 5 << 4])); + all_eq!(simd_shl(y1, y2), U32::<4>::from_array([1 << 2, 2 << 3, 3 << 4, 4 << 5])); + all_eq!(simd_shl(y2, y1), U32::<4>::from_array([2 << 1, 3 << 2, 4 << 3, 5 << 4])); // test right-shift by assuming left-shift is correct all_eq!(simd_shr(simd_shl(x1, x2), x2), x1); @@ -85,7 +82,7 @@ fn main() { all_eq!( simd_funnel_shl(x1, x2, x1), - i32x4([ + i32x4::from_array([ (1 << 1) | (2 >> 31), (2 << 2) | (3 >> 30), (3 << 3) | (4 >> 29), @@ -94,7 +91,7 @@ fn main() { ); all_eq!( simd_funnel_shl(x2, x1, x1), - i32x4([ + i32x4::from_array([ (2 << 1) | (1 >> 31), (3 << 2) | (2 >> 30), (4 << 3) | (3 >> 29), @@ -103,7 +100,7 @@ fn main() { ); all_eq!( simd_funnel_shl(y1, y2, y1), - U32::<4>([ + U32::<4>::from_array([ (1 << 1) | (2 >> 31), (2 << 2) | (3 >> 30), (3 << 3) | (4 >> 29), @@ -112,7 +109,7 @@ fn main() { ); all_eq!( simd_funnel_shl(y2, y1, y1), - U32::<4>([ + U32::<4>::from_array([ (2 << 1) | (1 >> 31), (3 << 2) | (2 >> 30), (4 << 3) | (3 >> 29), @@ -122,7 +119,7 @@ fn main() { all_eq!( simd_funnel_shr(x1, x2, x1), - i32x4([ + i32x4::from_array([ (1 << 31) | (2 >> 1), (2 << 30) | (3 >> 2), (3 << 29) | (4 >> 3), @@ -131,7 +128,7 @@ fn main() { ); all_eq!( simd_funnel_shr(x2, x1, x1), - i32x4([ + i32x4::from_array([ (2 << 31) | (1 >> 1), (3 << 30) | (2 >> 2), (4 << 29) | (3 >> 3), @@ -140,7 +137,7 @@ fn main() { ); all_eq!( simd_funnel_shr(y1, y2, y1), - U32::<4>([ + U32::<4>::from_array([ (1 << 31) | (2 >> 1), (2 << 30) | (3 >> 2), (3 << 29) | (4 >> 3), @@ -149,7 +146,7 @@ fn main() { ); all_eq!( simd_funnel_shr(y2, y1, y1), - U32::<4>([ + U32::<4>::from_array([ (2 << 31) | (1 >> 1), (3 << 30) | (2 >> 2), (4 << 29) | (3 >> 3), @@ -159,52 +156,69 @@ fn main() { // ensure we get logical vs. arithmetic shifts correct let (a, b, c, d) = (-12, -123, -1234, -12345); - all_eq!(simd_shr(i32x4([a, b, c, d]), x1), i32x4([a >> 1, b >> 2, c >> 3, d >> 4])); all_eq!( - simd_shr(U32::<4>([a as u32, b as u32, c as u32, d as u32]), y1), - U32::<4>([(a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4]) + simd_shr(i32x4::from_array([a, b, c, d]), x1), + i32x4::from_array([a >> 1, b >> 2, c >> 3, d >> 4]), + ); + all_eq!( + simd_shr(U32::<4>::from_array([a as u32, b as u32, c as u32, d as u32]), y1), + U32::<4>::from_array([ + (a as u32) >> 1, + (b as u32) >> 2, + (c as u32) >> 3, + (d as u32) >> 4, + ]), ); - all_eq!(simd_and(x1, x2), i32x4([0, 2, 0, 4])); - all_eq!(simd_and(x2, x1), i32x4([0, 2, 0, 4])); - all_eq!(simd_and(y1, y2), U32::<4>([0, 2, 0, 4])); - all_eq!(simd_and(y2, y1), U32::<4>([0, 2, 0, 4])); + all_eq!(simd_and(x1, x2), i32x4::from_array([0, 2, 0, 4])); + all_eq!(simd_and(x2, x1), i32x4::from_array([0, 2, 0, 4])); + all_eq!(simd_and(y1, y2), U32::<4>::from_array([0, 2, 0, 4])); + all_eq!(simd_and(y2, y1), U32::<4>::from_array([0, 2, 0, 4])); - all_eq!(simd_or(x1, x2), i32x4([3, 3, 7, 5])); - all_eq!(simd_or(x2, x1), i32x4([3, 3, 7, 5])); - all_eq!(simd_or(y1, y2), U32::<4>([3, 3, 7, 5])); - all_eq!(simd_or(y2, y1), U32::<4>([3, 3, 7, 5])); + all_eq!(simd_or(x1, x2), i32x4::from_array([3, 3, 7, 5])); + all_eq!(simd_or(x2, x1), i32x4::from_array([3, 3, 7, 5])); + all_eq!(simd_or(y1, y2), U32::<4>::from_array([3, 3, 7, 5])); + all_eq!(simd_or(y2, y1), U32::<4>::from_array([3, 3, 7, 5])); - all_eq!(simd_xor(x1, x2), i32x4([3, 1, 7, 1])); - all_eq!(simd_xor(x2, x1), i32x4([3, 1, 7, 1])); - all_eq!(simd_xor(y1, y2), U32::<4>([3, 1, 7, 1])); - all_eq!(simd_xor(y2, y1), U32::<4>([3, 1, 7, 1])); + all_eq!(simd_xor(x1, x2), i32x4::from_array([3, 1, 7, 1])); + all_eq!(simd_xor(x2, x1), i32x4::from_array([3, 1, 7, 1])); + all_eq!(simd_xor(y1, y2), U32::<4>::from_array([3, 1, 7, 1])); + all_eq!(simd_xor(y2, y1), U32::<4>::from_array([3, 1, 7, 1])); - all_eq!(simd_neg(x1), i32x4([-1, -2, -3, -4])); - all_eq!(simd_neg(x2), i32x4([-2, -3, -4, -5])); - all_eq!(simd_neg(z1), f32x4([-1.0, -2.0, -3.0, -4.0])); - all_eq!(simd_neg(z2), f32x4([-2.0, -3.0, -4.0, -5.0])); + all_eq!(simd_neg(x1), i32x4::from_array([-1, -2, -3, -4])); + all_eq!(simd_neg(x2), i32x4::from_array([-2, -3, -4, -5])); + all_eq!(simd_neg(z1), f32x4::from_array([-1.0, -2.0, -3.0, -4.0])); + all_eq!(simd_neg(z2), f32x4::from_array([-2.0, -3.0, -4.0, -5.0])); - all_eq!(simd_bswap(x1), i32x4([0x01000000, 0x02000000, 0x03000000, 0x04000000])); - all_eq!(simd_bswap(y1), U32::<4>([0x01000000, 0x02000000, 0x03000000, 0x04000000])); + all_eq!( + simd_bswap(x1), + i32x4::from_array([0x01000000, 0x02000000, 0x03000000, 0x04000000]), + ); + all_eq!( + simd_bswap(y1), + U32::<4>::from_array([0x01000000, 0x02000000, 0x03000000, 0x04000000]), + ); all_eq!( simd_bitreverse(x1), - i32x4([0x80000000u32 as i32, 0x40000000, 0xc0000000u32 as i32, 0x20000000]) + i32x4::from_array([0x80000000u32 as i32, 0x40000000, 0xc0000000u32 as i32, 0x20000000]) + ); + all_eq!( + simd_bitreverse(y1), + U32::<4>::from_array([0x80000000, 0x40000000, 0xc0000000, 0x20000000]), ); - all_eq!(simd_bitreverse(y1), U32::<4>([0x80000000, 0x40000000, 0xc0000000, 0x20000000])); - all_eq!(simd_ctlz(x1), i32x4([31, 30, 30, 29])); - all_eq!(simd_ctlz(y1), U32::<4>([31, 30, 30, 29])); + all_eq!(simd_ctlz(x1), i32x4::from_array([31, 30, 30, 29])); + all_eq!(simd_ctlz(y1), U32::<4>::from_array([31, 30, 30, 29])); - all_eq!(simd_ctpop(x1), i32x4([1, 1, 2, 1])); - all_eq!(simd_ctpop(y1), U32::<4>([1, 1, 2, 1])); - all_eq!(simd_ctpop(x2), i32x4([1, 2, 1, 2])); - all_eq!(simd_ctpop(y2), U32::<4>([1, 2, 1, 2])); - all_eq!(simd_ctpop(x3), i32x4([0, 31, 1, 32])); - all_eq!(simd_ctpop(y3), U32::<4>([0, 31, 1, 32])); + all_eq!(simd_ctpop(x1), i32x4::from_array([1, 1, 2, 1])); + all_eq!(simd_ctpop(y1), U32::<4>::from_array([1, 1, 2, 1])); + all_eq!(simd_ctpop(x2), i32x4::from_array([1, 2, 1, 2])); + all_eq!(simd_ctpop(y2), U32::<4>::from_array([1, 2, 1, 2])); + all_eq!(simd_ctpop(x3), i32x4::from_array([0, 31, 1, 32])); + all_eq!(simd_ctpop(y3), U32::<4>::from_array([0, 31, 1, 32])); - all_eq!(simd_cttz(x1), i32x4([0, 1, 0, 2])); - all_eq!(simd_cttz(y1), U32::<4>([0, 1, 0, 2])); + all_eq!(simd_cttz(x1), i32x4::from_array([0, 1, 0, 2])); + all_eq!(simd_cttz(y1), U32::<4>::from_array([0, 1, 0, 2])); } } diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs index 4d12a312331a..a997f1237034 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs @@ -4,26 +4,24 @@ #![allow(non_camel_case_types)] #![feature(repr_simd, core_intrinsics)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub}; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct u32x4(pub [u32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct I32([i32; N]); +type I32 = Simd; fn main() { // unsigned { const M: u32 = u32::MAX; - let a = u32x4([1, 2, 3, 4]); - let b = u32x4([2, 4, 6, 8]); - let m = u32x4([M, M, M, M]); - let m1 = u32x4([M - 1, M - 1, M - 1, M - 1]); - let z = u32x4([0, 0, 0, 0]); + let a = u32x4::from_array([1, 2, 3, 4]); + let b = u32x4::from_array([2, 4, 6, 8]); + let m = u32x4::from_array([M, M, M, M]); + let m1 = u32x4::from_array([M - 1, M - 1, M - 1, M - 1]); + let z = u32x4::from_array([0, 0, 0, 0]); unsafe { assert_eq!(simd_saturating_add(z, z), z); @@ -48,41 +46,41 @@ fn main() { const MIN: i32 = i32::MIN; const MAX: i32 = i32::MAX; - let a = I32::<4>([1, 2, 3, 4]); - let b = I32::<4>([2, 4, 6, 8]); - let c = I32::<4>([-1, -2, -3, -4]); - let d = I32::<4>([-2, -4, -6, -8]); + let a = I32::<4>::from_array([1, 2, 3, 4]); + let b = I32::<4>::from_array([2, 4, 6, 8]); + let c = I32::<4>::from_array([-1, -2, -3, -4]); + let d = I32::<4>::from_array([-2, -4, -6, -8]); - let max = I32::<4>([MAX, MAX, MAX, MAX]); - let max1 = I32::<4>([MAX - 1, MAX - 1, MAX - 1, MAX - 1]); - let min = I32::<4>([MIN, MIN, MIN, MIN]); - let min1 = I32::<4>([MIN + 1, MIN + 1, MIN + 1, MIN + 1]); + let max = I32::<4>::from_array([MAX, MAX, MAX, MAX]); + let max1 = I32::<4>::from_array([MAX - 1, MAX - 1, MAX - 1, MAX - 1]); + let min = I32::<4>::from_array([MIN, MIN, MIN, MIN]); + let min1 = I32::<4>::from_array([MIN + 1, MIN + 1, MIN + 1, MIN + 1]); - let z = I32::<4>([0, 0, 0, 0]); + let z = I32::<4>::from_array([0, 0, 0, 0]); unsafe { - assert_eq!(simd_saturating_add(z, z).0, z.0); - assert_eq!(simd_saturating_add(z, a).0, a.0); - assert_eq!(simd_saturating_add(b, z).0, b.0); - assert_eq!(simd_saturating_add(a, a).0, b.0); - assert_eq!(simd_saturating_add(a, max).0, max.0); - assert_eq!(simd_saturating_add(max, b).0, max.0); - assert_eq!(simd_saturating_add(max1, a).0, max.0); - assert_eq!(simd_saturating_add(min1, z).0, min1.0); - assert_eq!(simd_saturating_add(min, z).0, min.0); - assert_eq!(simd_saturating_add(min1, c).0, min.0); - assert_eq!(simd_saturating_add(min, c).0, min.0); - assert_eq!(simd_saturating_add(min1, d).0, min.0); - assert_eq!(simd_saturating_add(min, d).0, min.0); + assert_eq!(simd_saturating_add(z, z), z); + assert_eq!(simd_saturating_add(z, a), a); + assert_eq!(simd_saturating_add(b, z), b); + assert_eq!(simd_saturating_add(a, a), b); + assert_eq!(simd_saturating_add(a, max), max); + assert_eq!(simd_saturating_add(max, b), max); + assert_eq!(simd_saturating_add(max1, a), max); + assert_eq!(simd_saturating_add(min1, z), min1); + assert_eq!(simd_saturating_add(min, z), min); + assert_eq!(simd_saturating_add(min1, c), min); + assert_eq!(simd_saturating_add(min, c), min); + assert_eq!(simd_saturating_add(min1, d), min); + assert_eq!(simd_saturating_add(min, d), min); - assert_eq!(simd_saturating_sub(b, z).0, b.0); - assert_eq!(simd_saturating_sub(b, a).0, a.0); - assert_eq!(simd_saturating_sub(a, a).0, z.0); - assert_eq!(simd_saturating_sub(a, b).0, c.0); - assert_eq!(simd_saturating_sub(z, max).0, min1.0); - assert_eq!(simd_saturating_sub(min1, z).0, min1.0); - assert_eq!(simd_saturating_sub(min1, a).0, min.0); - assert_eq!(simd_saturating_sub(min1, b).0, min.0); + assert_eq!(simd_saturating_sub(b, z), b); + assert_eq!(simd_saturating_sub(b, a), a); + assert_eq!(simd_saturating_sub(a, a), z); + assert_eq!(simd_saturating_sub(a, b), c); + assert_eq!(simd_saturating_sub(z, max), min1); + assert_eq!(simd_saturating_sub(min1, z), min1); + assert_eq!(simd_saturating_sub(min1, a), min); + assert_eq!(simd_saturating_sub(min1, b), min); } } } diff --git a/tests/ui/simd/intrinsic/generic-as.rs b/tests/ui/simd/intrinsic/generic-as.rs index da53211cbc74..f9ed416b6ff5 100644 --- a/tests/ui/simd/intrinsic/generic-as.rs +++ b/tests/ui/simd/intrinsic/generic-as.rs @@ -2,45 +2,47 @@ #![feature(repr_simd, core_intrinsics)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_as; -#[derive(Copy, Clone)] -#[repr(simd)] -struct V([T; 2]); +type V = Simd; fn main() { unsafe { - let u = V::([u32::MIN, u32::MAX]); + let u: V:: = Simd([u32::MIN, u32::MAX]); let i: V = simd_as(u); - assert_eq!(i.0[0], u.0[0] as i16); - assert_eq!(i.0[1], u.0[1] as i16); + assert_eq!(i[0], u[0] as i16); + assert_eq!(i[1], u[1] as i16); } unsafe { - let f = V::([f32::MIN, f32::MAX]); + let f: V:: = Simd([f32::MIN, f32::MAX]); let i: V = simd_as(f); - assert_eq!(i.0[0], f.0[0] as i16); - assert_eq!(i.0[1], f.0[1] as i16); + assert_eq!(i[0], f[0] as i16); + assert_eq!(i[1], f[1] as i16); } unsafe { - let f = V::([f32::MIN, f32::MAX]); + let f: V:: = Simd([f32::MIN, f32::MAX]); let u: V = simd_as(f); - assert_eq!(u.0[0], f.0[0] as u8); - assert_eq!(u.0[1], f.0[1] as u8); + assert_eq!(u[0], f[0] as u8); + assert_eq!(u[1], f[1] as u8); } unsafe { - let f = V::([f64::MIN, f64::MAX]); + let f: V:: = Simd([f64::MIN, f64::MAX]); let i: V = simd_as(f); - assert_eq!(i.0[0], f.0[0] as isize); - assert_eq!(i.0[1], f.0[1] as isize); + assert_eq!(i[0], f[0] as isize); + assert_eq!(i[1], f[1] as isize); } unsafe { - let f = V::([f64::MIN, f64::MAX]); + let f: V:: = Simd([f64::MIN, f64::MAX]); let u: V = simd_as(f); - assert_eq!(u.0[0], f.0[0] as usize); - assert_eq!(u.0[1], f.0[1] as usize); + assert_eq!(u[0], f[0] as usize); + assert_eq!(u[1], f[1] as usize); } } diff --git a/tests/ui/simd/intrinsic/generic-bswap-byte.rs b/tests/ui/simd/intrinsic/generic-bswap-byte.rs index 903a07656a70..d30a560b1c2e 100644 --- a/tests/ui/simd/intrinsic/generic-bswap-byte.rs +++ b/tests/ui/simd/intrinsic/generic-bswap-byte.rs @@ -2,19 +2,15 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_bswap; -#[repr(simd)] -#[derive(Copy, Clone)] -struct i8x4([i8; 4]); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct u8x4([u8; 4]); - fn main() { unsafe { - assert_eq!(simd_bswap(i8x4([0, 1, 2, 3])).0, [0, 1, 2, 3]); - assert_eq!(simd_bswap(u8x4([0, 1, 2, 3])).0, [0, 1, 2, 3]); + assert_eq!(simd_bswap(i8x4::from_array([0, 1, 2, 3])).into_array(), [0, 1, 2, 3]); + assert_eq!(simd_bswap(u8x4::from_array([0, 1, 2, 3])).into_array(), [0, 1, 2, 3]); } } diff --git a/tests/ui/simd/intrinsic/generic-cast-pass.rs b/tests/ui/simd/intrinsic/generic-cast-pass.rs index 7a4663bcad2b..0c3b00d65bf5 100644 --- a/tests/ui/simd/intrinsic/generic-cast-pass.rs +++ b/tests/ui/simd/intrinsic/generic-cast-pass.rs @@ -2,55 +2,57 @@ #![feature(repr_simd, core_intrinsics)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_cast; use std::cmp::{max, min}; -#[derive(Copy, Clone)] -#[repr(simd)] -struct V([T; 2]); +type V = Simd; fn main() { unsafe { - let u = V::([i16::MIN as u32, i16::MAX as u32]); + let u: V:: = Simd([i16::MIN as u32, i16::MAX as u32]); let i: V = simd_cast(u); - assert_eq!(i.0[0], u.0[0] as i16); - assert_eq!(i.0[1], u.0[1] as i16); + assert_eq!(i[0], u[0] as i16); + assert_eq!(i[1], u[1] as i16); } unsafe { - let f = V::([i16::MIN as f32, i16::MAX as f32]); + let f: V:: = Simd([i16::MIN as f32, i16::MAX as f32]); let i: V = simd_cast(f); - assert_eq!(i.0[0], f.0[0] as i16); - assert_eq!(i.0[1], f.0[1] as i16); + assert_eq!(i[0], f[0] as i16); + assert_eq!(i[1], f[1] as i16); } unsafe { - let f = V::([u8::MIN as f32, u8::MAX as f32]); + let f: V:: = Simd([u8::MIN as f32, u8::MAX as f32]); let u: V = simd_cast(f); - assert_eq!(u.0[0], f.0[0] as u8); - assert_eq!(u.0[1], f.0[1] as u8); + assert_eq!(u[0], f[0] as u8); + assert_eq!(u[1], f[1] as u8); } unsafe { // We would like to do isize::MIN..=isize::MAX, but those values are not representable in // an f64, so we clamp to the range of an i32 to prevent running into UB. - let f = V::([ + let f: V:: = Simd([ max(isize::MIN, i32::MIN as isize) as f64, min(isize::MAX, i32::MAX as isize) as f64, ]); let i: V = simd_cast(f); - assert_eq!(i.0[0], f.0[0] as isize); - assert_eq!(i.0[1], f.0[1] as isize); + assert_eq!(i[0], f[0] as isize); + assert_eq!(i[1], f[1] as isize); } unsafe { - let f = V::([ + let f: V:: = Simd([ max(usize::MIN, u32::MIN as usize) as f64, min(usize::MAX, u32::MAX as usize) as f64, ]); let u: V = simd_cast(f); - assert_eq!(u.0[0], f.0[0] as usize); - assert_eq!(u.0[1], f.0[1] as usize); + assert_eq!(u[0], f[0] as usize); + assert_eq!(u[1], f[1] as usize); } } diff --git a/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs b/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs index ea34e9ffeb8e..594d1d25d165 100644 --- a/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs +++ b/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs @@ -1,18 +1,24 @@ //@ run-pass #![feature(repr_simd, core_intrinsics)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_cast; -#[derive(Copy, Clone)] -#[repr(simd)] -struct V([T; 4]); +type V = Simd; fn main() { - let u = V::([0, 1, 2, 3]); + let u: V:: = Simd([0, 1, 2, 3]); let uu32: V = unsafe { simd_cast(u) }; let ui64: V = unsafe { simd_cast(u) }; - for (u, (uu32, ui64)) in u.0.iter().zip(uu32.0.iter().zip(ui64.0.iter())) { + for (u, (uu32, ui64)) in u + .as_array() + .iter() + .zip(uu32.as_array().iter().zip(ui64.as_array().iter())) + { assert_eq!(*u as u32, *uu32); assert_eq!(*u as i64, *ui64); } diff --git a/tests/ui/simd/intrinsic/generic-comparison-pass.rs b/tests/ui/simd/intrinsic/generic-comparison-pass.rs index 50a05eecb03b..3e803e8f6032 100644 --- a/tests/ui/simd/intrinsic/generic-comparison-pass.rs +++ b/tests/ui/simd/intrinsic/generic-comparison-pass.rs @@ -3,17 +3,11 @@ #![feature(repr_simd, core_intrinsics, macro_metavar_expr_concat)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::{simd_eq, simd_ge, simd_gt, simd_le, simd_lt, simd_ne}; +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone)] -struct i32x4([i32; 4]); -#[repr(simd)] -#[derive(Copy, Clone)] -struct u32x4(pub [u32; 4]); -#[repr(simd)] -#[derive(Copy, Clone)] -struct f32x4(pub [f32; 4]); +use std::intrinsics::simd::{simd_eq, simd_ge, simd_gt, simd_le, simd_lt, simd_ne}; macro_rules! cmp { ($method: ident($lhs: expr, $rhs: expr)) => {{ @@ -21,10 +15,11 @@ macro_rules! cmp { let rhs = $rhs; let e: u32x4 = ${concat(simd_, $method)}($lhs, $rhs); // assume the scalar version is correct/the behaviour we want. - assert!((e.0[0] != 0) == lhs.0[0].$method(&rhs.0[0])); - assert!((e.0[1] != 0) == lhs.0[1].$method(&rhs.0[1])); - assert!((e.0[2] != 0) == lhs.0[2].$method(&rhs.0[2])); - assert!((e.0[3] != 0) == lhs.0[3].$method(&rhs.0[3])); + let (lhs, rhs, e) = (lhs.as_array(), rhs.as_array(), e.as_array()); + assert!((e[0] != 0) == lhs[0].$method(&rhs[0])); + assert!((e[1] != 0) == lhs[1].$method(&rhs[1])); + assert!((e[2] != 0) == lhs[2].$method(&rhs[2])); + assert!((e[3] != 0) == lhs[3].$method(&rhs[3])); }}; } macro_rules! tests { @@ -53,17 +48,17 @@ macro_rules! tests { fn main() { // 13 vs. -100 tests that we get signed vs. unsigned comparisons // correct (i32: 13 > -100, u32: 13 < -100). let i1 = i32x4(10, -11, 12, 13); - let i1 = i32x4([10, -11, 12, 13]); - let i2 = i32x4([5, -5, 20, -100]); - let i3 = i32x4([10, -11, 20, -100]); + let i1 = i32x4::from_array([10, -11, 12, 13]); + let i2 = i32x4::from_array([5, -5, 20, -100]); + let i3 = i32x4::from_array([10, -11, 20, -100]); - let u1 = u32x4([10, !11 + 1, 12, 13]); - let u2 = u32x4([5, !5 + 1, 20, !100 + 1]); - let u3 = u32x4([10, !11 + 1, 20, !100 + 1]); + let u1 = u32x4::from_array([10, !11 + 1, 12, 13]); + let u2 = u32x4::from_array([5, !5 + 1, 20, !100 + 1]); + let u3 = u32x4::from_array([10, !11 + 1, 20, !100 + 1]); - let f1 = f32x4([10.0, -11.0, 12.0, 13.0]); - let f2 = f32x4([5.0, -5.0, 20.0, -100.0]); - let f3 = f32x4([10.0, -11.0, 20.0, -100.0]); + let f1 = f32x4::from_array([10.0, -11.0, 12.0, 13.0]); + let f2 = f32x4::from_array([5.0, -5.0, 20.0, -100.0]); + let f3 = f32x4::from_array([10.0, -11.0, 20.0, -100.0]); unsafe { tests! { @@ -84,7 +79,7 @@ fn main() { // NAN comparisons are special: // -11 (*) 13 // -5 -100 (*) - let f4 = f32x4([f32::NAN, f1.0[1], f32::NAN, f2.0[3]]); + let f4 = f32x4::from_array([f32::NAN, f1[1], f32::NAN, f2[3]]); unsafe { tests! { diff --git a/tests/ui/simd/intrinsic/generic-elements-pass.rs b/tests/ui/simd/intrinsic/generic-elements-pass.rs index e4d47cdb3818..f441d992e11b 100644 --- a/tests/ui/simd/intrinsic/generic-elements-pass.rs +++ b/tests/ui/simd/intrinsic/generic-elements-pass.rs @@ -2,23 +2,14 @@ #![feature(repr_simd, intrinsics, core_intrinsics)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{ simd_extract, simd_extract_dyn, simd_insert, simd_insert_dyn, simd_shuffle, }; -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] -struct i32x2([i32; 2]); -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] -struct i32x4([i32; 4]); -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] -struct i32x8([i32; 8]); - #[repr(simd)] struct SimdShuffleIdx([u32; LEN]); @@ -34,26 +25,26 @@ macro_rules! all_eq { } fn main() { - let x2 = i32x2([20, 21]); - let x4 = i32x4([40, 41, 42, 43]); - let x8 = i32x8([80, 81, 82, 83, 84, 85, 86, 87]); + let x2 = i32x2::from_array([20, 21]); + let x4 = i32x4::from_array([40, 41, 42, 43]); + let x8 = i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 87]); unsafe { - all_eq!(simd_insert(x2, 0, 100), i32x2([100, 21])); - all_eq!(simd_insert(x2, 1, 100), i32x2([20, 100])); + all_eq!(simd_insert(x2, 0, 100), i32x2::from_array([100, 21])); + all_eq!(simd_insert(x2, 1, 100), i32x2::from_array([20, 100])); - all_eq!(simd_insert(x4, 0, 100), i32x4([100, 41, 42, 43])); - all_eq!(simd_insert(x4, 1, 100), i32x4([40, 100, 42, 43])); - all_eq!(simd_insert(x4, 2, 100), i32x4([40, 41, 100, 43])); - all_eq!(simd_insert(x4, 3, 100), i32x4([40, 41, 42, 100])); + all_eq!(simd_insert(x4, 0, 100), i32x4::from_array([100, 41, 42, 43])); + all_eq!(simd_insert(x4, 1, 100), i32x4::from_array([40, 100, 42, 43])); + all_eq!(simd_insert(x4, 2, 100), i32x4::from_array([40, 41, 100, 43])); + all_eq!(simd_insert(x4, 3, 100), i32x4::from_array([40, 41, 42, 100])); - all_eq!(simd_insert(x8, 0, 100), i32x8([100, 81, 82, 83, 84, 85, 86, 87])); - all_eq!(simd_insert(x8, 1, 100), i32x8([80, 100, 82, 83, 84, 85, 86, 87])); - all_eq!(simd_insert(x8, 2, 100), i32x8([80, 81, 100, 83, 84, 85, 86, 87])); - all_eq!(simd_insert(x8, 3, 100), i32x8([80, 81, 82, 100, 84, 85, 86, 87])); - all_eq!(simd_insert(x8, 4, 100), i32x8([80, 81, 82, 83, 100, 85, 86, 87])); - all_eq!(simd_insert(x8, 5, 100), i32x8([80, 81, 82, 83, 84, 100, 86, 87])); - all_eq!(simd_insert(x8, 6, 100), i32x8([80, 81, 82, 83, 84, 85, 100, 87])); - all_eq!(simd_insert(x8, 7, 100), i32x8([80, 81, 82, 83, 84, 85, 86, 100])); + all_eq!(simd_insert(x8, 0, 100), i32x8::from_array([100, 81, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 1, 100), i32x8::from_array([80, 100, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 2, 100), i32x8::from_array([80, 81, 100, 83, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 3, 100), i32x8::from_array([80, 81, 82, 100, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 4, 100), i32x8::from_array([80, 81, 82, 83, 100, 85, 86, 87])); + all_eq!(simd_insert(x8, 5, 100), i32x8::from_array([80, 81, 82, 83, 84, 100, 86, 87])); + all_eq!(simd_insert(x8, 6, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 100, 87])); + all_eq!(simd_insert(x8, 7, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 100])); all_eq!(simd_extract(x2, 0), 20); all_eq!(simd_extract(x2, 1), 21); @@ -73,22 +64,22 @@ fn main() { all_eq!(simd_extract(x8, 7), 87); } unsafe { - all_eq!(simd_insert_dyn(x2, 0, 100), i32x2([100, 21])); - all_eq!(simd_insert_dyn(x2, 1, 100), i32x2([20, 100])); + all_eq!(simd_insert_dyn(x2, 0, 100), i32x2::from_array([100, 21])); + all_eq!(simd_insert_dyn(x2, 1, 100), i32x2::from_array([20, 100])); - all_eq!(simd_insert_dyn(x4, 0, 100), i32x4([100, 41, 42, 43])); - all_eq!(simd_insert_dyn(x4, 1, 100), i32x4([40, 100, 42, 43])); - all_eq!(simd_insert_dyn(x4, 2, 100), i32x4([40, 41, 100, 43])); - all_eq!(simd_insert_dyn(x4, 3, 100), i32x4([40, 41, 42, 100])); + all_eq!(simd_insert_dyn(x4, 0, 100), i32x4::from_array([100, 41, 42, 43])); + all_eq!(simd_insert_dyn(x4, 1, 100), i32x4::from_array([40, 100, 42, 43])); + all_eq!(simd_insert_dyn(x4, 2, 100), i32x4::from_array([40, 41, 100, 43])); + all_eq!(simd_insert_dyn(x4, 3, 100), i32x4::from_array([40, 41, 42, 100])); - all_eq!(simd_insert_dyn(x8, 0, 100), i32x8([100, 81, 82, 83, 84, 85, 86, 87])); - all_eq!(simd_insert_dyn(x8, 1, 100), i32x8([80, 100, 82, 83, 84, 85, 86, 87])); - all_eq!(simd_insert_dyn(x8, 2, 100), i32x8([80, 81, 100, 83, 84, 85, 86, 87])); - all_eq!(simd_insert_dyn(x8, 3, 100), i32x8([80, 81, 82, 100, 84, 85, 86, 87])); - all_eq!(simd_insert_dyn(x8, 4, 100), i32x8([80, 81, 82, 83, 100, 85, 86, 87])); - all_eq!(simd_insert_dyn(x8, 5, 100), i32x8([80, 81, 82, 83, 84, 100, 86, 87])); - all_eq!(simd_insert_dyn(x8, 6, 100), i32x8([80, 81, 82, 83, 84, 85, 100, 87])); - all_eq!(simd_insert_dyn(x8, 7, 100), i32x8([80, 81, 82, 83, 84, 85, 86, 100])); + all_eq!(simd_insert_dyn(x8, 0, 100), i32x8::from_array([100, 81, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 1, 100), i32x8::from_array([80, 100, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 2, 100), i32x8::from_array([80, 81, 100, 83, 84, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 3, 100), i32x8::from_array([80, 81, 82, 100, 84, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 4, 100), i32x8::from_array([80, 81, 82, 83, 100, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 5, 100), i32x8::from_array([80, 81, 82, 83, 84, 100, 86, 87])); + all_eq!(simd_insert_dyn(x8, 6, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 100, 87])); + all_eq!(simd_insert_dyn(x8, 7, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 100])); all_eq!(simd_extract_dyn(x2, 0), 20); all_eq!(simd_extract_dyn(x2, 1), 21); @@ -108,38 +99,47 @@ fn main() { all_eq!(simd_extract_dyn(x8, 7), 87); } - let y2 = i32x2([120, 121]); - let y4 = i32x4([140, 141, 142, 143]); - let y8 = i32x8([180, 181, 182, 183, 184, 185, 186, 187]); + let y2 = i32x2::from_array([120, 121]); + let y4 = i32x4::from_array([140, 141, 142, 143]); + let y8 = i32x8::from_array([180, 181, 182, 183, 184, 185, 186, 187]); unsafe { - all_eq!(simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0]) }), i32x2([121, 20])); + all_eq!( + simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0]) }), + i32x2::from_array([121, 20]) + ); all_eq!( simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0, 1, 2]) }), - i32x4([121, 20, 21, 120]) + i32x4::from_array([121, 20, 21, 120]) ); all_eq!( simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0, 1, 2, 1, 2, 3, 0]) }), - i32x8([121, 20, 21, 120, 21, 120, 121, 20]) + i32x8::from_array([121, 20, 21, 120, 21, 120, 121, 20]) ); - all_eq!(simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2]) }), i32x2([143, 42])); + all_eq!( + simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2]) }), + i32x2::from_array([143, 42]) + ); all_eq!( simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2, 5, 0]) }), - i32x4([143, 42, 141, 40]) + i32x4::from_array([143, 42, 141, 40]) ); all_eq!( simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2, 5, 0, 3, 6, 4, 1]) }), - i32x8([143, 42, 141, 40, 43, 142, 140, 41]) + i32x8::from_array([143, 42, 141, 40, 43, 142, 140, 41]) ); - all_eq!(simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5]) }), i32x2([183, 85])); + all_eq!( + simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5]) }), + i32x2::from_array([183, 85]) + ); all_eq!( simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5, 15, 0]) }), - i32x4([183, 85, 187, 80]) + i32x4::from_array([183, 85, 187, 80]) ); all_eq!( simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5, 15, 0, 3, 8, 12, 1]) }), - i32x8([183, 85, 187, 80, 83, 180, 184, 81]) + i32x8::from_array([183, 85, 187, 80, 83, 180, 184, 81]) ); } } diff --git a/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs b/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs index b98d4d6575bb..c2418c019eda 100644 --- a/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs +++ b/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs @@ -6,24 +6,26 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{simd_gather, simd_scatter}; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct x4(pub [T; 4]); +type x4 = Simd; fn main() { let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.]; - let default = x4([-3_f32, -3., -3., -3.]); - let s_strided = x4([0_f32, 2., -3., 6.]); - let mask = x4([-1_i32, -1, 0, -1]); + let default = x4::from_array([-3_f32, -3., -3., -3.]); + let s_strided = x4::from_array([0_f32, 2., -3., 6.]); + let mask = x4::from_array([-1_i32, -1, 0, -1]); // reading from *const unsafe { let pointer = x.as_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); let r_strided = simd_gather(default, pointers, mask); @@ -34,7 +36,7 @@ fn main() { unsafe { let pointer = x.as_mut_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); let r_strided = simd_gather(default, pointers, mask); @@ -45,9 +47,9 @@ fn main() { unsafe { let pointer = x.as_mut_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); - let values = x4([42_f32, 43_f32, 44_f32, 45_f32]); + let values = x4::from_array([42_f32, 43_f32, 44_f32, 45_f32]); simd_scatter(values, pointers, mask); assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]); @@ -65,14 +67,14 @@ fn main() { &x[7] as *const f32, ]; - let default = x4([y[0], y[0], y[0], y[0]]); - let s_strided = x4([y[0], y[2], y[0], y[6]]); + let default = x4::from_array([y[0], y[0], y[0], y[0]]); + let s_strided = x4::from_array([y[0], y[2], y[0], y[6]]); // reading from *const unsafe { let pointer = y.as_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); let r_strided = simd_gather(default, pointers, mask); @@ -83,7 +85,7 @@ fn main() { unsafe { let pointer = y.as_mut_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); let r_strided = simd_gather(default, pointers, mask); @@ -94,9 +96,9 @@ fn main() { unsafe { let pointer = y.as_mut_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); - let values = x4([y[7], y[6], y[5], y[1]]); + let values = x4::from_array([y[7], y[6], y[5], y[1]]); simd_scatter(values, pointers, mask); let s = [ diff --git a/tests/ui/simd/intrinsic/generic-select-pass.rs b/tests/ui/simd/intrinsic/generic-select-pass.rs index 0e5f7c4902f3..ff2d70d6a978 100644 --- a/tests/ui/simd/intrinsic/generic-select-pass.rs +++ b/tests/ui/simd/intrinsic/generic-select-pass.rs @@ -6,38 +6,24 @@ // Test that the simd_select intrinsics produces correct results. #![feature(repr_simd, core_intrinsics)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{simd_select, simd_select_bitmask}; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct i32x4(pub [i32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct u32x4(pub [u32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct u32x8([u32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct b8x4(pub [i8; 4]); +type b8x4 = i8x4; fn main() { - let m0 = b8x4([!0, !0, !0, !0]); - let m1 = b8x4([0, 0, 0, 0]); - let m2 = b8x4([!0, !0, 0, 0]); - let m3 = b8x4([0, 0, !0, !0]); - let m4 = b8x4([!0, 0, !0, 0]); + let m0 = b8x4::from_array([!0, !0, !0, !0]); + let m1 = b8x4::from_array([0, 0, 0, 0]); + let m2 = b8x4::from_array([!0, !0, 0, 0]); + let m3 = b8x4::from_array([0, 0, !0, !0]); + let m4 = b8x4::from_array([!0, 0, !0, 0]); unsafe { - let a = i32x4([1, -2, 3, 4]); - let b = i32x4([5, 6, -7, 8]); + let a = i32x4::from_array([1, -2, 3, 4]); + let b = i32x4::from_array([5, 6, -7, 8]); let r: i32x4 = simd_select(m0, a, b); let e = a; @@ -48,21 +34,21 @@ fn main() { assert_eq!(r, e); let r: i32x4 = simd_select(m2, a, b); - let e = i32x4([1, -2, -7, 8]); + let e = i32x4::from_array([1, -2, -7, 8]); assert_eq!(r, e); let r: i32x4 = simd_select(m3, a, b); - let e = i32x4([5, 6, 3, 4]); + let e = i32x4::from_array([5, 6, 3, 4]); assert_eq!(r, e); let r: i32x4 = simd_select(m4, a, b); - let e = i32x4([1, 6, 3, 8]); + let e = i32x4::from_array([1, 6, 3, 8]); assert_eq!(r, e); } unsafe { - let a = u32x4([1, 2, 3, 4]); - let b = u32x4([5, 6, 7, 8]); + let a = u32x4::from_array([1, 2, 3, 4]); + let b = u32x4::from_array([5, 6, 7, 8]); let r: u32x4 = simd_select(m0, a, b); let e = a; @@ -73,21 +59,21 @@ fn main() { assert_eq!(r, e); let r: u32x4 = simd_select(m2, a, b); - let e = u32x4([1, 2, 7, 8]); + let e = u32x4::from_array([1, 2, 7, 8]); assert_eq!(r, e); let r: u32x4 = simd_select(m3, a, b); - let e = u32x4([5, 6, 3, 4]); + let e = u32x4::from_array([5, 6, 3, 4]); assert_eq!(r, e); let r: u32x4 = simd_select(m4, a, b); - let e = u32x4([1, 6, 3, 8]); + let e = u32x4::from_array([1, 6, 3, 8]); assert_eq!(r, e); } unsafe { - let a = f32x4([1., 2., 3., 4.]); - let b = f32x4([5., 6., 7., 8.]); + let a = f32x4::from_array([1., 2., 3., 4.]); + let b = f32x4::from_array([5., 6., 7., 8.]); let r: f32x4 = simd_select(m0, a, b); let e = a; @@ -98,23 +84,23 @@ fn main() { assert_eq!(r, e); let r: f32x4 = simd_select(m2, a, b); - let e = f32x4([1., 2., 7., 8.]); + let e = f32x4::from_array([1., 2., 7., 8.]); assert_eq!(r, e); let r: f32x4 = simd_select(m3, a, b); - let e = f32x4([5., 6., 3., 4.]); + let e = f32x4::from_array([5., 6., 3., 4.]); assert_eq!(r, e); let r: f32x4 = simd_select(m4, a, b); - let e = f32x4([1., 6., 3., 8.]); + let e = f32x4::from_array([1., 6., 3., 8.]); assert_eq!(r, e); } unsafe { let t = !0 as i8; let f = 0 as i8; - let a = b8x4([t, f, t, f]); - let b = b8x4([f, f, f, t]); + let a = b8x4::from_array([t, f, t, f]); + let b = b8x4::from_array([f, f, f, t]); let r: b8x4 = simd_select(m0, a, b); let e = a; @@ -125,21 +111,21 @@ fn main() { assert_eq!(r, e); let r: b8x4 = simd_select(m2, a, b); - let e = b8x4([t, f, f, t]); + let e = b8x4::from_array([t, f, f, t]); assert_eq!(r, e); let r: b8x4 = simd_select(m3, a, b); - let e = b8x4([f, f, t, f]); + let e = b8x4::from_array([f, f, t, f]); assert_eq!(r, e); let r: b8x4 = simd_select(m4, a, b); - let e = b8x4([t, f, t, t]); + let e = b8x4::from_array([t, f, t, t]); assert_eq!(r, e); } unsafe { - let a = u32x8([0, 1, 2, 3, 4, 5, 6, 7]); - let b = u32x8([8, 9, 10, 11, 12, 13, 14, 15]); + let a = u32x8::from_array([0, 1, 2, 3, 4, 5, 6, 7]); + let b = u32x8::from_array([8, 9, 10, 11, 12, 13, 14, 15]); let r: u32x8 = simd_select_bitmask(0u8, a, b); let e = b; @@ -150,21 +136,21 @@ fn main() { assert_eq!(r, e); let r: u32x8 = simd_select_bitmask(0b01010101u8, a, b); - let e = u32x8([0, 9, 2, 11, 4, 13, 6, 15]); + let e = u32x8::from_array([0, 9, 2, 11, 4, 13, 6, 15]); assert_eq!(r, e); let r: u32x8 = simd_select_bitmask(0b10101010u8, a, b); - let e = u32x8([8, 1, 10, 3, 12, 5, 14, 7]); + let e = u32x8::from_array([8, 1, 10, 3, 12, 5, 14, 7]); assert_eq!(r, e); let r: u32x8 = simd_select_bitmask(0b11110000u8, a, b); - let e = u32x8([8, 9, 10, 11, 4, 5, 6, 7]); + let e = u32x8::from_array([8, 9, 10, 11, 4, 5, 6, 7]); assert_eq!(r, e); } unsafe { - let a = u32x4([0, 1, 2, 3]); - let b = u32x4([4, 5, 6, 7]); + let a = u32x4::from_array([0, 1, 2, 3]); + let b = u32x4::from_array([4, 5, 6, 7]); let r: u32x4 = simd_select_bitmask(0u8, a, b); let e = b; @@ -175,15 +161,15 @@ fn main() { assert_eq!(r, e); let r: u32x4 = simd_select_bitmask(0b0101u8, a, b); - let e = u32x4([0, 5, 2, 7]); + let e = u32x4::from_array([0, 5, 2, 7]); assert_eq!(r, e); let r: u32x4 = simd_select_bitmask(0b1010u8, a, b); - let e = u32x4([4, 1, 6, 3]); + let e = u32x4::from_array([4, 1, 6, 3]); assert_eq!(r, e); let r: u32x4 = simd_select_bitmask(0b1100u8, a, b); - let e = u32x4([4, 5, 2, 3]); + let e = u32x4::from_array([4, 5, 2, 3]); assert_eq!(r, e); } } diff --git a/tests/ui/simd/intrinsic/inlining-issue67557.rs b/tests/ui/simd/intrinsic/inlining-issue67557.rs index 13e7266b2a56..14f180425d8a 100644 --- a/tests/ui/simd/intrinsic/inlining-issue67557.rs +++ b/tests/ui/simd/intrinsic/inlining-issue67557.rs @@ -5,11 +5,13 @@ //@ compile-flags: -Zmir-opt-level=4 #![feature(core_intrinsics, repr_simd)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_shuffle; -#[repr(simd)] -#[derive(Debug, PartialEq)] -struct Simd2([u8; 2]); +type Simd2 = u8x2; #[repr(simd)] struct SimdShuffleIdx([u32; LEN]); @@ -17,7 +19,11 @@ struct SimdShuffleIdx([u32; LEN]); fn main() { unsafe { const IDX: SimdShuffleIdx<2> = SimdShuffleIdx([0, 1]); - let p_res: Simd2 = simd_shuffle(Simd2([10, 11]), Simd2([12, 13]), IDX); + let p_res: Simd2 = simd_shuffle( + Simd2::from_array([10, 11]), + Simd2::from_array([12, 13]), + IDX, + ); let a_res: Simd2 = inline_me(); assert_10_11(p_res); @@ -27,16 +33,16 @@ fn main() { #[inline(never)] fn assert_10_11(x: Simd2) { - assert_eq!(x, Simd2([10, 11])); + assert_eq!(x.into_array(), [10, 11]); } #[inline(never)] fn assert_10_13(x: Simd2) { - assert_eq!(x, Simd2([10, 13])); + assert_eq!(x.into_array(), [10, 13]); } #[inline(always)] unsafe fn inline_me() -> Simd2 { const IDX: SimdShuffleIdx<2> = SimdShuffleIdx([0, 3]); - simd_shuffle(Simd2([10, 11]), Simd2([12, 13]), IDX) + simd_shuffle(Simd2::from_array([10, 11]), Simd2::from_array([12, 13]), IDX) } diff --git a/tests/ui/simd/intrinsic/ptr-cast.rs b/tests/ui/simd/intrinsic/ptr-cast.rs index 3a73c0273e1a..63b65d83f767 100644 --- a/tests/ui/simd/intrinsic/ptr-cast.rs +++ b/tests/ui/simd/intrinsic/ptr-cast.rs @@ -2,18 +2,20 @@ #![feature(repr_simd, core_intrinsics)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{simd_cast_ptr, simd_expose_provenance, simd_with_exposed_provenance}; -#[derive(Copy, Clone)] -#[repr(simd)] -struct V([T; 2]); +type V = Simd; fn main() { unsafe { let mut foo = 4i8; let ptr = &mut foo as *mut i8; - let ptrs = V::<*mut i8>([ptr, core::ptr::null_mut()]); + let ptrs: V::<*mut i8> = Simd([ptr, core::ptr::null_mut()]); // change constness and type let const_ptrs: V<*const u8> = simd_cast_ptr(ptrs); @@ -22,8 +24,8 @@ fn main() { let with_exposed_provenance: V<*mut i8> = simd_with_exposed_provenance(exposed_addr); - assert!(const_ptrs.0 == [ptr as *const u8, core::ptr::null()]); - assert!(exposed_addr.0 == [ptr as usize, 0]); - assert!(with_exposed_provenance.0 == ptrs.0); + assert!(const_ptrs.into_array() == [ptr as *const u8, core::ptr::null()]); + assert!(exposed_addr.into_array() == [ptr as usize, 0]); + assert!(with_exposed_provenance.into_array() == ptrs.into_array()); } } diff --git a/tests/ui/simd/issue-39720.rs b/tests/ui/simd/issue-39720.rs index db441e551679..09d6142c9201 100644 --- a/tests/ui/simd/issue-39720.rs +++ b/tests/ui/simd/issue-39720.rs @@ -2,16 +2,16 @@ #![feature(repr_simd, core_intrinsics)] -#[repr(simd)] -#[derive(Copy, Clone, Debug)] -pub struct Char3(pub [i8; 3]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, Debug)] -pub struct Short3(pub [i16; 3]); +pub type Char3 = Simd; + +pub type Short3 = Simd; fn main() { - let cast: Short3 = unsafe { std::intrinsics::simd::simd_cast(Char3([10, -3, -9])) }; + let cast: Short3 = unsafe { std::intrinsics::simd::simd_cast(Char3::from_array([10, -3, -9])) }; println!("{:?}", cast); } diff --git a/tests/ui/simd/issue-85915-simd-ptrs.rs b/tests/ui/simd/issue-85915-simd-ptrs.rs index 4e2379d05251..a74c36fabc1b 100644 --- a/tests/ui/simd/issue-85915-simd-ptrs.rs +++ b/tests/ui/simd/issue-85915-simd-ptrs.rs @@ -6,35 +6,27 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{simd_gather, simd_scatter}; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct cptrx4([*const T; 4]); +type cptrx4 = Simd<*const T, 4>; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct mptrx4([*mut T; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4([f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct i32x4([i32; 4]); +type mptrx4 = Simd<*mut T, 4>; fn main() { let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.]; - let default = f32x4([-3_f32, -3., -3., -3.]); - let s_strided = f32x4([0_f32, 2., -3., 6.]); - let mask = i32x4([-1_i32, -1, 0, -1]); + let default = f32x4::from_array([-3_f32, -3., -3., -3.]); + let s_strided = f32x4::from_array([0_f32, 2., -3., 6.]); + let mask = i32x4::from_array([-1_i32, -1, 0, -1]); // reading from *const unsafe { let pointer = &x as *const f32; - let pointers = cptrx4([ + let pointers = cptrx4::from_array([ pointer.offset(0) as *const f32, pointer.offset(2), pointer.offset(4), @@ -49,14 +41,14 @@ fn main() { // writing to *mut unsafe { let pointer = &mut x as *mut f32; - let pointers = mptrx4([ + let pointers = mptrx4::from_array([ pointer.offset(0) as *mut f32, pointer.offset(2), pointer.offset(4), pointer.offset(6), ]); - let values = f32x4([42_f32, 43_f32, 44_f32, 45_f32]); + let values = f32x4::from_array([42_f32, 43_f32, 44_f32, 45_f32]); simd_scatter(values, pointers, mask); assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]); diff --git a/tests/ui/simd/issue-89193.rs b/tests/ui/simd/issue-89193.rs index a6c3017572a1..da4cd4565893 100644 --- a/tests/ui/simd/issue-89193.rs +++ b/tests/ui/simd/issue-89193.rs @@ -6,36 +6,38 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_gather; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct x4(pub [T; 4]); +type x4 = Simd; fn main() { let x: [usize; 4] = [10, 11, 12, 13]; - let default = x4([0_usize, 1, 2, 3]); + let default = x4::from_array([0_usize, 1, 2, 3]); let all_set = u8::MAX as i8; // aka -1 - let mask = x4([all_set, all_set, all_set, all_set]); - let expected = x4([10_usize, 11, 12, 13]); + let mask = x4::from_array([all_set, all_set, all_set, all_set]); + let expected = x4::from_array([10_usize, 11, 12, 13]); unsafe { let pointer = x.as_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(1), pointer.offset(2), pointer.offset(3)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i))); let result = simd_gather(default, pointers, mask); assert_eq!(result, expected); } // and again for isize let x: [isize; 4] = [10, 11, 12, 13]; - let default = x4([0_isize, 1, 2, 3]); - let expected = x4([10_isize, 11, 12, 13]); + let default = x4::from_array([0_isize, 1, 2, 3]); + let expected = x4::from_array([10_isize, 11, 12, 13]); unsafe { let pointer = x.as_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(1), pointer.offset(2), pointer.offset(3)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i))); let result = simd_gather(default, pointers, mask); assert_eq!(result, expected); } diff --git a/tests/ui/simd/masked-load-store.rs b/tests/ui/simd/masked-load-store.rs index 69ea76581ee6..da32ba611c48 100644 --- a/tests/ui/simd/masked-load-store.rs +++ b/tests/ui/simd/masked-load-store.rs @@ -1,11 +1,11 @@ //@ run-pass #![feature(repr_simd, core_intrinsics)] -use std::intrinsics::simd::{simd_masked_load, simd_masked_store}; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[derive(Copy, Clone)] -#[repr(simd)] -struct Simd([T; N]); +use std::intrinsics::simd::{simd_masked_load, simd_masked_store}; fn main() { unsafe { @@ -15,7 +15,7 @@ fn main() { let b: Simd = simd_masked_load(Simd::([-1, 0, -1, -1]), b_src.as_ptr(), b_default); - assert_eq!(&b.0, &[4, 9, 6, 7]); + assert_eq!(b.as_array(), &[4, 9, 6, 7]); let mut output = [u8::MAX; 5]; diff --git a/tests/ui/simd/monomorphize-shuffle-index.rs b/tests/ui/simd/monomorphize-shuffle-index.rs index a56f2ea14520..1490f8e2319f 100644 --- a/tests/ui/simd/monomorphize-shuffle-index.rs +++ b/tests/ui/simd/monomorphize-shuffle-index.rs @@ -11,6 +11,10 @@ )] #![allow(incomplete_features)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + #[cfg(old)] use std::intrinsics::simd::simd_shuffle; @@ -18,10 +22,6 @@ use std::intrinsics::simd::simd_shuffle; #[rustc_intrinsic] unsafe fn simd_shuffle_const_generic(a: T, b: T) -> U; -#[derive(Copy, Clone)] -#[repr(simd)] -struct Simd([T; N]); - trait Shuffle { const I: Simd; const J: &'static [u32] = &Self::I.0; @@ -57,9 +57,9 @@ fn main() { let b = Simd::([4, 5, 6, 7]); unsafe { let x: Simd = I1.shuffle(a, b); - assert_eq!(x.0, [0, 2, 4, 6]); + assert_eq!(x.into_array(), [0, 2, 4, 6]); let y: Simd = I2.shuffle(a, b); - assert_eq!(y.0, [1, 5]); + assert_eq!(y.into_array(), [1, 5]); } } diff --git a/tests/ui/simd/repr_packed.rs b/tests/ui/simd/repr_packed.rs index cc54477ae713..f0c6de7c402f 100644 --- a/tests/ui/simd/repr_packed.rs +++ b/tests/ui/simd/repr_packed.rs @@ -3,15 +3,16 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_add; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd, packed)] -struct Simd([T; N]); +use std::intrinsics::simd::simd_add; fn check_size_align() { use std::mem; - assert_eq!(mem::size_of::>(), mem::size_of::<[T; N]>()); - assert_eq!(mem::size_of::>() % mem::align_of::>(), 0); + assert_eq!(mem::size_of::>(), mem::size_of::<[T; N]>()); + assert_eq!(mem::size_of::>() % mem::align_of::>(), 0); } fn check_ty() { @@ -35,14 +36,21 @@ fn main() { unsafe { // powers-of-two have no padding and have the same layout as #[repr(simd)] - let x: Simd = - simd_add(Simd::([0., 1., 2., 3.]), Simd::([2., 2., 2., 2.])); - assert_eq!(std::mem::transmute::<_, [f64; 4]>(x), [2., 3., 4., 5.]); + let x: PackedSimd = + simd_add( + PackedSimd::([0., 1., 2., 3.]), + PackedSimd::([2., 2., 2., 2.]), + ); + assert_eq!(x.into_array(), [2., 3., 4., 5.]); // non-powers-of-two should have padding (which is removed by #[repr(packed)]), // but the intrinsic handles it - let x: Simd = simd_add(Simd::([0., 1., 2.]), Simd::([2., 2., 2.])); - let arr: [f64; 3] = x.0; + let x: PackedSimd = + simd_add( + PackedSimd::([0., 1., 2.]), + PackedSimd::([2., 2., 2.]), + ); + let arr: [f64; 3] = x.into_array(); assert_eq!(arr, [2., 3., 4.]); } } diff --git a/tests/ui/simd/shuffle.rs b/tests/ui/simd/shuffle.rs index cd270edcf00c..061571a47867 100644 --- a/tests/ui/simd/shuffle.rs +++ b/tests/ui/simd/shuffle.rs @@ -10,10 +10,16 @@ use std::marker::ConstParamTy; use std::intrinsics::simd::simd_shuffle; +// not using `minisimd` because of the `ConstParamTy` #[derive(Copy, Clone, ConstParamTy, PartialEq, Eq)] #[repr(simd)] struct Simd([T; N]); +fn into_array(v: Simd) -> [T; N] { + const { assert!(size_of::>() == size_of::<[T; N]>()) } + unsafe { std::intrinsics::transmute_unchecked(v) } +} + unsafe fn __shuffle_vector16, T, U>(x: T, y: T) -> U { simd_shuffle(x, y, IDX) } @@ -25,10 +31,10 @@ fn main() { let b = Simd::([4, 5, 6, 7]); unsafe { let x: Simd = simd_shuffle(a, b, I1); - assert_eq!(x.0, [0, 2, 4, 6]); + assert_eq!(into_array(x), [0, 2, 4, 6]); let y: Simd = simd_shuffle(a, b, I2); - assert_eq!(y.0, [1, 5]); + assert_eq!(into_array(y), [1, 5]); } // Test that an indirection (via an unnamed constant) diff --git a/tests/ui/simd/simd-bitmask-notpow2.rs b/tests/ui/simd/simd-bitmask-notpow2.rs index 4935097065ea..b9af591d1b94 100644 --- a/tests/ui/simd/simd-bitmask-notpow2.rs +++ b/tests/ui/simd/simd-bitmask-notpow2.rs @@ -4,21 +4,23 @@ //@ ignore-endian-big #![feature(repr_simd, core_intrinsics)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{simd_bitmask, simd_select_bitmask}; fn main() { // Non-power-of-2 multi-byte mask. - #[repr(simd, packed)] #[allow(non_camel_case_types)] - #[derive(Copy, Clone, Debug, PartialEq)] - struct i32x10([i32; 10]); + type i32x10 = PackedSimd; impl i32x10 { fn splat(x: i32) -> Self { Self([x; 10]) } } unsafe { - let mask = i32x10([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]); + let mask = i32x10::from_array([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]); let mask_bits = if cfg!(target_endian = "little") { 0b0101001011 } else { 0b1101001010 }; let mask_bytes = if cfg!(target_endian = "little") { [0b01001011, 0b01] } else { [0b11, 0b01001010] }; @@ -43,17 +45,20 @@ fn main() { } // Test for a mask where the next multiple of 8 is not a power of two. - #[repr(simd, packed)] #[allow(non_camel_case_types)] - #[derive(Copy, Clone, Debug, PartialEq)] - struct i32x20([i32; 20]); + type i32x20 = PackedSimd; impl i32x20 { fn splat(x: i32) -> Self { Self([x; 20]) } } unsafe { - let mask = i32x20([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0, 0, 0, 0, !0, !0, !0, !0, !0, !0, !0]); + let mask = i32x20::from_array([ + !0, !0, 0, !0, 0, + 0, !0, 0, !0, 0, + 0, 0, 0, !0, !0, + !0, !0, !0, !0, !0, + ]); let mask_bits = if cfg!(target_endian = "little") { 0b11111110000101001011 } else { diff --git a/tests/ui/simd/simd-bitmask.rs b/tests/ui/simd/simd-bitmask.rs index 6fcceeaa24bb..609dae3647b2 100644 --- a/tests/ui/simd/simd-bitmask.rs +++ b/tests/ui/simd/simd-bitmask.rs @@ -1,11 +1,11 @@ //@run-pass #![feature(repr_simd, core_intrinsics)] -use std::intrinsics::simd::{simd_bitmask, simd_select_bitmask}; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[derive(Copy, Clone)] -#[repr(simd)] -struct Simd([T; N]); +use std::intrinsics::simd::{simd_bitmask, simd_select_bitmask}; fn main() { unsafe { @@ -41,11 +41,11 @@ fn main() { let mask = if cfg!(target_endian = "little") { 0b0101u8 } else { 0b1010u8 }; let r = simd_select_bitmask(mask, a, b); - assert_eq!(r.0, e); + assert_eq!(r.into_array(), e); let mask = if cfg!(target_endian = "little") { [0b0101u8] } else { [0b1010u8] }; let r = simd_select_bitmask(mask, a, b); - assert_eq!(r.0, e); + assert_eq!(r.into_array(), e); let a = Simd::([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); let b = Simd::([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]); @@ -57,7 +57,7 @@ fn main() { 0b0011000000001010u16 }; let r = simd_select_bitmask(mask, a, b); - assert_eq!(r.0, e); + assert_eq!(r.into_array(), e); let mask = if cfg!(target_endian = "little") { [0b00001100u8, 0b01010000u8] @@ -65,6 +65,6 @@ fn main() { [0b00110000u8, 0b00001010u8] }; let r = simd_select_bitmask(mask, a, b); - assert_eq!(r.0, e); + assert_eq!(r.into_array(), e); } } diff --git a/tests/ui/simd/target-feature-mixup.rs b/tests/ui/simd/target-feature-mixup.rs index 77f186152487..82902891b97f 100644 --- a/tests/ui/simd/target-feature-mixup.rs +++ b/tests/ui/simd/target-feature-mixup.rs @@ -8,6 +8,11 @@ #![feature(repr_simd, target_feature, cfg_target_feature)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +#[allow(unused)] +use minisimd::*; + use std::process::{Command, ExitStatus}; use std::env; @@ -50,19 +55,13 @@ fn is_sigill(status: ExitStatus) -> bool { #[allow(nonstandard_style)] mod test { // An SSE type - #[repr(simd)] - #[derive(PartialEq, Debug, Clone, Copy)] - struct __m128i([u64; 2]); + type __m128i = super::u64x2; // An AVX type - #[repr(simd)] - #[derive(PartialEq, Debug, Clone, Copy)] - struct __m256i([u64; 4]); + type __m256i = super::u64x4; // An AVX-512 type - #[repr(simd)] - #[derive(PartialEq, Debug, Clone, Copy)] - struct __m512i([u64; 8]); + type __m512i = super::u64x8; pub fn main(level: &str) { unsafe { @@ -88,9 +87,9 @@ mod test { )*) => ($( $(#[$attr])* unsafe fn $main(level: &str) { - let m128 = __m128i([1, 2]); - let m256 = __m256i([3, 4, 5, 6]); - let m512 = __m512i([7, 8, 9, 10, 11, 12, 13, 14]); + let m128 = __m128i::from_array([1, 2]); + let m256 = __m256i::from_array([3, 4, 5, 6]); + let m512 = __m512i::from_array([7, 8, 9, 10, 11, 12, 13, 14]); assert_eq!(id_sse_128(m128), m128); assert_eq!(id_sse_256(m256), m256); assert_eq!(id_sse_512(m512), m512); @@ -125,55 +124,55 @@ mod test { #[target_feature(enable = "sse2")] unsafe fn id_sse_128(a: __m128i) -> __m128i { - assert_eq!(a, __m128i([1, 2])); + assert_eq!(a, __m128i::from_array([1, 2])); a.clone() } #[target_feature(enable = "sse2")] unsafe fn id_sse_256(a: __m256i) -> __m256i { - assert_eq!(a, __m256i([3, 4, 5, 6])); + assert_eq!(a, __m256i::from_array([3, 4, 5, 6])); a.clone() } #[target_feature(enable = "sse2")] unsafe fn id_sse_512(a: __m512i) -> __m512i { - assert_eq!(a, __m512i([7, 8, 9, 10, 11, 12, 13, 14])); + assert_eq!(a, __m512i::from_array([7, 8, 9, 10, 11, 12, 13, 14])); a.clone() } #[target_feature(enable = "avx")] unsafe fn id_avx_128(a: __m128i) -> __m128i { - assert_eq!(a, __m128i([1, 2])); + assert_eq!(a, __m128i::from_array([1, 2])); a.clone() } #[target_feature(enable = "avx")] unsafe fn id_avx_256(a: __m256i) -> __m256i { - assert_eq!(a, __m256i([3, 4, 5, 6])); + assert_eq!(a, __m256i::from_array([3, 4, 5, 6])); a.clone() } #[target_feature(enable = "avx")] unsafe fn id_avx_512(a: __m512i) -> __m512i { - assert_eq!(a, __m512i([7, 8, 9, 10, 11, 12, 13, 14])); + assert_eq!(a, __m512i::from_array([7, 8, 9, 10, 11, 12, 13, 14])); a.clone() } #[target_feature(enable = "avx512bw")] unsafe fn id_avx512_128(a: __m128i) -> __m128i { - assert_eq!(a, __m128i([1, 2])); + assert_eq!(a, __m128i::from_array([1, 2])); a.clone() } #[target_feature(enable = "avx512bw")] unsafe fn id_avx512_256(a: __m256i) -> __m256i { - assert_eq!(a, __m256i([3, 4, 5, 6])); + assert_eq!(a, __m256i::from_array([3, 4, 5, 6])); a.clone() } #[target_feature(enable = "avx512bw")] unsafe fn id_avx512_512(a: __m512i) -> __m512i { - assert_eq!(a, __m512i([7, 8, 9, 10, 11, 12, 13, 14])); + assert_eq!(a, __m512i::from_array([7, 8, 9, 10, 11, 12, 13, 14])); a.clone() } } From 25a804ab062582bba55bf5cd9844bd13aae00f21 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 18 Jul 2025 17:29:33 -0700 Subject: [PATCH 354/363] ...and wasm tests too --- tests/ui/wasm/simd-to-array-80108.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/ui/wasm/simd-to-array-80108.rs b/tests/ui/wasm/simd-to-array-80108.rs index c7f8585eaa4e..f6b368992bef 100644 --- a/tests/ui/wasm/simd-to-array-80108.rs +++ b/tests/ui/wasm/simd-to-array-80108.rs @@ -10,6 +10,8 @@ pub struct Vector([i32; 4]); impl Vector { pub const fn to_array(self) -> [i32; 4] { - self.0 + // This used to just be `.0`, but that was banned in + // + unsafe { std::mem::transmute(self) } } } From 493fd9a54110dc9d0d60566140e65f701070e34c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 12 Jul 2025 17:11:47 -0700 Subject: [PATCH 355/363] Update cranelift tests --- .../example/float-minmax-pass.rs | 22 ++++++++++++------- .../example/mini_core_hello_world.rs | 3 ++- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs index ad46e18c11c0..b7491b7e522f 100644 --- a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs +++ b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs @@ -11,6 +11,12 @@ #[derive(Copy, Clone, PartialEq, Debug)] struct f32x4(pub [f32; 4]); +impl f32x4 { + fn into_array(self) -> [f32; 4] { + unsafe { std::mem::transmute(self) } + } +} + use std::intrinsics::simd::*; fn main() { @@ -29,22 +35,22 @@ fn main() { unsafe { let min0 = simd_fmin(x, y); let min1 = simd_fmin(y, x); - assert_eq!(min0, min1); + assert_eq!(min0.into_array(), min1.into_array()); let e = f32x4([1.0, 1.0, 3.0, 3.0]); - assert_eq!(min0, e); + assert_eq!(min0.into_array(), e.into_array()); let minn = simd_fmin(x, n); - assert_eq!(minn, x); + assert_eq!(minn.into_array(), x.into_array()); let minn = simd_fmin(y, n); - assert_eq!(minn, y); + assert_eq!(minn.into_array(), y.into_array()); let max0 = simd_fmax(x, y); let max1 = simd_fmax(y, x); - assert_eq!(max0, max1); + assert_eq!(max0.into_array(), max1.into_array()); let e = f32x4([2.0, 2.0, 4.0, 4.0]); - assert_eq!(max0, e); + assert_eq!(max0.into_array(), e.into_array()); let maxn = simd_fmax(x, n); - assert_eq!(maxn, x); + assert_eq!(maxn.into_array(), x.into_array()); let maxn = simd_fmax(y, n); - assert_eq!(maxn, y); + assert_eq!(maxn.into_array(), y.into_array()); } } diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 246bd3104ec4..86602c6b2a3f 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -348,7 +348,8 @@ fn main() { struct V([f64; 2]); let f = V([0.0, 1.0]); - let _a = f.0[0]; + let fp = (&raw const f) as *const [f64; 2]; + let _a = (unsafe { &*fp })[0]; stack_val_align(); } From f790042c6ab3cf05622e63928b13cb802d68fadf Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 13 Jul 2025 11:26:40 -0700 Subject: [PATCH 356/363] Update Miri Tests --- .../tests/pass/intrinsics/portable-simd.rs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs index 726d4c01cc3f..e2cd08733af1 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs @@ -349,12 +349,15 @@ fn simd_mask() { // Non-power-of-2 multi-byte mask. #[repr(simd, packed)] #[allow(non_camel_case_types)] - #[derive(Copy, Clone, Debug, PartialEq)] + #[derive(Copy, Clone)] struct i32x10([i32; 10]); impl i32x10 { fn splat(x: i32) -> Self { Self([x; 10]) } + fn into_array(self) -> [i32; 10] { + unsafe { std::mem::transmute(self) } + } } unsafe { let mask = i32x10([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]); @@ -377,19 +380,22 @@ fn simd_mask() { i32x10::splat(!0), // yes i32x10::splat(0), // no ); - assert_eq!(selected1, mask); - assert_eq!(selected2, mask); + assert_eq!(selected1.into_array(), mask.into_array()); + assert_eq!(selected2.into_array(), mask.into_array()); } // Test for a mask where the next multiple of 8 is not a power of two. #[repr(simd, packed)] #[allow(non_camel_case_types)] - #[derive(Copy, Clone, Debug, PartialEq)] + #[derive(Copy, Clone)] struct i32x20([i32; 20]); impl i32x20 { fn splat(x: i32) -> Self { Self([x; 20]) } + fn into_array(self) -> [i32; 20] { + unsafe { std::mem::transmute(self) } + } } unsafe { let mask = i32x20([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0, 0, 0, 0, !0, !0, !0, !0, !0, !0, !0]); @@ -419,8 +425,8 @@ fn simd_mask() { i32x20::splat(!0), // yes i32x20::splat(0), // no ); - assert_eq!(selected1, mask); - assert_eq!(selected2, mask); + assert_eq!(selected1.into_array(), mask.into_array()); + assert_eq!(selected2.into_array(), mask.into_array()); } } @@ -708,12 +714,12 @@ fn simd_ops_non_pow2() { let x = SimdPacked([1u32; 3]); let y = SimdPacked([2u32; 3]); let z = unsafe { intrinsics::simd_add(x, y) }; - assert_eq!({ z.0 }, [3u32; 3]); + assert_eq!(unsafe { *(&raw const z).cast::<[u32; 3]>() }, [3u32; 3]); let x = SimdPadded([1u32; 3]); let y = SimdPadded([2u32; 3]); let z = unsafe { intrinsics::simd_add(x, y) }; - assert_eq!(z.0, [3u32; 3]); + assert_eq!(unsafe { *(&raw const z).cast::<[u32; 3]>() }, [3u32; 3]); } fn main() { From 41ce1ed252f194756fb2f3e3e92bbdfb3940088d Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 6 Mar 2025 19:13:46 -0800 Subject: [PATCH 357/363] Ban projecting into SIMD types [MCP838] --- compiler/rustc_codegen_ssa/src/mir/operand.rs | 19 +++--------- compiler/rustc_mir_transform/src/validate.rs | 9 ++++++ .../simd/project-to-simd-array-field.rs | 31 ------------------- tests/ui/mir/validate/project-into-simd.rs | 18 +++++++++++ tests/ui/simd/issue-105439.rs | 4 ++- 5 files changed, 35 insertions(+), 46 deletions(-) delete mode 100644 tests/codegen/simd/project-to-simd-array-field.rs create mode 100644 tests/ui/mir/validate/project-into-simd.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 6a3fdb6ede18..06bedaaa4a27 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -329,20 +329,11 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let offset = self.layout.fields.offset(i); if !bx.is_backend_ref(self.layout) && bx.is_backend_ref(field) { - if let BackendRepr::SimdVector { count, .. } = self.layout.backend_repr - && let BackendRepr::Memory { sized: true } = field.backend_repr - && count.is_power_of_two() - { - assert_eq!(field.size, self.layout.size); - // This is being deprecated, but for now stdarch still needs it for - // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]); - let place = PlaceRef::alloca(bx, field); - self.val.store(bx, place.val.with_type(self.layout)); - return bx.load_operand(place); - } else { - // Part of https://github.com/rust-lang/compiler-team/issues/838 - bug!("Non-ref type {self:?} cannot project to ref field type {field:?}"); - } + // Part of https://github.com/rust-lang/compiler-team/issues/838 + span_bug!( + fx.mir.span, + "Non-ref type {self:?} cannot project to ref field type {field:?}", + ); } let val = if field.is_zst() { diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 659ca4df159d..5860072d541f 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -721,6 +721,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } + if adt_def.repr().simd() { + self.fail( + location, + format!( + "Projecting into SIMD type {adt_def:?} is banned by MCP#838" + ), + ); + } + let var = parent_ty.variant_index.unwrap_or(FIRST_VARIANT); let Some(field) = adt_def.variant(var).fields.get(f) else { fail_out_of_bounds(self, location); diff --git a/tests/codegen/simd/project-to-simd-array-field.rs b/tests/codegen/simd/project-to-simd-array-field.rs deleted file mode 100644 index 29fab6406336..000000000000 --- a/tests/codegen/simd/project-to-simd-array-field.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@compile-flags: -Copt-level=3 - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] - -#[allow(non_camel_case_types)] -#[derive(Clone, Copy)] -#[repr(simd)] -struct i32x4([i32; 4]); - -#[inline(always)] -fn to_array4(a: i32x4) -> [i32; 4] { - a.0 -} - -// CHECK-LABEL: simd_add_self_then_return_array( -// CHECK-SAME: ptr{{.+}}sret{{.+}}%[[RET:.+]], -// CHECK-SAME: ptr{{.+}}%a) -#[no_mangle] -pub fn simd_add_self_then_return_array(a: &i32x4) -> [i32; 4] { - // It would be nice to just ban `.0` into simd types, - // but until we do this has to keep working. - // See also - - // CHECK: %[[T1:.+]] = load <4 x i32>, ptr %a - // CHECK: %[[T2:.+]] = shl <4 x i32> %[[T1]], {{splat \(i32 1\)|}} - // CHECK: store <4 x i32> %[[T2]], ptr %[[RET]] - let a = *a; - let b = unsafe { core::intrinsics::simd::simd_add(a, a) }; - to_array4(b) -} diff --git a/tests/ui/mir/validate/project-into-simd.rs b/tests/ui/mir/validate/project-into-simd.rs new file mode 100644 index 000000000000..67766c8c4b01 --- /dev/null +++ b/tests/ui/mir/validate/project-into-simd.rs @@ -0,0 +1,18 @@ +// Optimized MIR shouldn't have critical call edges +// +//@ build-fail +//@ edition: 2021 +//@ compile-flags: --crate-type=lib +//@ failure-status: 101 +//@ dont-check-compiler-stderr + +#![feature(repr_simd)] + +#[repr(simd)] +pub struct U32x4([u32; 4]); + +pub fn f(a: U32x4) -> [u32; 4] { + a.0 + //~^ ERROR broken MIR in Item + //~| ERROR Projecting into SIMD type U32x4 is banned by MCP#838 +} diff --git a/tests/ui/simd/issue-105439.rs b/tests/ui/simd/issue-105439.rs index 0a44f36fb2ec..1d57eff341c0 100644 --- a/tests/ui/simd/issue-105439.rs +++ b/tests/ui/simd/issue-105439.rs @@ -10,7 +10,9 @@ struct i32x4([i32; 4]); #[inline(always)] fn to_array(a: i32x4) -> [i32; 4] { - a.0 + // This was originally just `a.0`, but that ended up being annoying enough + // that it was banned by + unsafe { std::mem::transmute(a) } } fn main() { From 1e96d7a55304f8573b6dfeb5ccbdabdb407b89b9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 20 Jul 2025 17:44:55 +0000 Subject: [PATCH 358/363] Consider param-env for fast path --- .../src/solve/delegate.rs | 22 +++++--------- .../src/traits/fulfill.rs | 2 +- .../traits/query/type_op/prove_predicate.rs | 2 +- .../src/traits/select/mod.rs | 2 +- .../rustc_trait_selection/src/traits/util.rs | 20 ++++++++++++- .../rustc_traits/src/evaluate_obligation.rs | 2 +- ...sue-143992.current_sized_hierarchy.stderr} | 4 +-- ...e-issue-143992.next_sized_hierarchy.stderr | 17 +++++++++++ .../incomplete-inference-issue-143992.rs | 10 +++++-- .../normalizes-to-is-not-productive.stderr | 7 ----- .../normalize/normalize-param-env-2.stderr | 19 +----------- .../normalize-param-env-4.next.stderr | 16 +--------- tests/ui/where-clauses/ignore-err-clauses.rs | 2 +- .../where-clauses/ignore-err-clauses.stderr | 29 +++++++++++++++---- 14 files changed, 82 insertions(+), 72 deletions(-) rename tests/ui/sized-hierarchy/{incomplete-inference-issue-143992.next.stderr => incomplete-inference-issue-143992.current_sized_hierarchy.stderr} (80%) create mode 100644 tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next_sized_hierarchy.stderr diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 17429e15cce0..7426504e1393 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -12,11 +12,11 @@ use rustc_infer::traits::solve::Goal; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::Certainty; use rustc_middle::ty::{ - self, SizedTraitKind, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode, + self, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode, }; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; -use crate::traits::{EvaluateConstErr, ObligationCause, specialization_graph}; +use crate::traits::{EvaluateConstErr, ObligationCause, sizedness_fast_path, specialization_graph}; #[repr(transparent)] pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>); @@ -76,19 +76,11 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< if trait_pred.polarity() == ty::PredicatePolarity::Positive { match self.0.tcx.as_lang_item(trait_pred.def_id()) { - Some(LangItem::Sized) - if self - .resolve_vars_if_possible(trait_pred.self_ty().skip_binder()) - .has_trivial_sizedness(self.0.tcx, SizedTraitKind::Sized) => - { - return Some(Certainty::Yes); - } - Some(LangItem::MetaSized) - if self - .resolve_vars_if_possible(trait_pred.self_ty().skip_binder()) - .has_trivial_sizedness(self.0.tcx, SizedTraitKind::MetaSized) => - { - return Some(Certainty::Yes); + Some(LangItem::Sized) | Some(LangItem::MetaSized) => { + let predicate = self.resolve_vars_if_possible(goal.predicate); + if sizedness_fast_path(self.tcx, predicate, goal.param_env) { + return Some(Certainty::Yes); + } } Some(LangItem::Copy | LangItem::Clone) => { let self_ty = diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e35f89358e9f..6b884b360804 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -363,7 +363,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let infcx = self.selcx.infcx; - if sizedness_fast_path(infcx.tcx, obligation.predicate) { + if sizedness_fast_path(infcx.tcx, obligation.predicate, obligation.param_env) { return ProcessResult::Changed(thin_vec![]); } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index 22eeb285b376..f24214145baf 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -15,7 +15,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>, ) -> Option { - if sizedness_fast_path(tcx, key.value.predicate) { + if sizedness_fast_path(tcx, key.value.predicate, key.param_env) { return Some(()); } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2b563c5b8d5f..f90316f520b3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -597,7 +597,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)?, } - if sizedness_fast_path(self.tcx(), obligation.predicate) { + if sizedness_fast_path(self.tcx(), obligation.predicate, obligation.param_env) { return Ok(EvaluatedToOk); } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 0c14b124e25c..c3d60ec45c46 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -365,7 +365,11 @@ impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { } } -pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>) -> bool { +pub fn sizedness_fast_path<'tcx>( + tcx: TyCtxt<'tcx>, + predicate: ty::Predicate<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> bool { // Proving `Sized`/`MetaSized`, very often on "obviously sized" types like // `&T`, accounts for about 60% percentage of the predicates we have to prove. No need to // canonicalize and all that for such cases. @@ -390,6 +394,20 @@ pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc debug!("fast path -- trivial sizedness"); return true; } + + if matches!(trait_pred.self_ty().kind(), ty::Param(_) | ty::Placeholder(_)) { + for clause in param_env.caller_bounds() { + if let ty::ClauseKind::Trait(clause_pred) = clause.kind().skip_binder() + && clause_pred.polarity == ty::PredicatePolarity::Positive + && clause_pred.self_ty() == trait_pred.self_ty() + && (clause_pred.def_id() == trait_pred.def_id() + || (sizedness == SizedTraitKind::MetaSized + && tcx.is_lang_item(clause_pred.def_id(), LangItem::Sized))) + { + return true; + } + } + } } false diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index 7771db855d70..819b8e3231ce 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -24,7 +24,7 @@ fn evaluate_obligation<'tcx>( debug!("evaluate_obligation: goal={:#?}", goal); let ParamEnvAnd { param_env, value: predicate } = goal; - if sizedness_fast_path(tcx, predicate) { + if sizedness_fast_path(tcx, predicate, param_env) { return Ok(EvaluationResult::EvaluatedToOk); } diff --git a/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next.stderr b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.current_sized_hierarchy.stderr similarity index 80% rename from tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next.stderr rename to tests/ui/sized-hierarchy/incomplete-inference-issue-143992.current_sized_hierarchy.stderr index cf56f42afc8a..b904b784df73 100644 --- a/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next.stderr +++ b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.current_sized_hierarchy.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/incomplete-inference-issue-143992.rs:27:28 + --> $DIR/incomplete-inference-issue-143992.rs:30:28 | LL | let _x = T::Assoc::new(()); | ------------- ^^ expected `[u32; 1]`, found `()` @@ -7,7 +7,7 @@ LL | let _x = T::Assoc::new(()); | arguments to this function are incorrect | note: associated function defined here - --> $DIR/incomplete-inference-issue-143992.rs:18:8 + --> $DIR/incomplete-inference-issue-143992.rs:21:8 | LL | fn new(r: R) -> R { | ^^^ ---- diff --git a/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next_sized_hierarchy.stderr b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next_sized_hierarchy.stderr new file mode 100644 index 000000000000..b904b784df73 --- /dev/null +++ b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next_sized_hierarchy.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/incomplete-inference-issue-143992.rs:30:28 + | +LL | let _x = T::Assoc::new(()); + | ------------- ^^ expected `[u32; 1]`, found `()` + | | + | arguments to this function are incorrect + | +note: associated function defined here + --> $DIR/incomplete-inference-issue-143992.rs:21:8 + | +LL | fn new(r: R) -> R { + | ^^^ ---- + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs index 3e3e1dc50e58..b9e65ed28393 100644 --- a/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs +++ b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs @@ -1,9 +1,12 @@ //@ compile-flags: --crate-type=lib -//@ revisions: current next +//@ revisions: current next current_sized_hierarchy next_sized_hierarchy //@ ignore-compare-mode-next-solver (explicit revisions) //@[current] check-pass +//@[next] check-pass //@[next] compile-flags: -Znext-solver -//@[next] check-fail +//@[next_sized_hierarchy] compile-flags: -Znext-solver + +#![cfg_attr(any(current_sized_hierarchy, next_sized_hierarchy), feature(sized_hierarchy))] // Test that we avoid incomplete inference when normalizing. Without this, // `Trait`'s implicit `MetaSized` supertrait requires proving `T::Assoc<_>: MetaSized` @@ -25,5 +28,6 @@ where T::Assoc<[u32; 1]>: Clone, { let _x = T::Assoc::new(()); -//[next]~^ ERROR mismatched types + //[next_sized_hierarchy]~^ ERROR mismatched types + //[current_sized_hierarchy]~^^ ERROR mismatched types } diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr index 1eb445f4848c..8901805a20f5 100644 --- a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr +++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr @@ -12,13 +12,6 @@ LL | impl Trait for T { | ----- ^^^^^^^^ ^ | | | unsatisfied trait bound introduced here -note: required by a bound in `Bound` - --> $DIR/normalizes-to-is-not-productive.rs:8:1 - | -LL | / trait Bound { -LL | | fn method(); -LL | | } - | |_^ required by this bound in `Bound` error[E0277]: the trait bound `Foo: Bound` is not satisfied --> $DIR/normalizes-to-is-not-productive.rs:47:19 diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr index 8d8909625ffc..d179c8059623 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr @@ -19,23 +19,6 @@ error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` LL | Self::Assoc: A, | ^^^^ -error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: MetaSized` - --> $DIR/normalize-param-env-2.rs:24:22 - | -LL | Self::Assoc: A, - | ^^^^ - | -note: required by a bound in `A` - --> $DIR/normalize-param-env-2.rs:9:1 - | -LL | / trait A { -LL | | type Assoc; -LL | | -LL | | fn f() -... | -LL | | } - | |_^ required by this bound in `A` - error[E0275]: overflow evaluating the requirement `<() as A>::Assoc well-formed` --> $DIR/normalize-param-env-2.rs:24:22 | @@ -63,6 +46,6 @@ LL | where LL | Self::Assoc: A, | ^^^^ required by this bound in `A::f` -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr index 9f7f74f94664..f5fd9ce9864c 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr @@ -4,20 +4,6 @@ error[E0275]: overflow evaluating the requirement `::Assoc: Trait` LL | ::Assoc: Trait, | ^^^^^ -error[E0275]: overflow evaluating the requirement `::Assoc: MetaSized` - --> $DIR/normalize-param-env-4.rs:19:26 - | -LL | ::Assoc: Trait, - | ^^^^^ - | -note: required by a bound in `Trait` - --> $DIR/normalize-param-env-4.rs:7:1 - | -LL | / trait Trait { -LL | | type Assoc; -LL | | } - | |_^ required by this bound in `Trait` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/where-clauses/ignore-err-clauses.rs b/tests/ui/where-clauses/ignore-err-clauses.rs index 428ebf4b4083..6f21e5ccbaad 100644 --- a/tests/ui/where-clauses/ignore-err-clauses.rs +++ b/tests/ui/where-clauses/ignore-err-clauses.rs @@ -1,13 +1,13 @@ use std::ops::Add; fn dbl(x: T) -> ::Output -//~^ ERROR type annotations needed where T: Copy + Add, UUU: Copy, //~^ ERROR cannot find type `UUU` in this scope { x + x + //~^ ERROR use of moved value: `x` } fn main() { diff --git a/tests/ui/where-clauses/ignore-err-clauses.stderr b/tests/ui/where-clauses/ignore-err-clauses.stderr index fbf1b99334f4..9c76c1c6a048 100644 --- a/tests/ui/where-clauses/ignore-err-clauses.stderr +++ b/tests/ui/where-clauses/ignore-err-clauses.stderr @@ -1,16 +1,33 @@ error[E0412]: cannot find type `UUU` in this scope - --> $DIR/ignore-err-clauses.rs:7:5 + --> $DIR/ignore-err-clauses.rs:6:5 | LL | UUU: Copy, | ^^^ not found in this scope -error[E0282]: type annotations needed - --> $DIR/ignore-err-clauses.rs:3:14 +error[E0382]: use of moved value: `x` + --> $DIR/ignore-err-clauses.rs:9:9 | LL | fn dbl(x: T) -> ::Output - | ^ cannot infer type for type parameter `T` + | - move occurs because `x` has type `T`, which does not implement the `Copy` trait +... +LL | x + x + | ----^ + | | | + | | value used here after move + | `x` moved due to usage in operator + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/ignore-err-clauses.rs:3:8 + | +LL | fn dbl(x: T) -> ::Output + | ^ consider constraining this type parameter with `Clone` +... +LL | x + x + | - you could clone this value +note: calling this operator moves the left-hand side + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL error: aborting due to 2 previous errors -Some errors have detailed explanations: E0282, E0412. -For more information about an error, try `rustc --explain E0282`. +Some errors have detailed explanations: E0382, E0412. +For more information about an error, try `rustc --explain E0382`. From 750c1e9c39633de1242acf086ef1c053961219b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 21 Jul 2025 09:17:54 +0300 Subject: [PATCH 359/363] Preparing for merge from rust-lang/rust --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 57ff326ce5a2..c2b1c151b834 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -a9fb6103b05c6ad6eee6bed4c0bb5a2e8e1024c6 +e05ab47e6c418fb2b9faa2eae9a7e70c65c98eaa From 1482809fc16f11ecedb92e688922cf52a2441ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 21 Jul 2025 09:19:24 +0300 Subject: [PATCH 360/363] Bump rustc crates --- src/tools/rust-analyzer/Cargo.lock | 40 +++++++++++++++++------------- src/tools/rust-analyzer/Cargo.toml | 10 ++++---- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index e55cd80943df..f3adc4006acf 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1505,7 +1505,7 @@ dependencies = [ "edition", "expect-test", "ra-ap-rustc_lexer", - "rustc-literal-escaper", + "rustc-literal-escaper 0.0.4", "stdx", "tracing", ] @@ -1756,9 +1756,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.121.0" +version = "0.122.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee51482d1c9d3e538acda8cce723db8eea1a81540544bf362bf4c3d841b2329" +checksum = "fb01e1fec578003c85481c1cad4ff8cd8195b07c2dc85ae3f716108507ae15d5" dependencies = [ "bitflags 2.9.1", "ra-ap-rustc_hashes", @@ -1768,18 +1768,18 @@ dependencies = [ [[package]] name = "ra-ap-rustc_hashes" -version = "0.121.0" +version = "0.122.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19c8f1e0c28e24e1b4c55dc08058c6c9829df2204497d4034259f491d348c204" +checksum = "e0ec056e72a472ffef8761ce96ece6c626eb07368c09d0105b6df30d27d07673" dependencies = [ "rustc-stable-hash", ] [[package]] name = "ra-ap-rustc_index" -version = "0.121.0" +version = "0.122.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33f429cec6b92fa2c7243883279fb29dd233fdc3e94099aff32aa91aa87f50" +checksum = "0fcdd1001db0295e59052e9f53aeda588bbe81e362534f4687d41bd44777b5a7" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1787,9 +1787,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.121.0" +version = "0.122.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9b55910dbe1fe7ef34bdc1d1bcb41e99b377eb680ea58a1218d95d6b4152257" +checksum = "728d64dd98e25530b32e3f7c7c1e844e52722b269360daa1cdeba9dff9727a26" dependencies = [ "proc-macro2", "quote", @@ -1798,9 +1798,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.121.0" +version = "0.122.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22944e31fb91e9b3e75bcbc91e37d958b8c0825a6160927f2856831d2ce83b36" +checksum = "415f0821f512608d825b3215489a6a6a2c18ed9f0045953d514e7ec23d4b90ab" dependencies = [ "memchr", "unicode-properties", @@ -1809,19 +1809,19 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.121.0" +version = "0.122.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81057891bc2063ad9e353f29462fbc47a0f5072560af34428ae9313aaa5e9d97" +checksum = "18d2c4b48fa26e031b1cca0c8ca7433770f5e35e33da56da8636dae2cd45d4e1" dependencies = [ "ra-ap-rustc_lexer", - "rustc-literal-escaper", + "rustc-literal-escaper 0.0.5", ] [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.121.0" +version = "0.122.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe21a3542980d56d2435e96c2720773cac1c63fd4db666417e414729da192eb3" +checksum = "4657fcfdfe06e2a02ec8180d4e7c95aecf4811ba50367e363d1a2300b7623284" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.1.1", @@ -1972,6 +1972,12 @@ version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b" +[[package]] +name = "rustc-literal-escaper" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b" + [[package]] name = "rustc-stable-hash" version = "0.1.2" @@ -2259,7 +2265,7 @@ dependencies = [ "rayon", "rowan", "rustc-hash 2.1.1", - "rustc-literal-escaper", + "rustc-literal-escaper 0.0.4", "rustc_apfloat", "smol_str", "stdx", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 41fa06a76a7b..b21ac158d8e7 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -89,11 +89,11 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } edition = { path = "./crates/edition", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.121", default-features = false } -ra-ap-rustc_parse_format = { version = "0.121", default-features = false } -ra-ap-rustc_index = { version = "0.121", default-features = false } -ra-ap-rustc_abi = { version = "0.121", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.121", default-features = false } +ra-ap-rustc_lexer = { version = "0.122", default-features = false } +ra-ap-rustc_parse_format = { version = "0.122", 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 } # local crates that aren't published to crates.io. These should not have versions. From f2633640d6e4dbc544b7c722bcda491a8f564285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 21 Jul 2025 09:27:37 +0300 Subject: [PATCH 361/363] Bump rustc-literal-escaper --- src/tools/rust-analyzer/Cargo.lock | 12 +++--------- src/tools/rust-analyzer/Cargo.toml | 2 +- .../rust-analyzer/crates/syntax/src/ast/token_ext.rs | 4 ++-- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index f3adc4006acf..711d03224644 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1505,7 +1505,7 @@ dependencies = [ "edition", "expect-test", "ra-ap-rustc_lexer", - "rustc-literal-escaper 0.0.4", + "rustc-literal-escaper", "stdx", "tracing", ] @@ -1814,7 +1814,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18d2c4b48fa26e031b1cca0c8ca7433770f5e35e33da56da8636dae2cd45d4e1" dependencies = [ "ra-ap-rustc_lexer", - "rustc-literal-escaper 0.0.5", + "rustc-literal-escaper", ] [[package]] @@ -1966,12 +1966,6 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" -[[package]] -name = "rustc-literal-escaper" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b" - [[package]] name = "rustc-literal-escaper" version = "0.0.5" @@ -2265,7 +2259,7 @@ dependencies = [ "rayon", "rowan", "rustc-hash 2.1.1", - "rustc-literal-escaper 0.0.4", + "rustc-literal-escaper", "rustc_apfloat", "smol_str", "stdx", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index b21ac158d8e7..1ca258abf4b4 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -149,7 +149,7 @@ serde = { version = "1.0.219" } serde_derive = { version = "1.0.219" } serde_json = "1.0.140" rustc-hash = "2.1.1" -rustc-literal-escaper = "0.0.4" +rustc-literal-escaper = "0.0.5" smallvec = { version = "1.15.1", features = [ "const_new", "union", diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs index 4afdda78a0e7..742c452616ef 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs @@ -309,8 +309,8 @@ impl ast::CString { let mut prev_end = 0; let mut has_error = None; let extend_unit = |buf: &mut Vec, unit: MixedUnit| match unit { - MixedUnit::Char(c) => buf.extend(c.encode_utf8(&mut [0; 4]).as_bytes()), - MixedUnit::HighByte(b) => buf.push(b), + MixedUnit::Char(c) => buf.extend(c.get().encode_utf8(&mut [0; 4]).as_bytes()), + MixedUnit::HighByte(b) => buf.push(b.get()), }; unescape_c_str(text, |char_range, unescaped| match (unescaped, buf.capacity() == 0) { (Ok(u), false) => extend_unit(&mut buf, u), From 2050358679088b319cde837f9c6e9d9e58249503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 21 Jul 2025 09:31:28 +0300 Subject: [PATCH 362/363] Revert "Bump rustc-literal-escaper" This reverts commit 9f3adc540b51a4c2d0472d94033f6d9147b36f6e. --- src/tools/rust-analyzer/Cargo.lock | 12 +++++++++--- src/tools/rust-analyzer/Cargo.toml | 2 +- .../rust-analyzer/crates/syntax/src/ast/token_ext.rs | 4 ++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 711d03224644..f3adc4006acf 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1505,7 +1505,7 @@ dependencies = [ "edition", "expect-test", "ra-ap-rustc_lexer", - "rustc-literal-escaper", + "rustc-literal-escaper 0.0.4", "stdx", "tracing", ] @@ -1814,7 +1814,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18d2c4b48fa26e031b1cca0c8ca7433770f5e35e33da56da8636dae2cd45d4e1" dependencies = [ "ra-ap-rustc_lexer", - "rustc-literal-escaper", + "rustc-literal-escaper 0.0.5", ] [[package]] @@ -1966,6 +1966,12 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustc-literal-escaper" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b" + [[package]] name = "rustc-literal-escaper" version = "0.0.5" @@ -2259,7 +2265,7 @@ dependencies = [ "rayon", "rowan", "rustc-hash 2.1.1", - "rustc-literal-escaper", + "rustc-literal-escaper 0.0.4", "rustc_apfloat", "smol_str", "stdx", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 1ca258abf4b4..b21ac158d8e7 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -149,7 +149,7 @@ serde = { version = "1.0.219" } serde_derive = { version = "1.0.219" } serde_json = "1.0.140" rustc-hash = "2.1.1" -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.4" smallvec = { version = "1.15.1", features = [ "const_new", "union", diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs index 742c452616ef..4afdda78a0e7 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs @@ -309,8 +309,8 @@ impl ast::CString { let mut prev_end = 0; let mut has_error = None; let extend_unit = |buf: &mut Vec, unit: MixedUnit| match unit { - MixedUnit::Char(c) => buf.extend(c.get().encode_utf8(&mut [0; 4]).as_bytes()), - MixedUnit::HighByte(b) => buf.push(b.get()), + MixedUnit::Char(c) => buf.extend(c.encode_utf8(&mut [0; 4]).as_bytes()), + MixedUnit::HighByte(b) => buf.push(b), }; unescape_c_str(text, |char_range, unescaped| match (unescaped, buf.capacity() == 0) { (Ok(u), false) => extend_unit(&mut buf, u), From da90db796d0cf39658eac0074c63e5e9ffec2ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 21 Jul 2025 09:36:14 +0300 Subject: [PATCH 363/363] Downgrade ra-ap-rustc_parse_format --- src/tools/rust-analyzer/Cargo.lock | 37 +++++++++++++++++------------- src/tools/rust-analyzer/Cargo.toml | 2 +- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index f3adc4006acf..c471234bbe3a 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1268,7 +1268,7 @@ dependencies = [ "expect-test", "intern", "parser", - "ra-ap-rustc_lexer", + "ra-ap-rustc_lexer 0.122.0", "rustc-hash 2.1.1", "smallvec", "span", @@ -1504,8 +1504,8 @@ dependencies = [ "drop_bomb", "edition", "expect-test", - "ra-ap-rustc_lexer", - "rustc-literal-escaper 0.0.4", + "ra-ap-rustc_lexer 0.122.0", + "rustc-literal-escaper", "stdx", "tracing", ] @@ -1614,7 +1614,7 @@ dependencies = [ "object", "paths", "proc-macro-test", - "ra-ap-rustc_lexer", + "ra-ap-rustc_lexer 0.122.0", "span", "syntax-bridge", "tt", @@ -1796,6 +1796,17 @@ dependencies = [ "syn", ] +[[package]] +name = "ra-ap-rustc_lexer" +version = "0.121.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22944e31fb91e9b3e75bcbc91e37d958b8c0825a6160927f2856831d2ce83b36" +dependencies = [ + "memchr", + "unicode-properties", + "unicode-xid", +] + [[package]] name = "ra-ap-rustc_lexer" version = "0.122.0" @@ -1809,12 +1820,12 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.122.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d2c4b48fa26e031b1cca0c8ca7433770f5e35e33da56da8636dae2cd45d4e1" +checksum = "81057891bc2063ad9e353f29462fbc47a0f5072560af34428ae9313aaa5e9d97" dependencies = [ - "ra-ap-rustc_lexer", - "rustc-literal-escaper 0.0.5", + "ra-ap-rustc_lexer 0.121.0", + "rustc-literal-escaper", ] [[package]] @@ -1972,12 +1983,6 @@ version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b" -[[package]] -name = "rustc-literal-escaper" -version = "0.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b" - [[package]] name = "rustc-stable-hash" version = "0.1.2" @@ -2265,7 +2270,7 @@ dependencies = [ "rayon", "rowan", "rustc-hash 2.1.1", - "rustc-literal-escaper 0.0.4", + "rustc-literal-escaper", "rustc_apfloat", "smol_str", "stdx", @@ -2587,7 +2592,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "intern", - "ra-ap-rustc_lexer", + "ra-ap-rustc_lexer 0.122.0", "stdx", "text-size", ] diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index b21ac158d8e7..700c116ec182 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -90,7 +90,7 @@ 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_parse_format = { version = "0.122", 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 }