From cf0b55eb6232491a7c29ac0f47564b6ee7adb13e Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Tue, 11 Apr 2023 19:47:44 +0000 Subject: Add `needless_maybe_sized` lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/needless_maybe_sized.rs | 164 ++++++++++ tests/ui-toml/type_repetition_in_bounds/main.rs | 1 + .../ui-toml/type_repetition_in_bounds/main.stderr | 2 +- tests/ui/auxiliary/proc_macros.rs | 6 +- tests/ui/needless_maybe_sized.fixed | 116 +++++++ tests/ui/needless_maybe_sized.rs | 119 +++++++ tests/ui/needless_maybe_sized.stderr | 353 +++++++++++++++++++++ tests/ui/type_repetition_in_bounds.rs | 6 +- tests/ui/type_repetition_in_bounds.stderr | 10 +- 12 files changed, 771 insertions(+), 10 deletions(-) create mode 100644 clippy_lints/src/needless_maybe_sized.rs create mode 100644 tests/ui/needless_maybe_sized.fixed create mode 100644 tests/ui/needless_maybe_sized.rs create mode 100644 tests/ui/needless_maybe_sized.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index bd3a04e34ae..aaa53d8a6cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5523,6 +5523,7 @@ Released 2018-09-13 [`needless_late_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_late_init [`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes [`needless_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_match +[`needless_maybe_sized`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_maybe_sized [`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref [`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take [`needless_parens_on_range_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_parens_on_range_literals diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 5ff7d8e5134..dd16e13e7ad 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -527,6 +527,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::needless_for_each::NEEDLESS_FOR_EACH_INFO, crate::needless_if::NEEDLESS_IF_INFO, crate::needless_late_init::NEEDLESS_LATE_INIT_INFO, + crate::needless_maybe_sized::NEEDLESS_MAYBE_SIZED_INFO, crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO, crate::needless_pass_by_ref_mut::NEEDLESS_PASS_BY_REF_MUT_INFO, crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e2aac58bf97..bfddbffe9b2 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -254,6 +254,7 @@ mod needless_else; mod needless_for_each; mod needless_if; mod needless_late_init; +mod needless_maybe_sized; mod needless_parens_on_range_literals; mod needless_pass_by_ref_mut; mod needless_pass_by_value; @@ -1032,6 +1033,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi)); store.register_late_pass(|_| Box::new(collection_is_never_read::CollectionIsNeverRead)); store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage)); + store.register_late_pass(|_| Box::new(needless_maybe_sized::NeedlessMaybeSized)); store.register_late_pass(|_| Box::new(redundant_async_block::RedundantAsyncBlock)); store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped)); store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute)); diff --git a/clippy_lints/src/needless_maybe_sized.rs b/clippy_lints/src/needless_maybe_sized.rs new file mode 100644 index 00000000000..06ae1723a03 --- /dev/null +++ b/clippy_lints/src/needless_maybe_sized.rs @@ -0,0 +1,164 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_errors::Applicability; +use rustc_hir::def_id::{DefId, DefIdMap}; +use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifier, WherePredicate}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{ClauseKind, PredicatePolarity}; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::Ident; + +declare_clippy_lint! { + /// ### What it does + /// Lints `?Sized` bounds applied to type parameters that cannot be unsized + /// + /// ### Why is this bad? + /// The `?Sized` bound is misleading because it cannot be satisfied by an + /// unsized type + /// + /// ### Example + /// ```rust + /// // `T` cannot be unsized because `Clone` requires it to be `Sized` + /// fn f(t: &T) {} + /// ``` + /// Use instead: + /// ```rust + /// fn f(t: &T) {} + /// + /// // or choose alternative bounds for `T` so that it can be unsized + /// ``` + #[clippy::version = "1.79.0"] + pub NEEDLESS_MAYBE_SIZED, + suspicious, + "a `?Sized` bound that is unusable due to a `Sized` requirement" +} +declare_lint_pass!(NeedlessMaybeSized => [NEEDLESS_MAYBE_SIZED]); + +#[allow(clippy::struct_field_names)] +struct Bound<'tcx> { + /// The [`DefId`] of the type parameter the bound refers to + param: DefId, + ident: Ident, + + trait_bound: &'tcx PolyTraitRef<'tcx>, + modifier: TraitBoundModifier, + + predicate_pos: usize, + bound_pos: usize, +} + +/// Finds all of the [`Bound`]s that refer to a type parameter and are not from a macro expansion +fn type_param_bounds<'tcx>(generics: &'tcx Generics<'tcx>) -> impl Iterator> { + generics + .predicates + .iter() + .enumerate() + .filter_map(|(predicate_pos, predicate)| { + let WherePredicate::BoundPredicate(bound_predicate) = predicate else { + return None; + }; + + let (param, ident) = bound_predicate.bounded_ty.as_generic_param()?; + + Some( + bound_predicate + .bounds + .iter() + .enumerate() + .filter_map(move |(bound_pos, bound)| match bound { + &GenericBound::Trait(ref trait_bound, modifier) => Some(Bound { + param, + ident, + trait_bound, + modifier, + predicate_pos, + bound_pos, + }), + GenericBound::Outlives(_) => None, + }) + .filter(|bound| !bound.trait_bound.span.from_expansion()), + ) + }) + .flatten() +} + +/// Searches the supertraits of the trait referred to by `trait_bound` recursively, returning the +/// path taken to find a `Sized` bound if one is found +fn path_to_sized_bound(cx: &LateContext<'_>, trait_bound: &PolyTraitRef<'_>) -> Option> { + fn search(cx: &LateContext<'_>, path: &mut Vec) -> bool { + let trait_def_id = *path.last().unwrap(); + + if Some(trait_def_id) == cx.tcx.lang_items().sized_trait() { + return true; + } + + for &(predicate, _) in cx.tcx.super_predicates_of(trait_def_id).predicates { + if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && trait_predicate.polarity == PredicatePolarity::Positive + && !path.contains(&trait_predicate.def_id()) + { + path.push(trait_predicate.def_id()); + if search(cx, path) { + return true; + } + path.pop(); + } + } + + false + } + + let mut path = vec![trait_bound.trait_ref.trait_def_id()?]; + search(cx, &mut path).then_some(path) +} + +impl LateLintPass<'_> for NeedlessMaybeSized { + fn check_generics(&mut self, cx: &LateContext<'_>, generics: &Generics<'_>) { + let Some(sized_trait) = cx.tcx.lang_items().sized_trait() else { + return; + }; + + let maybe_sized_params: DefIdMap<_> = type_param_bounds(generics) + .filter(|bound| { + bound.trait_bound.trait_ref.trait_def_id() == Some(sized_trait) + && bound.modifier == TraitBoundModifier::Maybe + }) + .map(|bound| (bound.param, bound)) + .collect(); + + for bound in type_param_bounds(generics) { + if bound.modifier == TraitBoundModifier::None + && let Some(sized_bound) = maybe_sized_params.get(&bound.param) + && let Some(path) = path_to_sized_bound(cx, bound.trait_bound) + { + span_lint_and_then( + cx, + NEEDLESS_MAYBE_SIZED, + sized_bound.trait_bound.span, + "`?Sized` bound is ignored because of a `Sized` requirement", + |diag| { + let ty_param = sized_bound.ident; + diag.span_note( + bound.trait_bound.span, + format!("`{ty_param}` cannot be unsized because of the bound"), + ); + + for &[current_id, next_id] in path.array_windows() { + let current = cx.tcx.item_name(current_id); + let next = cx.tcx.item_name(next_id); + diag.note(format!("...because `{current}` has the bound `{next}`")); + } + + diag.span_suggestion_verbose( + generics.span_for_bound_removal(sized_bound.predicate_pos, sized_bound.bound_pos), + "change the bounds that require `Sized`, or remove the `?Sized` bound", + "", + Applicability::MaybeIncorrect, + ); + }, + ); + + return; + } + } + } +} diff --git a/tests/ui-toml/type_repetition_in_bounds/main.rs b/tests/ui-toml/type_repetition_in_bounds/main.rs index 2454c10382d..7f93d2071c9 100644 --- a/tests/ui-toml/type_repetition_in_bounds/main.rs +++ b/tests/ui-toml/type_repetition_in_bounds/main.rs @@ -1,3 +1,4 @@ +#![allow(clippy::needless_maybe_sized)] #![warn(clippy::type_repetition_in_bounds)] fn f() diff --git a/tests/ui-toml/type_repetition_in_bounds/main.stderr b/tests/ui-toml/type_repetition_in_bounds/main.stderr index 6005f76b94b..c5102c39d1c 100644 --- a/tests/ui-toml/type_repetition_in_bounds/main.stderr +++ b/tests/ui-toml/type_repetition_in_bounds/main.stderr @@ -1,5 +1,5 @@ error: this type has already been used as a bound predicate - --> tests/ui-toml/type_repetition_in_bounds/main.rs:13:5 + --> tests/ui-toml/type_repetition_in_bounds/main.rs:14:5 | LL | T: Unpin + PartialEq, | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs index 3303eb14567..4a81a191e72 100644 --- a/tests/ui/auxiliary/proc_macros.rs +++ b/tests/ui/auxiliary/proc_macros.rs @@ -57,7 +57,7 @@ fn group_with_span(delimiter: Delimiter, stream: TokenStream, span: Span) -> Gro const ESCAPE_CHAR: char = '$'; /// Takes a single token followed by a sequence of tokens. Returns the sequence of tokens with their -/// span set to that of the first token. Tokens may be escaped with either `#ident` or `#(tokens)`. +/// span set to that of the first token. Tokens may be escaped with either `$ident` or `$(tokens)`. #[proc_macro] pub fn with_span(input: TokenStream) -> TokenStream { let mut iter = input.into_iter(); @@ -71,7 +71,7 @@ pub fn with_span(input: TokenStream) -> TokenStream { } /// Takes a sequence of tokens and return the tokens with the span set such that they appear to be -/// from an external macro. Tokens may be escaped with either `#ident` or `#(tokens)`. +/// from an external macro. Tokens may be escaped with either `$ident` or `$(tokens)`. #[proc_macro] pub fn external(input: TokenStream) -> TokenStream { let mut res = TokenStream::new(); @@ -83,7 +83,7 @@ pub fn external(input: TokenStream) -> TokenStream { } /// Copies all the tokens, replacing all their spans with the given span. Tokens can be escaped -/// either by `#ident` or `#(tokens)`. +/// either by `$ident` or `$(tokens)`. fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Result<()> { while let Some(tt) = input.next() { match tt { diff --git a/tests/ui/needless_maybe_sized.fixed b/tests/ui/needless_maybe_sized.fixed new file mode 100644 index 00000000000..4d24a7cee61 --- /dev/null +++ b/tests/ui/needless_maybe_sized.fixed @@ -0,0 +1,116 @@ +//@aux-build:proc_macros.rs + +#![allow(unused, clippy::multiple_bound_locations)] +#![warn(clippy::needless_maybe_sized)] + +extern crate proc_macros; +use proc_macros::external; + +fn directly(t: &T) {} + +trait A: Sized {} +trait B: A {} + +fn depth_1(t: &T) {} +fn depth_2(t: &T) {} + +// We only need to show one +fn multiple_paths(t: &T) {} + +fn in_where(t: &T) +where + T: Sized, +{ +} + +fn mixed_1(t: &T) +{ +} + +fn mixed_2(t: &T) +where + T: Sized, +{ +} + +fn mixed_3(t: &T) +where + T: Sized, +{ +} + +struct Struct(T); + +impl Struct { + fn method(&self) {} +} + +enum Enum { + Variant(&'static T), +} + +union Union<'a, T: Sized> { + a: &'a T, +} + +trait Trait { + fn trait_method() {} + + type GAT; + + type Assoc: Sized + ?Sized; // False negative +} + +trait SecondInTrait: Send + Sized {} +fn second_in_trait() {} + +fn impl_trait(_: &(impl Sized)) {} + +trait GenericTrait: Sized {} +fn in_generic_trait, U>() {} + +mod larger_graph { + // C1 C2 Sized + // \ /\ / + // B1 B2 + // \ / + // A1 + + trait C1 {} + trait C2 {} + trait B1: C1 + C2 {} + trait B2: C2 + Sized {} + trait A1: B1 + B2 {} + + fn larger_graph() {} +} + +// Should not lint + +fn sized() {} +fn maybe_sized() {} + +struct SeparateBounds(T); +impl SeparateBounds {} + +trait P {} +trait Q: P {} + +fn ok_depth_1() {} +fn ok_depth_2() {} + +external! { + fn in_macro(t: &T) {} + + fn with_local_clone(t: &T) {} +} + +#[derive(Clone)] +struct InDerive { + t: T, +} + +struct Refined(T); +impl Refined {} + +fn main() {} diff --git a/tests/ui/needless_maybe_sized.rs b/tests/ui/needless_maybe_sized.rs new file mode 100644 index 00000000000..ef66f9a4f2a --- /dev/null +++ b/tests/ui/needless_maybe_sized.rs @@ -0,0 +1,119 @@ +//@aux-build:proc_macros.rs + +#![allow(unused, clippy::multiple_bound_locations)] +#![warn(clippy::needless_maybe_sized)] + +extern crate proc_macros; +use proc_macros::external; + +fn directly(t: &T) {} + +trait A: Sized {} +trait B: A {} + +fn depth_1(t: &T) {} +fn depth_2(t: &T) {} + +// We only need to show one +fn multiple_paths(t: &T) {} + +fn in_where(t: &T) +where + T: Sized + ?Sized, +{ +} + +fn mixed_1(t: &T) +where + T: ?Sized, +{ +} + +fn mixed_2(t: &T) +where + T: Sized, +{ +} + +fn mixed_3(t: &T) +where + T: Sized, + T: ?Sized, +{ +} + +struct Struct(T); + +impl Struct { + fn method(&self) {} +} + +enum Enum { + Variant(&'static T), +} + +union Union<'a, T: Sized + ?Sized> { + a: &'a T, +} + +trait Trait { + fn trait_method() {} + + type GAT; + + type Assoc: Sized + ?Sized; // False negative +} + +trait SecondInTrait: Send + Sized {} +fn second_in_trait() {} + +fn impl_trait(_: &(impl Sized + ?Sized)) {} + +trait GenericTrait: Sized {} +fn in_generic_trait + ?Sized, U>() {} + +mod larger_graph { + // C1 C2 Sized + // \ /\ / + // B1 B2 + // \ / + // A1 + + trait C1 {} + trait C2 {} + trait B1: C1 + C2 {} + trait B2: C2 + Sized {} + trait A1: B1 + B2 {} + + fn larger_graph() {} +} + +// Should not lint + +fn sized() {} +fn maybe_sized() {} + +struct SeparateBounds(T); +impl SeparateBounds {} + +trait P {} +trait Q: P {} + +fn ok_depth_1() {} +fn ok_depth_2() {} + +external! { + fn in_macro(t: &T) {} + + fn with_local_clone(t: &T) {} +} + +#[derive(Clone)] +struct InDerive { + t: T, +} + +struct Refined(T); +impl Refined {} + +fn main() {} diff --git a/tests/ui/needless_maybe_sized.stderr b/tests/ui/needless_maybe_sized.stderr new file mode 100644 index 00000000000..3b1d2b49b06 --- /dev/null +++ b/tests/ui/needless_maybe_sized.stderr @@ -0,0 +1,353 @@ +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:9:24 + | +LL | fn directly(t: &T) {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:9:16 + | +LL | fn directly(t: &T) {} + | ^^^^^ + = note: `-D clippy::needless-maybe-sized` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_maybe_sized)]` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn directly(t: &T) {} +LL + fn directly(t: &T) {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:14:19 + | +LL | fn depth_1(t: &T) {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:14:15 + | +LL | fn depth_1(t: &T) {} + | ^ + = note: ...because `A` has the bound `Sized` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn depth_1(t: &T) {} +LL + fn depth_1(t: &T) {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:15:19 + | +LL | fn depth_2(t: &T) {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:15:15 + | +LL | fn depth_2(t: &T) {} + | ^ + = note: ...because `B` has the bound `A` + = note: ...because `A` has the bound `Sized` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn depth_2(t: &T) {} +LL + fn depth_2(t: &T) {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:18:30 + | +LL | fn multiple_paths(t: &T) {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:18:22 + | +LL | fn multiple_paths(t: &T) {} + | ^ + = note: ...because `A` has the bound `Sized` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn multiple_paths(t: &T) {} +LL + fn multiple_paths(t: &T) {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:22:16 + | +LL | T: Sized + ?Sized, + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:22:8 + | +LL | T: Sized + ?Sized, + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - T: Sized + ?Sized, +LL + T: Sized, + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:28:8 + | +LL | T: ?Sized, + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:26:15 + | +LL | fn mixed_1(t: &T) + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - where +LL - T: ?Sized, + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:32:15 + | +LL | fn mixed_2(t: &T) + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:34:8 + | +LL | T: Sized, + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn mixed_2(t: &T) +LL + fn mixed_2(t: &T) + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:41:8 + | +LL | T: ?Sized, + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:40:8 + | +LL | T: Sized, + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - T: Sized, +LL - T: ?Sized, +LL + T: Sized, + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:45:26 + | +LL | struct Struct(T); + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:45:18 + | +LL | struct Struct(T); + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - struct Struct(T); +LL + struct Struct(T); + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:47:17 + | +LL | impl Struct { + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:47:9 + | +LL | impl Struct { + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - impl Struct { +LL + impl Struct { + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:48:26 + | +LL | fn method(&self) {} + | ^^^^^^ + | +note: `U` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:48:18 + | +LL | fn method(&self) {} + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn method(&self) {} +LL + fn method(&self) {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:51:22 + | +LL | enum Enum { + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:51:14 + | +LL | enum Enum { + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - enum Enum { +LL + enum Enum { + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:55:28 + | +LL | union Union<'a, T: Sized + ?Sized> { + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:55:20 + | +LL | union Union<'a, T: Sized + ?Sized> { + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - union Union<'a, T: Sized + ?Sized> { +LL + union Union<'a, T: Sized> { + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:59:24 + | +LL | trait Trait { + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:59:16 + | +LL | trait Trait { + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - trait Trait { +LL + trait Trait { + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:60:32 + | +LL | fn trait_method() {} + | ^^^^^^ + | +note: `U` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:60:24 + | +LL | fn trait_method() {} + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn trait_method() {} +LL + fn trait_method() {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:62:25 + | +LL | type GAT; + | ^^^^^^ + | +note: `U` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:62:17 + | +LL | type GAT; + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - type GAT; +LL + type GAT; + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:68:23 + | +LL | fn second_in_trait() {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:68:32 + | +LL | fn second_in_trait() {} + | ^^^^^^^^^^^^^ + = note: ...because `SecondInTrait` has the bound `Sized` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn second_in_trait() {} +LL + fn second_in_trait() {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:70:33 + | +LL | fn impl_trait(_: &(impl Sized + ?Sized)) {} + | ^^^^^^ + | +note: `impl Sized + ?Sized` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:70:25 + | +LL | fn impl_trait(_: &(impl Sized + ?Sized)) {} + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn impl_trait(_: &(impl Sized + ?Sized)) {} +LL + fn impl_trait(_: &(impl Sized)) {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:73:42 + | +LL | fn in_generic_trait + ?Sized, U>() {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:73:24 + | +LL | fn in_generic_trait + ?Sized, U>() {} + | ^^^^^^^^^^^^^^^ + = note: ...because `GenericTrait` has the bound `Sized` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn in_generic_trait + ?Sized, U>() {} +LL + fn in_generic_trait, U>() {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:88:29 + | +LL | fn larger_graph() {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:88:24 + | +LL | fn larger_graph() {} + | ^^ + = note: ...because `A1` has the bound `B2` + = note: ...because `B2` has the bound `Sized` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn larger_graph() {} +LL + fn larger_graph() {} + | + +error: aborting due to 20 previous errors + diff --git a/tests/ui/type_repetition_in_bounds.rs b/tests/ui/type_repetition_in_bounds.rs index 0039c805b7d..d325887bfba 100644 --- a/tests/ui/type_repetition_in_bounds.rs +++ b/tests/ui/type_repetition_in_bounds.rs @@ -1,5 +1,9 @@ #![deny(clippy::type_repetition_in_bounds)] -#![allow(clippy::extra_unused_type_parameters, clippy::multiple_bound_locations)] +#![allow( + clippy::extra_unused_type_parameters, + clippy::multiple_bound_locations, + clippy::needless_maybe_sized +)] use serde::Deserialize; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; diff --git a/tests/ui/type_repetition_in_bounds.stderr b/tests/ui/type_repetition_in_bounds.stderr index e9c6b41aaa8..77944c95045 100644 --- a/tests/ui/type_repetition_in_bounds.stderr +++ b/tests/ui/type_repetition_in_bounds.stderr @@ -1,5 +1,5 @@ error: this type has already been used as a bound predicate - --> tests/ui/type_repetition_in_bounds.rs:10:5 + --> tests/ui/type_repetition_in_bounds.rs:14:5 | LL | T: Clone, | ^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(clippy::type_repetition_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this type has already been used as a bound predicate - --> tests/ui/type_repetition_in_bounds.rs:28:5 + --> tests/ui/type_repetition_in_bounds.rs:32:5 | LL | Self: Copy + Default + Ord, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | Self: Copy + Default + Ord, = help: consider combining the bounds: `Self: Clone + Copy + Default + Ord` error: this type has already been used as a bound predicate - --> tests/ui/type_repetition_in_bounds.rs:103:5 + --> tests/ui/type_repetition_in_bounds.rs:107:5 | LL | T: Clone, | ^^^^^^^^ @@ -28,7 +28,7 @@ LL | T: Clone, = help: consider combining the bounds: `T: ?Sized + Clone` error: this type has already been used as a bound predicate - --> tests/ui/type_repetition_in_bounds.rs:109:5 + --> tests/ui/type_repetition_in_bounds.rs:113:5 | LL | T: ?Sized, | ^^^^^^^^^ @@ -36,7 +36,7 @@ LL | T: ?Sized, = help: consider combining the bounds: `T: Clone + ?Sized` error: this type has already been used as a bound predicate - --> tests/ui/type_repetition_in_bounds.rs:135:9 + --> tests/ui/type_repetition_in_bounds.rs:139:9 | LL | T: Trait, Box<[String]>, bool> + 'static, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 334bab2c253bfe1cdff6c0ebf93b82fb0e963b61 Mon Sep 17 00:00:00 2001 From: Luv-Ray Date: Sun, 21 Apr 2024 19:53:47 +0800 Subject: [`overly_complex_bool_expr`]: Fix trigger wrongly on never type --- clippy_lints/src/booleans.rs | 5 +++++ tests/ui/overly_complex_bool_expr.fixed | 10 ++++++++++ tests/ui/overly_complex_bool_expr.rs | 10 ++++++++++ 3 files changed, 25 insertions(+) diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index b6341b3fe8e..eae34e85e78 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -232,6 +232,11 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { _ => (), } } + + if self.cx.typeck_results().expr_ty(e).is_never() { + return Err("contains never type".to_owned()); + } + for (n, expr) in self.terminals.iter().enumerate() { if eq_expr_value(self.cx, e, expr) { #[expect(clippy::cast_possible_truncation)] diff --git a/tests/ui/overly_complex_bool_expr.fixed b/tests/ui/overly_complex_bool_expr.fixed index e44f6063156..439b1145431 100644 --- a/tests/ui/overly_complex_bool_expr.fixed +++ b/tests/ui/overly_complex_bool_expr.fixed @@ -37,3 +37,13 @@ fn check_expect() { #[expect(clippy::overly_complex_bool_expr)] let _ = a < b && a >= b; } + +#[allow(clippy::never_loop)] +fn check_never_type() { + loop { + _ = (break) || true; + } + loop { + _ = (return) || true; + } +} diff --git a/tests/ui/overly_complex_bool_expr.rs b/tests/ui/overly_complex_bool_expr.rs index f010a8537e7..b96fd1adf11 100644 --- a/tests/ui/overly_complex_bool_expr.rs +++ b/tests/ui/overly_complex_bool_expr.rs @@ -37,3 +37,13 @@ fn check_expect() { #[expect(clippy::overly_complex_bool_expr)] let _ = a < b && a >= b; } + +#[allow(clippy::never_loop)] +fn check_never_type() { + loop { + _ = (break) || true; + } + loop { + _ = (return) || true; + } +} -- cgit 1.4.1-3-g733a5 From e6040437ef5e6f2ac8110fd160c58ec2fa8ad202 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 17 May 2024 16:45:00 +0000 Subject: Swap `for_each_expr` and `for_each_expr_with_closures` --- clippy_lints/src/blocks_in_conditions.rs | 4 ++-- clippy_lints/src/casts/cast_sign_loss.rs | 6 +++--- clippy_lints/src/casts/unnecessary_cast.rs | 4 ++-- clippy_lints/src/cognitive_complexity.rs | 4 ++-- clippy_lints/src/collection_is_never_read.rs | 4 ++-- clippy_lints/src/copies.rs | 6 +++--- clippy_lints/src/functions/must_use.rs | 4 ++-- clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs | 4 ++-- clippy_lints/src/implicit_return.rs | 4 ++-- clippy_lints/src/matches/redundant_guards.rs | 4 ++-- clippy_lints/src/matches/redundant_pattern_match.rs | 4 ++-- clippy_lints/src/methods/collapsible_str_replace.rs | 4 ++-- clippy_lints/src/methods/str_splitn.rs | 4 ++-- clippy_lints/src/methods/unnecessary_filter_map.rs | 4 ++-- clippy_lints/src/methods/unnecessary_iter_cloned.rs | 4 ++-- clippy_lints/src/missing_asserts_for_indexing.rs | 4 ++-- clippy_lints/src/missing_fields_in_debug.rs | 6 +++--- clippy_lints/src/multiple_unsafe_ops_per_block.rs | 4 ++-- clippy_lints/src/needless_late_init.rs | 6 +++--- clippy_lints/src/needless_pass_by_ref_mut.rs | 4 ++-- clippy_lints/src/operators/assign_op_pattern.rs | 4 ++-- clippy_lints/src/panic_in_result_fn.rs | 4 ++-- clippy_lints/src/redundant_async_block.rs | 4 ++-- clippy_lints/src/returns.rs | 4 ++-- clippy_lints/src/suspicious_trait_impl.rs | 4 ++-- clippy_lints/src/undocumented_unsafe_blocks.rs | 4 ++-- clippy_lints/src/unused_self.rs | 2 +- clippy_lints/src/unwrap_in_result.rs | 4 ++-- clippy_lints/src/zero_repeat_side_effects.rs | 4 ++-- clippy_utils/src/lib.rs | 4 ++-- clippy_utils/src/macros.rs | 10 +++++----- clippy_utils/src/ptr.rs | 4 ++-- clippy_utils/src/usage.rs | 8 ++++---- clippy_utils/src/visitors.rs | 14 +++++++------- 34 files changed, 81 insertions(+), 81 deletions(-) diff --git a/clippy_lints/src/blocks_in_conditions.rs b/clippy_lints/src/blocks_in_conditions.rs index 171f3031860..869ed332b9c 100644 --- a/clippy_lints/src/blocks_in_conditions.rs +++ b/clippy_lints/src/blocks_in_conditions.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_block_with_applicability; use clippy_utils::ty::implements_trait; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; use clippy_utils::{get_parent_expr, higher, is_from_proc_macro}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -125,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInConditions { } } } else { - let _: Option = for_each_expr(cond, |e| { + let _: Option = for_each_expr_without_closures(cond, |e| { if let ExprKind::Closure(closure) = e.kind { // do not lint if the closure is called using an iterator (see #1141) if let Some(parent) = get_parent_expr(cx, e) diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 864489ee3fc..8bbd41b0db1 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; use clippy_utils::{method_chain_args, sext}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -266,7 +266,7 @@ fn expr_add_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign { fn exprs_with_muldiv_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> { let mut res = vec![]; - for_each_expr(expr, |sub_expr| -> ControlFlow { + for_each_expr_without_closures(expr, |sub_expr| -> ControlFlow { // We don't check for mul/div/rem methods here, but we could. if let ExprKind::Binary(op, lhs, _rhs) = sub_expr.kind { if matches!(op.node, BinOpKind::Mul | BinOpKind::Div) { @@ -315,7 +315,7 @@ fn exprs_with_muldiv_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> { fn exprs_with_add_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> { let mut res = vec![]; - for_each_expr(expr, |sub_expr| -> ControlFlow { + for_each_expr_without_closures(expr, |sub_expr| -> ControlFlow { // We don't check for add methods here, but we could. if let ExprKind::Binary(op, _lhs, _rhs) = sub_expr.kind { if matches!(op.node, BinOpKind::Add) { diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index a7f7bf7854e..fb0b0cba6a6 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; use clippy_utils::source::snippet_opt; -use clippy_utils::visitors::{for_each_expr, Visitable}; +use clippy_utils::visitors::{for_each_expr_without_closures, Visitable}; use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; @@ -245,7 +245,7 @@ fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 { /// TODO: Maybe we should move this to `clippy_utils` so others won't need to go down this dark, /// dark path reimplementing this (or something similar). fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx>, cast_from: Ty<'tcx>) -> bool { - for_each_expr(expr, |expr| { + for_each_expr_without_closures(expr, |expr| { // Calls are a `Path`, and usage of locals are a `Path`. So, this checks // - call() as i32 // - local as i32 diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index ee1bb63b50d..e41abf42234 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack}; use core::ops::ControlFlow; use rustc_ast::ast::Attribute; @@ -65,7 +65,7 @@ impl CognitiveComplexity { let mut cc = 1u64; let mut returns = 0u64; - let _: Option = for_each_expr(expr, |e| { + let _: Option = for_each_expr_without_closures(expr, |e| { match e.kind { ExprKind::If(_, _, _) => { cc += 1; diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index 70856b80881..28d9f68d504 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use clippy_utils::visitors::{for_each_expr_with_closures, Visitable}; +use clippy_utils::visitors::{for_each_expr, Visitable}; use clippy_utils::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; @@ -82,7 +82,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI let mut has_read_access = false; // Inspect all expressions and sub-expressions in the block. - for_each_expr_with_closures(cx, block, |expr| { + for_each_expr(cx, block, |expr| { // Ignore expressions that are not simply `id`. if !path_to_local_id(expr, id) { return ControlFlow::Continue(()); diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index ccf1d9d6f8c..480df675d75 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt}; use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ capture_local_usage, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, if_sequence, is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, @@ -362,7 +362,7 @@ fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool { /// Checks if the statement modifies or moves any of the given locals. fn modifies_any_local<'tcx>(cx: &LateContext<'tcx>, s: &'tcx Stmt<'_>, locals: &HirIdSet) -> bool { - for_each_expr(s, |e| { + for_each_expr_without_closures(s, |e| { if let Some(id) = path_to_local(e) && locals.contains(&id) && !capture_local_usage(cx, e).is_imm_ref() @@ -413,7 +413,7 @@ fn scan_block_for_eq<'tcx>( let mut cond_locals = HirIdSet::default(); for &cond in conds { - let _: Option = for_each_expr(cond, |e| { + let _: Option = for_each_expr_without_closures(cond, |e| { if let Some(id) = path_to_local(e) { cond_locals.insert(id); } diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index e7ec2b3151e..cce8617821e 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -14,7 +14,7 @@ use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_must_use_ty; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{return_ty, trait_ref_of_method}; use core::ops::ControlFlow; @@ -226,7 +226,7 @@ fn is_mutated_static(e: &hir::Expr<'_>) -> bool { } fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bool { - for_each_expr(body.value, |e| { + for_each_expr_without_closures(body.value, |e| { use hir::ExprKind::{AddrOf, Assign, AssignOp, Call, MethodCall}; match e.kind { diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index 995dd782cbb..466d38c52d7 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -5,7 +5,7 @@ use rustc_span::def_id::LocalDefId; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::type_is_unsafe_function; -use clippy_utils::visitors::for_each_expr_with_closures; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{iter_input_pats, path_to_local}; use core::ops::ControlFlow; @@ -49,7 +49,7 @@ fn check_raw_ptr<'tcx>( if !raw_ptrs.is_empty() { let typeck = cx.tcx.typeck_body(body.id()); - let _: Option = for_each_expr_with_closures(cx, body.value, |e| { + let _: Option = for_each_expr(cx, body.value, |e| { match e.kind { hir::ExprKind::Call(f, args) if type_is_unsafe_function(cx, typeck.expr_ty(f)) => { for arg in args { diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 5288efd8df8..b54c147e4d8 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{get_async_fn_body, is_async_fn}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -152,7 +152,7 @@ fn lint_implicit_returns( ExprKind::Loop(block, ..) => { let mut add_return = false; - let _: Option = for_each_expr(block, |e| { + let _: Option = for_each_expr_without_closures(block, |e| { if let ExprKind::Break(dest, sub_expr) = e.kind { if dest.target_id.ok() == Some(expr.hir_id) { if call_site_span.is_none() && e.span.ctxt() == ctxt { diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index a75cf37945f..c2c0fbf439d 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -2,7 +2,7 @@ use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::source::snippet; -use clippy_utils::visitors::{for_each_expr, is_local_used}; +use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used}; use clippy_utils::{in_constant, path_to_local}; use rustc_ast::{BorrowKind, LitKind}; use rustc_errors::Applicability; @@ -249,7 +249,7 @@ fn emit_redundant_guards<'tcx>( /// an error in the future, and rustc already actively warns against this (see rust#41620), /// so we don't consider those as usable within patterns for linting purposes. fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - for_each_expr(expr, |expr| { + for_each_expr_without_closures(expr, |expr| { if match expr.kind { ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat, ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => { diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 78973984fb0..0e4b2d9d34a 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::sugg::{make_unop, Sugg}; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; -use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr}; +use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures}; use clippy_utils::{higher, is_expn_of, is_trait_method}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -283,7 +283,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op // to see that there aren't any let chains anywhere in the guard, as that would break // if we suggest `t.is_none() && (let X = y && z)` for: // `match t { None if let X = y && z => true, _ => false }` - let has_nested_let_chain = for_each_expr(guard, |expr| { + let has_nested_let_chain = for_each_expr_without_closures(guard, |expr| { if matches!(expr.kind, ExprKind::Let(..)) { ControlFlow::Break(()) } else { diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index 5409ede6008..1fab6c0e499 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{eq_expr_value, get_parent_expr}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -46,7 +46,7 @@ fn collect_replace_calls<'tcx>( let mut methods = VecDeque::new(); let mut from_args = VecDeque::new(); - let _: Option<()> = for_each_expr(expr, |e| { + let _: Option<()> = for_each_expr_without_closures(expr, |e| { if let Some(("replace", _, [from, to], _, _)) = method_call(e) { if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() { methods.push_front(e); diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index e8c12bbeea0..4f42fb73547 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; -use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; +use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -209,7 +209,7 @@ fn indirect_usage<'tcx>( }) = stmt.kind { let mut path_to_binding = None; - let _: Option = for_each_expr_with_closures(cx, init_expr, |e| { + let _: Option = for_each_expr(cx, init_expr, |e| { if path_to_local_id(e, binding) { path_to_binding = Some(e); } diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index daf99d98614..c9b9d98dbe6 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir as hir; @@ -26,7 +26,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, body.value); - let _: Option = for_each_expr(body.value, |e| { + let _: Option = for_each_expr_without_closures(body.value, |e| { if let hir::ExprKind::Ret(Some(e)) = &e.kind { let (found_mapping_res, found_filtering_res) = check_expression(cx, arg_id, e); found_mapping |= found_mapping_res; diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 7431dc1cf0b..e23ea54867f 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr, path_to_local}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -61,7 +61,7 @@ pub fn check_for_loop_iter( fn is_caller_or_fields_change(cx: &LateContext<'_>, body: &Expr<'_>, caller: &Expr<'_>) -> bool { let mut change = false; if let ExprKind::Block(block, ..) = body.kind { - for_each_expr(block, |e| { + for_each_expr_without_closures(block, |e| { match e.kind { ExprKind::Assign(assignee, _, _) | ExprKind::AssignOp(_, assignee, _) => { change |= !can_mut_borrow_both(cx, caller, assignee); diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index c29e46b941c..a95b567ef5f 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -4,7 +4,7 @@ use std::ops::ControlFlow; use clippy_utils::comparisons::{normalize_comparison, Rel}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{eq_expr_value, hash_expr, higher}; use rustc_ast::{LitKind, RangeLimits}; use rustc_data_structures::packed::Pu128; @@ -405,7 +405,7 @@ impl LateLintPass<'_> for MissingAssertsForIndexing { fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) { let mut map = UnhashMap::default(); - for_each_expr(body.value, |expr| { + for_each_expr_without_closures(body.value, |expr| { check_index(cx, expr, &mut map); check_assert(cx, expr, &mut map); ControlFlow::::Continue(()) diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index a64faa124f0..10f6cb7c0d3 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_path_lang_item; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{for_each_expr, Visitable}; +use clippy_utils::visitors::{for_each_expr_without_closures, Visitable}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; @@ -110,7 +110,7 @@ fn should_lint<'tcx>( // Is there a call to `DebugStruct::debug_struct`? Do lint if there is. let mut has_debug_struct = false; - for_each_expr(block, |expr| { + for_each_expr_without_closures(block, |expr| { if let ExprKind::MethodCall(path, recv, ..) = &expr.kind { let recv_ty = typeck_results.expr_ty(recv).peel_refs(); @@ -165,7 +165,7 @@ fn check_struct<'tcx>( let mut has_direct_field_access = false; let mut field_accesses = FxHashSet::default(); - for_each_expr(block, |expr| { + for_each_expr_without_closures(block, |expr| { if let ExprKind::Field(target, ident) = expr.kind && let target_ty = typeck_results.expr_ty_adjusted(target).peel_refs() && target_ty == self_ty diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 0e138066780..ca995cc76da 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::visitors::{for_each_expr_with_closures, Descend, Visitable}; +use clippy_utils::visitors::{for_each_expr, Descend, Visitable}; use core::ops::ControlFlow::Continue; use hir::def::{DefKind, Res}; use hir::{BlockCheckMode, ExprKind, QPath, UnOp, Unsafety}; @@ -96,7 +96,7 @@ fn collect_unsafe_exprs<'tcx>( node: impl Visitable<'tcx>, unsafe_ops: &mut Vec<(&'static str, Span)>, ) { - for_each_expr_with_closures(cx, node, |expr| { + for_each_expr(cx, node, |expr| { match expr.kind { ExprKind::InlineAsm(_) => unsafe_ops.push(("inline assembly used here", expr.span)), diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 5a0ae1a4d6d..4bfc30fa5cf 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::path_to_local; use clippy_utils::source::snippet_opt; use clippy_utils::ty::needs_ordered_drop; -use clippy_utils::visitors::{for_each_expr, for_each_expr_with_closures, is_local_used}; +use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used}; use core::ops::ControlFlow; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::{ @@ -63,7 +63,7 @@ declare_clippy_lint! { declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]); fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool { - for_each_expr_with_closures(cx, stmt, |e| { + for_each_expr(cx, stmt, |e| { if matches!(e.kind, ExprKind::Assign(..)) { ControlFlow::Break(()) } else { @@ -74,7 +74,7 @@ fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> } fn contains_let(cond: &Expr<'_>) -> bool { - for_each_expr(cond, |e| { + for_each_expr_without_closures(cond, |e| { if matches!(e.kind, ExprKind::Let(_)) { ControlFlow::Break(()) } else { diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index da6ed5fb96f..57ba0da5331 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -1,7 +1,7 @@ use super::needless_pass_by_value::requires_exact_signature; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr_with_closures; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{inherits_cfg, is_from_proc_macro, is_self}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; @@ -205,7 +205,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { // We retrieve all the closures declared in the function because they will not be found // by `euv::Delegate`. let mut closures: FxHashSet = FxHashSet::default(); - for_each_expr_with_closures(cx, body, |expr| { + for_each_expr(cx, body, |expr| { if let ExprKind::Closure(closure) = expr.kind { closures.insert(closure.def_id); } diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 910e584a7a0..641d881d974 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( }; let mut found = false; - let found_multiple = for_each_expr(e, |e| { + let found_multiple = for_each_expr_without_closures(e, |e| { if eq_expr_value(cx, assignee, e) { if found { return ControlFlow::Break(()); diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index f821a4efee7..6d43143abab 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::return_ty; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) { let mut panics = Vec::new(); - let _: Option = for_each_expr(body.value, |e| { + let _: Option = for_each_expr_without_closures(body.value, |e| { let Some(macro_call) = root_macro_call_first_node(cx, e) else { return ControlFlow::Continue(Descend::Yes); }; diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 0ed957f1f2f..313e4083256 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::ty::implements_trait; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use rustc_errors::Applicability; use rustc_hir::{ Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource, @@ -107,7 +107,7 @@ fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind && let ExprKind::Call(_, [into_future_arg]) = match_value.kind && let ctxt = expr.span.ctxt() - && for_each_expr(into_future_arg, |e| { + && for_each_expr_without_closures(into_future_arg, |e| { walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(())) }) .is_none() diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index e8f9d438104..bf0903a6b1b 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; +use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::{ fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg, span_find_starting_semi, @@ -444,7 +444,7 @@ fn emit_return_lint( } fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - for_each_expr_with_closures(cx, expr, |e| { + for_each_expr(cx, expr, |e| { if let Some(def_id) = fn_def_id(cx, e) && cx .tcx diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 3f030b80331..744d6392e06 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TRAITS}; use core::ops::ControlFlow; use rustc_hir as hir; @@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { fn count_binops(expr: &hir::Expr<'_>) -> u32 { let mut count = 0u32; - let _: Option = for_each_expr(expr, |e| { + let _: Option = for_each_expr_without_closures(expr, |e| { if matches!( e.kind, hir::ExprKind::Binary(..) diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index cbd16180077..6ab9d641bdb 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_lint_allowed; use clippy_utils::source::walk_span_to_context; -use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; +use clippy_utils::visitors::{for_each_expr, Descend}; use hir::HirId; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; @@ -297,7 +297,7 @@ fn expr_has_unnecessary_safety_comment<'tcx>( } // this should roughly be the reverse of `block_parents_have_safety_comment` - if for_each_expr_with_closures(cx, expr, |expr| match expr.kind { + if for_each_expr(cx, expr, |expr| match expr.kind { hir::ExprKind::Block( Block { rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index a67f53f00ae..3e6102f5982 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { let parent_item = cx.tcx.hir().expect_item(parent); let assoc_item = cx.tcx.associated_item(impl_item.owner_id); let contains_todo = |cx, body: &'_ Body<'_>| -> bool { - clippy_utils::visitors::for_each_expr(body.value, |e| { + clippy_utils::visitors::for_each_expr_without_closures(body.value, |e| { if let Some(macro_call) = root_macro_call_first_node(cx, e) { if cx.tcx.item_name(macro_call.def_id).as_str() == "todo" { ControlFlow::Break(()) diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index aca500590ce..a4142a30ea4 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{method_chain_args, return_ty}; use core::ops::ControlFlow; use rustc_hir as hir; @@ -75,7 +75,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc let body = cx.tcx.hir().body(body_id); let typeck = cx.tcx.typeck(impl_item.owner_id.def_id); let mut result = Vec::new(); - let _: Option = for_each_expr(body.value, |e| { + let _: Option = for_each_expr_without_closures(body.value, |e| { // check for `expect` if let Some(arglists) = method_chain_args(e, &["expect"]) { let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); diff --git a/clippy_lints/src/zero_repeat_side_effects.rs b/clippy_lints/src/zero_repeat_side_effects.rs index 143fecdd237..da198b78d2e 100644 --- a/clippy_lints/src/zero_repeat_side_effects.rs +++ b/clippy_lints/src/zero_repeat_side_effects.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::VecArgs; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Node}; @@ -66,7 +66,7 @@ impl LateLintPass<'_> for ZeroRepeatSideEffects { fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr: &'_ rustc_hir::Expr<'_>, is_vec: bool) { // check if expr is a call or has a call inside it - if for_each_expr(inner_expr, |x| { + if for_each_expr_without_closures(inner_expr, |x| { if let ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _, _) = x.kind { std::ops::ControlFlow::Break(()) } else { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 4c603bda770..3bd09525d5a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -126,7 +126,7 @@ use visitors::Visitable; use crate::consts::{constant, mir_to_const, Constant}; use crate::higher::Range; use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; -use crate::visitors::for_each_expr; +use crate::visitors::for_each_expr_without_closures; use rustc_middle::hir::nested_filter; @@ -1313,7 +1313,7 @@ pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext< /// Returns `true` if `expr` contains a return expression pub fn contains_return<'tcx>(expr: impl Visitable<'tcx>) -> bool { - for_each_expr(expr, |e| { + for_each_expr_without_closures(expr, |e| { if matches!(e.kind, ExprKind::Ret(..)) { ControlFlow::Break(()) } else { diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 8daab9b0d92..455239cc37f 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,6 +1,6 @@ #![allow(clippy::similar_names)] // `expr` and `expn` -use crate::visitors::{for_each_expr, Descend}; +use crate::visitors::{for_each_expr_without_closures, Descend}; use arrayvec::ArrayVec; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; @@ -323,7 +323,7 @@ fn find_assert_args_inner<'a, const N: usize>( Some(inner_name) => find_assert_within_debug_assert(cx, expr, expn, Symbol::intern(inner_name))?, }; let mut args = ArrayVec::new(); - let panic_expn = for_each_expr(expr, |e| { + let panic_expn = for_each_expr_without_closures(expr, |e| { if args.is_full() { match PanicExpn::parse(e) { Some(expn) => ControlFlow::Break(expn), @@ -349,7 +349,7 @@ fn find_assert_within_debug_assert<'a>( expn: ExpnId, assert_name: Symbol, ) -> Option<(&'a Expr<'a>, ExpnId)> { - for_each_expr(expr, |e| { + for_each_expr_without_closures(expr, |e| { if !e.span.from_expansion() { return ControlFlow::Continue(Descend::No); } @@ -397,7 +397,7 @@ impl FormatArgsStorage { /// /// See also [`find_format_arg_expr`] pub fn get(&self, cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option<&FormatArgs> { - let format_args_expr = for_each_expr(start, |expr| { + let format_args_expr = for_each_expr_without_closures(start, |expr| { let ctxt = expr.span.ctxt(); if ctxt.outer_expn().is_descendant_of(expn_id) { if macro_backtrace(expr.span) @@ -439,7 +439,7 @@ pub fn find_format_arg_expr<'hir, 'ast>( parent: _, } = target.expr.span.data(); - for_each_expr(start, |expr| { + for_each_expr_without_closures(start, |expr| { // When incremental compilation is enabled spans gain a parent during AST to HIR lowering, // since we're comparing an AST span to a HIR one we need to ignore the parent field let data = expr.span.data(); diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs index 88837d8a143..991ea428dc3 100644 --- a/clippy_utils/src/ptr.rs +++ b/clippy_utils/src/ptr.rs @@ -1,5 +1,5 @@ use crate::source::snippet; -use crate::visitors::{for_each_expr, Descend}; +use crate::visitors::{for_each_expr_without_closures, Descend}; use crate::{path_to_local_id, strip_pat_refs}; use core::ops::ControlFlow; use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind}; @@ -31,7 +31,7 @@ fn extract_clone_suggestions<'tcx>( body: &'tcx Body<'_>, ) -> Option)>> { let mut spans = Vec::new(); - for_each_expr(body, |e| { + for_each_expr_without_closures(body, |e| { if let ExprKind::MethodCall(seg, recv, [], _) = e.kind && path_to_local_id(recv, id) { diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index 2a25d51d8e5..fbf3d95365a 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -1,4 +1,4 @@ -use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend, Visitable}; +use crate::visitors::{for_each_expr, for_each_expr_without_closures, Descend, Visitable}; use crate::{self as utils, get_enclosing_loop_or_multi_call_closure}; use core::ops::ControlFlow; use hir::def::Res; @@ -145,7 +145,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { } pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { - for_each_expr(expression, |e| { + for_each_expr_without_closures(expression, |e| { match e.kind { ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => ControlFlow::Break(()), // Something special could be done here to handle while or for loop @@ -159,7 +159,7 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { } pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visitable<'tcx>) -> bool { - for_each_expr_with_closures(cx, v, |e| { + for_each_expr(cx, v, |e| { if utils::path_to_local_id(e, local_id) { ControlFlow::Break(()) } else { @@ -184,7 +184,7 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr let loop_start = get_enclosing_loop_or_multi_call_closure(cx, after).map(|e| e.hir_id); let mut past_expr = false; - for_each_expr_with_closures(cx, block, |e| { + for_each_expr(cx, block, |e| { if past_expr { if utils::path_to_local_id(e, local_id) { ControlFlow::Break(()) diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index a3f3b32ed37..00a97822e49 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -100,7 +100,7 @@ visitable_ref!(Stmt, visit_stmt); /// Calls the given function once for each expression contained. This does not enter any bodies or /// nested items. -pub fn for_each_expr<'tcx, B, C: Continue>( +pub fn for_each_expr_without_closures<'tcx, B, C: Continue>( node: impl Visitable<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, ) -> Option { @@ -134,7 +134,7 @@ pub fn for_each_expr<'tcx, B, C: Continue>( /// Calls the given function once for each expression contained. This will enter bodies, but not /// nested items. -pub fn for_each_expr_with_closures<'tcx, B, C: Continue>( +pub fn for_each_expr<'tcx, B, C: Continue>( cx: &LateContext<'tcx>, node: impl Visitable<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, @@ -181,7 +181,7 @@ pub fn for_each_expr_with_closures<'tcx, B, C: Continue>( /// returns `true` if expr contains match expr desugared from try fn contains_try(expr: &Expr<'_>) -> bool { - for_each_expr(expr, |e| { + for_each_expr_without_closures(expr, |e| { if matches!(e.kind, ExprKind::Match(_, _, hir::MatchSource::TryDesugar(_))) { ControlFlow::Break(()) } else { @@ -286,7 +286,7 @@ where /// Checks if the given resolved path is used in the given body. pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { - for_each_expr_with_closures(cx, cx.tcx.hir().body(body).value, |e| { + for_each_expr(cx, cx.tcx.hir().body(body).value, |e| { if let ExprKind::Path(p) = &e.kind { if cx.qpath_res(p, e.hir_id) == res { return ControlFlow::Break(()); @@ -299,7 +299,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { /// Checks if the given local is used. pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool { - for_each_expr_with_closures(cx, visitable, |e| { + for_each_expr(cx, visitable, |e| { if path_to_local_id(e, id) { ControlFlow::Break(()) } else { @@ -757,7 +757,7 @@ pub fn for_each_local_assignment<'tcx, B>( } pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool { - for_each_expr(expr, |e| { + for_each_expr_without_closures(expr, |e| { if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) { ControlFlow::Break(()) } else { @@ -776,7 +776,7 @@ pub fn local_used_once<'tcx>( ) -> Option<&'tcx Expr<'tcx>> { let mut expr = None; - let cf = for_each_expr_with_closures(cx, visitable, |e| { + let cf = for_each_expr(cx, visitable, |e| { if path_to_local_id(e, id) && expr.replace(e).is_some() { ControlFlow::Break(()) } else { -- cgit 1.4.1-3-g733a5 From 68e7356b7eb2037295aa81332b15e184c0974b5e Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sun, 19 May 2024 15:08:36 +0000 Subject: Switch to `for_each_expr` in some lints --- clippy_lints/src/missing_fields_in_debug.rs | 6 +++--- clippy_lints/src/panic_in_result_fn.rs | 4 ++-- clippy_lints/src/unwrap_in_result.rs | 4 ++-- tests/ui/missing_fields_in_debug.rs | 18 ++++++++++++++++++ tests/ui/missing_fields_in_debug.stderr | 16 ++++++++-------- tests/ui/panic_in_result_fn.rs | 5 +++++ tests/ui/panic_in_result_fn.stderr | 18 +++++++++++++++++- tests/ui/unwrap_in_result.rs | 5 +++++ tests/ui/unwrap_in_result.stderr | 18 +++++++++++++++++- 9 files changed, 77 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 10f6cb7c0d3..77595b121aa 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_path_lang_item; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{for_each_expr_without_closures, Visitable}; +use clippy_utils::visitors::{for_each_expr, Visitable}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; @@ -110,7 +110,7 @@ fn should_lint<'tcx>( // Is there a call to `DebugStruct::debug_struct`? Do lint if there is. let mut has_debug_struct = false; - for_each_expr_without_closures(block, |expr| { + for_each_expr(cx, block, |expr| { if let ExprKind::MethodCall(path, recv, ..) = &expr.kind { let recv_ty = typeck_results.expr_ty(recv).peel_refs(); @@ -165,7 +165,7 @@ fn check_struct<'tcx>( let mut has_direct_field_access = false; let mut field_accesses = FxHashSet::default(); - for_each_expr_without_closures(block, |expr| { + for_each_expr(cx, block, |expr| { if let ExprKind::Field(target, ident) = expr.kind && let target_ty = typeck_results.expr_ty_adjusted(target).peel_refs() && target_ty == self_ty diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 6d43143abab..4cf238f71bc 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::return_ty; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; +use clippy_utils::visitors::{for_each_expr, Descend}; use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) { let mut panics = Vec::new(); - let _: Option = for_each_expr_without_closures(body.value, |e| { + let _: Option = for_each_expr(cx, body.value, |e| { let Some(macro_call) = root_macro_call_first_node(cx, e) else { return ControlFlow::Continue(Descend::Yes); }; diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index a4142a30ea4..cb0364c1bc0 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::for_each_expr_without_closures; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{method_chain_args, return_ty}; use core::ops::ControlFlow; use rustc_hir as hir; @@ -75,7 +75,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc let body = cx.tcx.hir().body(body_id); let typeck = cx.tcx.typeck(impl_item.owner_id.def_id); let mut result = Vec::new(); - let _: Option = for_each_expr_without_closures(body.value, |e| { + let _: Option = for_each_expr(cx, body.value, |e| { // check for `expect` if let Some(arglists) = method_chain_args(e, &["expect"]) { let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); diff --git a/tests/ui/missing_fields_in_debug.rs b/tests/ui/missing_fields_in_debug.rs index e91e8ab7f47..68867ec819d 100644 --- a/tests/ui/missing_fields_in_debug.rs +++ b/tests/ui/missing_fields_in_debug.rs @@ -4,6 +4,7 @@ use std::fmt; use std::marker::PhantomData; use std::ops::Deref; +use std::thread::LocalKey; struct NamedStruct1Ignored { data: u8, @@ -191,4 +192,21 @@ impl fmt::Debug for WithPD { } } +struct InClosure { + a: u8, + b: String, +} + +impl fmt::Debug for InClosure { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut d = f.debug_struct("InClosure"); + d.field("a", &self.a); + let mut c = || { + d.field("b", &self.b); + }; + c(); + d.finish() + } +} + fn main() {} diff --git a/tests/ui/missing_fields_in_debug.stderr b/tests/ui/missing_fields_in_debug.stderr index 6f8a9abe922..8c1810909dd 100644 --- a/tests/ui/missing_fields_in_debug.stderr +++ b/tests/ui/missing_fields_in_debug.stderr @@ -1,5 +1,5 @@ error: manual `Debug` impl does not include all fields - --> tests/ui/missing_fields_in_debug.rs:13:1 + --> tests/ui/missing_fields_in_debug.rs:14:1 | LL | / impl fmt::Debug for NamedStruct1Ignored { LL | | @@ -11,7 +11,7 @@ LL | | } | |_^ | note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:10:5 + --> tests/ui/missing_fields_in_debug.rs:11:5 | LL | hidden: u32, | ^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | hidden: u32, = help: to override `-D warnings` add `#[allow(clippy::missing_fields_in_debug)]` error: manual `Debug` impl does not include all fields - --> tests/ui/missing_fields_in_debug.rs:32:1 + --> tests/ui/missing_fields_in_debug.rs:33:1 | LL | / impl fmt::Debug for NamedStructMultipleIgnored { LL | | @@ -33,17 +33,17 @@ LL | | } | |_^ | note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:26:5 + --> tests/ui/missing_fields_in_debug.rs:27:5 | LL | hidden: u32, | ^^^^^^^^^^^ note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:27:5 + --> tests/ui/missing_fields_in_debug.rs:28:5 | LL | hidden2: String, | ^^^^^^^^^^^^^^^ note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:29:5 + --> tests/ui/missing_fields_in_debug.rs:30:5 | LL | hidden4: ((((u8), u16), u32), u64), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -51,7 +51,7 @@ LL | hidden4: ((((u8), u16), u32), u64), = help: consider calling `.finish_non_exhaustive()` if you intend to ignore fields error: manual `Debug` impl does not include all fields - --> tests/ui/missing_fields_in_debug.rs:94:1 + --> tests/ui/missing_fields_in_debug.rs:95:1 | LL | / impl fmt::Debug for MultiExprDebugImpl { LL | | @@ -63,7 +63,7 @@ LL | | } | |_^ | note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:90:5 + --> tests/ui/missing_fields_in_debug.rs:91:5 | LL | b: String, | ^^^^^^^^^ diff --git a/tests/ui/panic_in_result_fn.rs b/tests/ui/panic_in_result_fn.rs index 41e2f522689..aaaf9a109ac 100644 --- a/tests/ui/panic_in_result_fn.rs +++ b/tests/ui/panic_in_result_fn.rs @@ -56,6 +56,11 @@ fn function_result_with_panic() -> Result // should emit lint panic!("error"); } +fn in_closure() -> Result { + let c = || panic!(); + c() +} + fn todo() { println!("something"); } diff --git a/tests/ui/panic_in_result_fn.stderr b/tests/ui/panic_in_result_fn.stderr index cd2234bdfb1..2d49b5ab1b8 100644 --- a/tests/ui/panic_in_result_fn.stderr +++ b/tests/ui/panic_in_result_fn.stderr @@ -34,5 +34,21 @@ note: return Err() instead of panicking LL | panic!("error"); | ^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: used `panic!()` or assertion in a function that returns `Result` + --> tests/ui/panic_in_result_fn.rs:59:1 + | +LL | / fn in_closure() -> Result { +LL | | let c = || panic!(); +LL | | c() +LL | | } + | |_^ + | + = help: `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing +note: return Err() instead of panicking + --> tests/ui/panic_in_result_fn.rs:60:16 + | +LL | let c = || panic!(); + | ^^^^^^^^ + +error: aborting due to 3 previous errors diff --git a/tests/ui/unwrap_in_result.rs b/tests/ui/unwrap_in_result.rs index a19db46c667..62c6d959c84 100644 --- a/tests/ui/unwrap_in_result.rs +++ b/tests/ui/unwrap_in_result.rs @@ -38,6 +38,11 @@ impl A { } None } + + fn in_closure(a: Option) -> Option { + let c = || a.unwrap(); + Some(c()) + } } fn main() { diff --git a/tests/ui/unwrap_in_result.stderr b/tests/ui/unwrap_in_result.stderr index 29c7a9373aa..752177aaca5 100644 --- a/tests/ui/unwrap_in_result.stderr +++ b/tests/ui/unwrap_in_result.stderr @@ -38,5 +38,21 @@ note: potential non-recoverable error(s) LL | let i = i_str.parse::().expect("not a number"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: used unwrap or expect in a function that returns result or option + --> tests/ui/unwrap_in_result.rs:42:5 + | +LL | / fn in_closure(a: Option) -> Option { +LL | | let c = || a.unwrap(); +LL | | Some(c()) +LL | | } + | |_____^ + | + = help: unwrap and expect should not be used in a function that returns result or option +note: potential non-recoverable error(s) + --> tests/ui/unwrap_in_result.rs:43:20 + | +LL | let c = || a.unwrap(); + | ^^^^^^^^^^ + +error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From 9e5523e8c48d4c5ae6d662180c884bc771df8ee9 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Mon, 20 May 2024 17:57:40 +0000 Subject: lint_groups_priority: ignore lints & groups at the same level --- clippy_lints/src/cargo/lint_groups_priority.rs | 60 ++++++++++------------ .../lint_groups_priority/fail/Cargo.stderr | 49 +++++++++--------- .../ui-cargo/lint_groups_priority/fail/Cargo.toml | 4 -- .../ui-cargo/lint_groups_priority/pass/Cargo.toml | 7 +++ 4 files changed, 60 insertions(+), 60 deletions(-) diff --git a/clippy_lints/src/cargo/lint_groups_priority.rs b/clippy_lints/src/cargo/lint_groups_priority.rs index 0d9eaac882f..e924542fea2 100644 --- a/clippy_lints/src/cargo/lint_groups_priority.rs +++ b/clippy_lints/src/cargo/lint_groups_priority.rs @@ -71,12 +71,6 @@ struct CargoToml { workspace: Workspace, } -#[derive(Default, Debug)] -struct LintsAndGroups { - lints: Vec>, - groups: Vec<(Spanned, Spanned)>, -} - fn toml_span(range: Range, file: &SourceFile) -> Span { Span::new( file.start_pos + BytePos::from_usize(range.start), @@ -86,27 +80,28 @@ fn toml_span(range: Range, file: &SourceFile) -> Span { ) } -fn check_table(cx: &LateContext<'_>, table: LintTable, groups: &FxHashSet<&str>, file: &SourceFile) { - let mut by_priority = BTreeMap::<_, LintsAndGroups>::new(); +fn check_table(cx: &LateContext<'_>, table: LintTable, known_groups: &FxHashSet<&str>, file: &SourceFile) { + let mut lints = Vec::new(); + let mut groups = Vec::new(); for (name, config) in table { - let lints_and_groups = by_priority.entry(config.as_ref().priority()).or_default(); - if groups.contains(name.get_ref().as_str()) { - lints_and_groups.groups.push((name, config)); + if name.get_ref() == "warnings" { + continue; + } + + if known_groups.contains(name.get_ref().as_str()) { + groups.push((name, config)); } else { - lints_and_groups.lints.push(name); + lints.push((name, config.into_inner())); } } - let low_priority = by_priority - .iter() - .find(|(_, lints_and_groups)| !lints_and_groups.lints.is_empty()) - .map_or(-1, |(&lowest_lint_priority, _)| lowest_lint_priority - 1); - for (priority, LintsAndGroups { lints, groups }) in by_priority { - let Some(last_lint_alphabetically) = lints.last() else { - continue; - }; - - for (group, config) in groups { + for (group, group_config) in groups { + let priority = group_config.get_ref().priority(); + let level = group_config.get_ref().level(); + if let Some((conflict, _)) = lints + .iter() + .rfind(|(_, lint_config)| lint_config.priority() == priority && lint_config.level() != level) + { span_lint_and_then( cx, LINT_GROUPS_PRIORITY, @@ -116,22 +111,23 @@ fn check_table(cx: &LateContext<'_>, table: LintTable, groups: &FxHashSet<&str>, group.as_ref() ), |diag| { - let config_span = toml_span(config.span(), file); - if config.as_ref().is_implicit() { + let config_span = toml_span(group_config.span(), file); + + if group_config.as_ref().is_implicit() { diag.span_label(config_span, "has an implicit priority of 0"); } - // add the label to next lint after this group that has the same priority - let lint = lints - .iter() - .filter(|lint| lint.span().start > group.span().start) - .min_by_key(|lint| lint.span().start) - .unwrap_or(last_lint_alphabetically); - diag.span_label(toml_span(lint.span(), file), "has the same priority as this lint"); + diag.span_label(toml_span(conflict.span(), file), "has the same priority as this lint"); diag.note("the order of the lints in the table is ignored by Cargo"); + let mut suggestion = String::new(); + let low_priority = lints + .iter() + .map(|(_, config)| config.priority().saturating_sub(1)) + .min() + .unwrap_or(-1); Serialize::serialize( &LintConfigTable { - level: config.as_ref().level().into(), + level: level.into(), priority: Some(low_priority), }, toml::ser::ValueSerializer::new(&mut suggestion), diff --git a/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr b/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr index 9177e99f8e6..4fe7f6f7a9e 100644 --- a/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr +++ b/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr @@ -1,17 +1,18 @@ error: lint group `rust_2018_idioms` has the same priority (0) as a lint - --> Cargo.toml:7:1 - | -7 | rust_2018_idioms = "warn" - | ^^^^^^^^^^^^^^^^ ------ has an implicit priority of 0 -8 | bare_trait_objects = "allow" - | ------------------ has the same priority as this lint - | - = note: the order of the lints in the table is ignored by Cargo - = note: `#[deny(clippy::lint_groups_priority)]` on by default + --> Cargo.toml:7:1 + | +7 | rust_2018_idioms = "warn" + | ^^^^^^^^^^^^^^^^ ------ has an implicit priority of 0 +... +12 | unused_attributes = { level = "allow" } + | ----------------- has the same priority as this lint + | + = note: the order of the lints in the table is ignored by Cargo + = note: `#[deny(clippy::lint_groups_priority)]` on by default help: to have lints override the group set `rust_2018_idioms` to a lower priority - | -7 | rust_2018_idioms = { level = "warn", priority = -1 } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | +7 | rust_2018_idioms = { level = "warn", priority = -1 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: lint group `unused` has the same priority (0) as a lint --> Cargo.toml:10:1 @@ -29,45 +30,45 @@ help: to have lints override the group set `unused` to a lower priority | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: lint group `pedantic` has the same priority (-1) as a lint - --> Cargo.toml:19:1 + --> Cargo.toml:15:1 | -19 | pedantic = { level = "warn", priority = -1 } +15 | pedantic = { level = "warn", priority = -1 } | ^^^^^^^^ -20 | similar_names = { level = "allow", priority = -1 } +16 | similar_names = { level = "allow", priority = -1 } | ------------- has the same priority as this lint | = note: the order of the lints in the table is ignored by Cargo help: to have lints override the group set `pedantic` to a lower priority | -19 | pedantic = { level = "warn", priority = -2 } +15 | pedantic = { level = "warn", priority = -2 } | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: lint group `rust_2018_idioms` has the same priority (0) as a lint - --> Cargo.toml:23:1 + --> Cargo.toml:19:1 | -23 | rust_2018_idioms = "warn" +19 | rust_2018_idioms = "warn" | ^^^^^^^^^^^^^^^^ ------ has an implicit priority of 0 -24 | bare_trait_objects = "allow" +20 | bare_trait_objects = "allow" | ------------------ has the same priority as this lint | = note: the order of the lints in the table is ignored by Cargo help: to have lints override the group set `rust_2018_idioms` to a lower priority | -23 | rust_2018_idioms = { level = "warn", priority = -1 } +19 | rust_2018_idioms = { level = "warn", priority = -1 } | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: lint group `pedantic` has the same priority (0) as a lint - --> Cargo.toml:27:1 + --> Cargo.toml:23:1 | -27 | pedantic = "warn" +23 | pedantic = "warn" | ^^^^^^^^ ------ has an implicit priority of 0 -28 | similar_names = "allow" +24 | similar_names = "allow" | ------------- has the same priority as this lint | = note: the order of the lints in the table is ignored by Cargo help: to have lints override the group set `pedantic` to a lower priority | -27 | pedantic = { level = "warn", priority = -1 } +23 | pedantic = { level = "warn", priority = -1 } | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: could not compile `fail` (lib) due to 5 previous errors diff --git a/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml b/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml index e4d4af9cd23..c87662f822e 100644 --- a/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml +++ b/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml @@ -11,10 +11,6 @@ unused = { level = "deny" } unused_braces = { level = "allow", priority = 1 } unused_attributes = { level = "allow" } -# `warnings` is not a group so the order it is passed does not matter -warnings = "deny" -deprecated = "allow" - [lints.clippy] pedantic = { level = "warn", priority = -1 } similar_names = { level = "allow", priority = -1 } diff --git a/tests/ui-cargo/lint_groups_priority/pass/Cargo.toml b/tests/ui-cargo/lint_groups_priority/pass/Cargo.toml index e9fcf803d93..979c915cf0c 100644 --- a/tests/ui-cargo/lint_groups_priority/pass/Cargo.toml +++ b/tests/ui-cargo/lint_groups_priority/pass/Cargo.toml @@ -3,6 +3,13 @@ name = "pass" version = "0.1.0" publish = false +[lints.rust] +# Warnings does not conflict with any group or lint +warnings = "deny" +# Groups & lints at the same level do not conflict +rust_2018_idioms = "warn" +unsafe_code = "warn" + [lints.clippy] pedantic = { level = "warn", priority = -1 } style = { level = "warn", priority = 1 } -- cgit 1.4.1-3-g733a5 From 6add5c99cd1aed9b4c816613770da89470918d7b Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Tue, 14 May 2024 11:40:19 +0200 Subject: Document behavior of `create_dir_all` wrt. empty path The behavior makes sense because `Path::new("one_component").parent() == Some(Path::new(""))`, so if one naively wants to create the parent directory for a file to be written, it simply works. Closes #105108 by documenting the current behavior. --- library/std/src/fs.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 77e94365b08..5d78b9611a0 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2310,6 +2310,9 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// If this function returns an error, some of the parent components might have /// been created already. /// +/// If the empty path is passed to this function, it always succeeds without +/// creating any directories. +/// /// # Platform-specific behavior /// /// This function currently corresponds to multiple calls to the `mkdir` -- cgit 1.4.1-3-g733a5 From 95b295d9768fc492540d415c34c7f59b265967c1 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 24 May 2024 19:27:39 +0000 Subject: Fix `to_string_in_format_args` with macro call receiver --- clippy_lints/src/format_args.rs | 4 ++-- tests/ui/format_args.fixed | 1 + tests/ui/format_args.rs | 1 + tests/ui/format_args.stderr | 16 +++++++++++----- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 86115807aa4..99def199af0 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -424,14 +424,14 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter()) && implements_trait(cx, target, display_trait_id, &[]) && let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait() - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + && let Some(receiver_snippet) = snippet_opt(cx, receiver.span.source_callsite()) { let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); if n_needed_derefs == 0 && !needs_ref { span_lint_and_sugg( cx, TO_STRING_IN_FORMAT_ARGS, - to_string_span.with_lo(receiver.span.hi()), + to_string_span.with_lo(receiver.span.source_callsite().hi()), format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), "remove this", String::new(), diff --git a/tests/ui/format_args.fixed b/tests/ui/format_args.fixed index cab20b11e07..4d812f6bf1d 100644 --- a/tests/ui/format_args.fixed +++ b/tests/ui/format_args.fixed @@ -104,6 +104,7 @@ fn main() { println!("{foo}{bar}", foo = "foo", bar = "bar"); println!("{foo}{bar}", bar = "bar", foo = "foo"); println!("{foo}{bar}", bar = "bar", foo = "foo"); + println!("{}", my_other_macro!()); // negative tests println!("error: something failed at {}", Somewhere.to_string()); diff --git a/tests/ui/format_args.rs b/tests/ui/format_args.rs index bc3645cb2c2..d242623feb6 100644 --- a/tests/ui/format_args.rs +++ b/tests/ui/format_args.rs @@ -104,6 +104,7 @@ fn main() { println!("{foo}{bar}", foo = "foo", bar = "bar".to_string()); println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo"); println!("{foo}{bar}", bar = "bar", foo = "foo".to_string()); + println!("{}", my_other_macro!().to_string()); // negative tests println!("error: something failed at {}", Somewhere.to_string()); diff --git a/tests/ui/format_args.stderr b/tests/ui/format_args.stderr index f20cf9eca2f..91a45e27008 100644 --- a/tests/ui/format_args.stderr +++ b/tests/ui/format_args.stderr @@ -127,29 +127,35 @@ error: `to_string` applied to a type that implements `Display` in `println!` arg LL | println!("{foo}{bar}", bar = "bar", foo = "foo".to_string()); | ^^^^^^^^^^^^ help: remove this +error: `to_string` applied to a type that implements `Display` in `println!` args + --> tests/ui/format_args.rs:107:37 + | +LL | println!("{}", my_other_macro!().to_string()); + | ^^^^^^^^^^^^ help: remove this + error: `to_string` applied to a type that implements `Display` in `print!` args - --> tests/ui/format_args.rs:118:37 + --> tests/ui/format_args.rs:119:37 | LL | print!("{}", (Location::caller().to_string())); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `print!` args - --> tests/ui/format_args.rs:119:39 + --> tests/ui/format_args.rs:120:39 | LL | print!("{}", ((Location::caller()).to_string())); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `format!` args - --> tests/ui/format_args.rs:147:38 + --> tests/ui/format_args.rs:148:38 | LL | let x = format!("{} {}", a, b.to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:161:24 + --> tests/ui/format_args.rs:162:24 | LL | println!("{}", original[..10].to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use this: `&original[..10]` -error: aborting due to 25 previous errors +error: aborting due to 26 previous errors -- cgit 1.4.1-3-g733a5 From 93a77f2812ae80fda57003a6877d09de7793541e Mon Sep 17 00:00:00 2001 From: cookie-s Date: Fri, 24 May 2024 20:27:12 -0400 Subject: [`nonminimal_bool`]: Deduplicate diagnostics --- clippy_lints/src/booleans.rs | 2 -- tests/ui/nonminimal_bool_methods.fixed | 2 -- tests/ui/nonminimal_bool_methods.rs | 2 -- tests/ui/nonminimal_bool_methods.stderr | 32 ++++++++++++++++---------------- 4 files changed, 16 insertions(+), 22 deletions(-) diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index b6341b3fe8e..61e90167d81 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -609,7 +609,5 @@ impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { Applicability::MachineApplicable, ); } - - walk_expr(self, expr); } } diff --git a/tests/ui/nonminimal_bool_methods.fixed b/tests/ui/nonminimal_bool_methods.fixed index aba599678e3..cc91ba6ec66 100644 --- a/tests/ui/nonminimal_bool_methods.fixed +++ b/tests/ui/nonminimal_bool_methods.fixed @@ -1,5 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #![allow(unused, clippy::diverging_sub_expression, clippy::needless_if)] #![warn(clippy::nonminimal_bool)] diff --git a/tests/ui/nonminimal_bool_methods.rs b/tests/ui/nonminimal_bool_methods.rs index 35f22db1d36..c812f6f0ca4 100644 --- a/tests/ui/nonminimal_bool_methods.rs +++ b/tests/ui/nonminimal_bool_methods.rs @@ -1,5 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #![allow(unused, clippy::diverging_sub_expression, clippy::needless_if)] #![warn(clippy::nonminimal_bool)] diff --git a/tests/ui/nonminimal_bool_methods.stderr b/tests/ui/nonminimal_bool_methods.stderr index 18da4e0d380..d7adc0638b3 100644 --- a/tests/ui/nonminimal_bool_methods.stderr +++ b/tests/ui/nonminimal_bool_methods.stderr @@ -1,5 +1,5 @@ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:10:13 + --> tests/ui/nonminimal_bool_methods.rs:8:13 | LL | let _ = !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` @@ -8,91 +8,91 @@ LL | let _ = !a.is_some(); = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:12:13 + --> tests/ui/nonminimal_bool_methods.rs:10:13 | LL | let _ = !a.is_none(); | ^^^^^^^^^^^^ help: try: `a.is_some()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:14:13 + --> tests/ui/nonminimal_bool_methods.rs:12:13 | LL | let _ = !b.is_err(); | ^^^^^^^^^^^ help: try: `b.is_ok()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:16:13 + --> tests/ui/nonminimal_bool_methods.rs:14:13 | LL | let _ = !b.is_ok(); | ^^^^^^^^^^ help: try: `b.is_err()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:18:13 + --> tests/ui/nonminimal_bool_methods.rs:16:13 | LL | let _ = !(a.is_some() && !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() || c` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:19:13 + --> tests/ui/nonminimal_bool_methods.rs:17:13 | LL | let _ = !(a.is_some() || !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() && c` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:20:26 + --> tests/ui/nonminimal_bool_methods.rs:18:26 | LL | let _ = !(!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:21:25 + --> tests/ui/nonminimal_bool_methods.rs:19:25 | LL | let _ = (!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:22:23 + --> tests/ui/nonminimal_bool_methods.rs:20:23 | LL | let _ = !c ^ c || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:94:8 + --> tests/ui/nonminimal_bool_methods.rs:92:8 | LL | if !res.is_ok() {} | ^^^^^^^^^^^^ help: try: `res.is_err()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:95:8 + --> tests/ui/nonminimal_bool_methods.rs:93:8 | LL | if !res.is_err() {} | ^^^^^^^^^^^^^ help: try: `res.is_ok()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:98:8 + --> tests/ui/nonminimal_bool_methods.rs:96:8 | LL | if !res.is_some() {} | ^^^^^^^^^^^^^^ help: try: `res.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:99:8 + --> tests/ui/nonminimal_bool_methods.rs:97:8 | LL | if !res.is_none() {} | ^^^^^^^^^^^^^^ help: try: `res.is_some()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:115:8 + --> tests/ui/nonminimal_bool_methods.rs:113:8 | LL | if !(a as u64 >= b) {} | ^^^^^^^^^^^^^^^^ help: try: `(a as u64) < b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:116:8 + --> tests/ui/nonminimal_bool_methods.rs:114:8 | LL | if !((a as u64) >= b) {} | ^^^^^^^^^^^^^^^^^^ help: try: `(a as u64) < b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:117:8 + --> tests/ui/nonminimal_bool_methods.rs:115:8 | LL | if !(a as u64 <= b) {} | ^^^^^^^^^^^^^^^^ help: try: `a as u64 > b` -- cgit 1.4.1-3-g733a5 From b6350e94f7cf3f16caaf163e5406fd77c1cbd070 Mon Sep 17 00:00:00 2001 From: cookie-s Date: Fri, 24 May 2024 20:34:29 -0400 Subject: [`nonminimal_bool`]: Remove NotSimplificationVisitor --- clippy_lints/src/booleans.rs | 47 +++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 61e90167d81..b52d8f454ae 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -174,6 +174,25 @@ fn check_inverted_bool_in_condition( ); } +fn check_simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind + && !expr.span.from_expansion() + && !inner.span.from_expansion() + && let Some(suggestion) = simplify_not(cx, inner) + && cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow + { + span_lint_and_sugg( + cx, + NONMINIMAL_BOOL, + expr.span, + "this boolean expression can be simplified", + "try", + suggestion, + Applicability::MachineApplicable, + ); + } +} + struct NonminimalBoolVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, } @@ -542,8 +561,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } }; if improvements.is_empty() { - let mut visitor = NotSimplificationVisitor { cx: self.cx }; - visitor.visit_expr(e); + check_simplify_not(self.cx, e); } else { nonminimal_bool_lint( improvements @@ -586,28 +604,3 @@ fn implements_ord(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { .get_diagnostic_item(sym::Ord) .map_or(false, |id| implements_trait(cx, ty, id, &[])) } - -struct NotSimplificationVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, -} - -impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind - && !expr.span.from_expansion() - && !inner.span.from_expansion() - && let Some(suggestion) = simplify_not(self.cx, inner) - && self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow - { - span_lint_and_sugg( - self.cx, - NONMINIMAL_BOOL, - expr.span, - "this boolean expression can be simplified", - "try", - suggestion, - Applicability::MachineApplicable, - ); - } - } -} -- cgit 1.4.1-3-g733a5 From 417460027e544b7f034c4d79678b5088279eeb7b Mon Sep 17 00:00:00 2001 From: bohan Date: Wed, 8 May 2024 20:24:18 +0800 Subject: place explicit lifetime bound after generic param --- .../rustc_infer/src/infer/error_reporting/mod.rs | 18 +++- .../static-lifetime-tip-with-default-type.rs | 26 +++++ .../static-lifetime-tip-with-default-type.stderr | 110 +++++++++++++++++++++ 3 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.rs create mode 100644 tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e0894ed31bf..f7ca55ccc55 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -63,11 +63,11 @@ use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxt, DiagStyledString, ErrorGuaranteed, IntoDiagArg, StringPart, }; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; +use rustc_hir::{self as hir, ParamName}; use rustc_macros::extension; use rustc_middle::bug; use rustc_middle::dep_graph::DepContext; @@ -2379,7 +2379,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let (type_scope, type_param_sugg_span) = match bound_kind { GenericKind::Param(param) => { let generics = self.tcx.generics_of(generic_param_scope); - let def_id = generics.type_param(param, self.tcx).def_id.expect_local(); + let type_param = generics.type_param(param, self.tcx); + let def_id = type_param.def_id.expect_local(); let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.def_id; // Get the `hir::Param` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: 'a'b`, @@ -2389,7 +2390,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)), // If `param` corresponds to `Self`, no usable suggestion span. None if generics.has_self && param.index == 0 => None, - None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false, None)), + None => { + let span = if let Some(param) = + hir_generics.params.iter().find(|param| param.def_id == def_id) + && let ParamName::Plain(ident) = param.name + { + ident.span.shrink_to_hi() + } else { + let span = self.tcx.def_span(def_id); + span.shrink_to_hi() + }; + Some((span, false, None)) + } }; (scope, sugg_span) } diff --git a/tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.rs b/tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.rs new file mode 100644 index 00000000000..68879a0af29 --- /dev/null +++ b/tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.rs @@ -0,0 +1,26 @@ +//@ error-pattern: r#T: 'static +//@ error-pattern: r#K: 'static +//@ error-pattern: T: 'static= + +// https://github.com/rust-lang/rust/issues/124785 + +struct Foo(&'static T, &'static K); +//~^ ERROR: the parameter type `T` may not live long enough +//~| ERROR: the parameter type `K` may not live long enough + +struct Bar(&'static r#T, &'static r#K); +//~^ ERROR: the parameter type `T` may not live long enough +//~| ERROR: the parameter type `K` may not live long enough + +struct Boo(&'static T); +//~^ ERROR: the parameter type `T` may not live long enough + +struct Far(&'static T); +//~^ ERROR: the parameter type `T` may not live long enough + +struct S<'a, K: 'a = i32>(&'static K); +//~^ ERROR: lifetime parameter `'a` is never used +//~| ERROR: the parameter type `K` may not live long enough + +fn main() {} diff --git a/tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.stderr b/tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.stderr new file mode 100644 index 00000000000..7d985a9013f --- /dev/null +++ b/tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.stderr @@ -0,0 +1,110 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/static-lifetime-tip-with-default-type.rs:7:24 + | +LL | struct Foo(&'static T, &'static K); + | ^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the reference type `&'static T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct Foo(&'static T, &'static K); + | +++++++++ + +error[E0310]: the parameter type `K` may not live long enough + --> $DIR/static-lifetime-tip-with-default-type.rs:7:36 + | +LL | struct Foo(&'static T, &'static K); + | ^^^^^^^^^^ + | | + | the parameter type `K` must be valid for the static lifetime... + | ...so that the reference type `&'static K` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct Foo(&'static T, &'static K); + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/static-lifetime-tip-with-default-type.rs:11:28 + | +LL | struct Bar(&'static r#T, &'static r#K); + | ^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the reference type `&'static T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct Bar(&'static r#T, &'static r#K); + | +++++++++ + +error[E0310]: the parameter type `K` may not live long enough + --> $DIR/static-lifetime-tip-with-default-type.rs:11:42 + | +LL | struct Bar(&'static r#T, &'static r#K); + | ^^^^^^^^^^^^ + | | + | the parameter type `K` must be valid for the static lifetime... + | ...so that the reference type `&'static K` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct Bar(&'static r#T, &'static r#K); + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/static-lifetime-tip-with-default-type.rs:15:20 + | +LL | struct Boo(&'static T); + | ^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the reference type `&'static T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct Boo(&'static T); + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/static-lifetime-tip-with-default-type.rs:19:8 + | +LL | = i32>(&'static T); + | ^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the reference type `&'static T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct Far $DIR/static-lifetime-tip-with-default-type.rs:22:27 + | +LL | struct S<'a, K: 'a = i32>(&'static K); + | ^^^^^^^^^^ + | | + | the parameter type `K` must be valid for the static lifetime... + | ...so that the reference type `&'static K` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct S<'a, K: 'a + 'static = i32>(&'static K); + | +++++++++ + +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/static-lifetime-tip-with-default-type.rs:22:10 + | +LL | struct S<'a, K: 'a = i32>(&'static K); + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0310, E0392. +For more information about an error, try `rustc --explain E0310`. -- cgit 1.4.1-3-g733a5 From c53cea90ad4727fa190d5e548f09c2ce9e963470 Mon Sep 17 00:00:00 2001 From: WeiTheShinobi Date: Sun, 26 May 2024 17:54:44 +0800 Subject: fix: let non_canonical_impls skip proc marco --- clippy_lints/src/non_canonical_impls.rs | 5 +++++ tests/ui/auxiliary/proc_macro_derive.rs | 14 ++++++++++++++ tests/ui/non_canonical_clone_impl.fixed | 5 +++++ tests/ui/non_canonical_clone_impl.rs | 5 +++++ tests/ui/non_canonical_clone_impl.stderr | 8 ++++---- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index 932d6fe54d6..bbefc74e8d2 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -128,6 +128,11 @@ impl LateLintPass<'_> for NonCanonicalImpls { let ExprKind::Block(block, ..) = body.value.kind else { return; }; + if let Some(expr) = block.expr + && expr.span.from_expansion() + { + return; + } if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl.def_id) && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy) diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index 79a95d775b1..36ec31a7873 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -169,3 +169,17 @@ pub fn derive_ignored_unit_pattern(_: TokenStream) -> TokenStream { } } } + +#[proc_macro_derive(NonCanonicalClone)] +pub fn non_canonical_clone_derive(_: TokenStream) -> TokenStream { + quote! { + struct NonCanonicalClone; + impl Clone for NonCanonicalClone { + fn clone(&self) -> Self { + let a = *self; + a + } + } + impl Copy for NonCanonicalClone {} + } +} diff --git a/tests/ui/non_canonical_clone_impl.fixed b/tests/ui/non_canonical_clone_impl.fixed index 7d1be412e54..26274fe6574 100644 --- a/tests/ui/non_canonical_clone_impl.fixed +++ b/tests/ui/non_canonical_clone_impl.fixed @@ -1,3 +1,4 @@ +//@aux-build:proc_macro_derive.rs #![allow(clippy::clone_on_copy, unused)] #![allow(clippy::assigning_clones)] #![no_main] @@ -95,3 +96,7 @@ impl Clone for Uwu { } impl Copy for Uwu {} + +// should skip proc macros, see https://github.com/rust-lang/rust-clippy/issues/12788 +#[derive(proc_macro_derive::NonCanonicalClone)] +pub struct G; diff --git a/tests/ui/non_canonical_clone_impl.rs b/tests/ui/non_canonical_clone_impl.rs index beae05efb2f..e2b278ac493 100644 --- a/tests/ui/non_canonical_clone_impl.rs +++ b/tests/ui/non_canonical_clone_impl.rs @@ -1,3 +1,4 @@ +//@aux-build:proc_macro_derive.rs #![allow(clippy::clone_on_copy, unused)] #![allow(clippy::assigning_clones)] #![no_main] @@ -105,3 +106,7 @@ impl Clone for Uwu { } impl Copy for Uwu {} + +// should skip proc macros, see https://github.com/rust-lang/rust-clippy/issues/12788 +#[derive(proc_macro_derive::NonCanonicalClone)] +pub struct G; diff --git a/tests/ui/non_canonical_clone_impl.stderr b/tests/ui/non_canonical_clone_impl.stderr index 6bfc99d988b..80258ee8c77 100644 --- a/tests/ui/non_canonical_clone_impl.stderr +++ b/tests/ui/non_canonical_clone_impl.stderr @@ -1,5 +1,5 @@ error: non-canonical implementation of `clone` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:10:29 + --> tests/ui/non_canonical_clone_impl.rs:11:29 | LL | fn clone(&self) -> Self { | _____________________________^ @@ -11,7 +11,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::non_canonical_clone_impl)]` error: unnecessary implementation of `clone_from` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:14:5 + --> tests/ui/non_canonical_clone_impl.rs:15:5 | LL | / fn clone_from(&mut self, source: &Self) { LL | | source.clone(); @@ -20,7 +20,7 @@ LL | | } | |_____^ help: remove it error: non-canonical implementation of `clone` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:81:29 + --> tests/ui/non_canonical_clone_impl.rs:82:29 | LL | fn clone(&self) -> Self { | _____________________________^ @@ -29,7 +29,7 @@ LL | | } | |_____^ help: change this to: `{ *self }` error: unnecessary implementation of `clone_from` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:85:5 + --> tests/ui/non_canonical_clone_impl.rs:86:5 | LL | / fn clone_from(&mut self, source: &Self) { LL | | source.clone(); -- cgit 1.4.1-3-g733a5 From 566dfd90082d709aa2d42b354349bfd2b4b895b2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 May 2024 18:05:46 +0200 Subject: Add `needless_character_iteration` lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 24 +++++ .../src/methods/needless_character_iteration.rs | 108 +++++++++++++++++++++ .../src/methods/unnecessary_result_map_or_else.rs | 19 +--- clippy_lints/src/methods/utils.rs | 18 +++- tests/ui/needless_character_iteration.fixed | 51 ++++++++++ tests/ui/needless_character_iteration.rs | 59 +++++++++++ tests/ui/needless_character_iteration.stderr | 67 +++++++++++++ 9 files changed, 330 insertions(+), 18 deletions(-) create mode 100644 clippy_lints/src/methods/needless_character_iteration.rs create mode 100644 tests/ui/needless_character_iteration.fixed create mode 100644 tests/ui/needless_character_iteration.rs create mode 100644 tests/ui/needless_character_iteration.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index cfff0bb50a6..9f1d0e56745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5567,6 +5567,7 @@ Released 2018-09-13 [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference [`needless_borrows_for_generic_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrows_for_generic_args +[`needless_character_iteration`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_character_iteration [`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect [`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue [`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 6850ec821e8..2e436f0f767 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -418,6 +418,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::MAP_UNWRAP_OR_INFO, crate::methods::MUT_MUTEX_LOCK_INFO, crate::methods::NAIVE_BYTECOUNT_INFO, + crate::methods::NEEDLESS_CHARACTER_ITERATION_INFO, crate::methods::NEEDLESS_COLLECT_INFO, crate::methods::NEEDLESS_OPTION_AS_DEREF_INFO, crate::methods::NEEDLESS_OPTION_TAKE_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 60666445d08..b85218d3ca2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -66,6 +66,7 @@ mod map_flatten; mod map_identity; mod map_unwrap_or; mod mut_mutex_lock; +mod needless_character_iteration; mod needless_collect; mod needless_option_as_deref; mod needless_option_take; @@ -4089,6 +4090,27 @@ declare_clippy_lint! { "is_empty() called on strings known at compile time" } +declare_clippy_lint! { + /// ### What it does + /// Checks if an iterator is used to check if a string is ascii. + /// + /// ### Why is this bad? + /// The `str` type already implements the `is_ascii` method. + /// + /// ### Example + /// ```no_run + /// "foo".chars().all(|c| c.is_ascii()); + /// ``` + /// Use instead: + /// ```no_run + /// "foo".is_ascii(); + /// ``` + #[clippy::version = "1.80.0"] + pub NEEDLESS_CHARACTER_ITERATION, + suspicious, + "is_ascii() called on a char iterator" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4254,6 +4276,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_RESULT_MAP_OR_ELSE, MANUAL_C_STR_LITERALS, UNNECESSARY_GET_THEN_CHECK, + NEEDLESS_CHARACTER_ITERATION, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4461,6 +4484,7 @@ impl Methods { }, ("all", [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); + needless_character_iteration::check(cx, expr, recv, arg); if let Some(("cloned", recv2, [], _, _)) = method_call(recv) { iter_overeager_cloned::check( cx, diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs new file mode 100644 index 00000000000..f4467af4de8 --- /dev/null +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -0,0 +1,108 @@ +use rustc_errors::Applicability; +use rustc_hir::{Closure, Expr, ExprKind, HirId, StmtKind, UnOp}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::Span; + +use super::utils::get_last_chain_binding_hir_id; +use super::NEEDLESS_CHARACTER_ITERATION; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; +use clippy_utils::{match_def_path, path_to_local_id, peel_blocks}; + +fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> { + while let ExprKind::AddrOf(_, _, e) = expr.kind { + expr = e; + } + expr +} + +fn handle_expr( + cx: &LateContext<'_>, + expr: &Expr<'_>, + first_param: HirId, + span: Span, + before_chars: Span, + revert: bool, +) { + match expr.kind { + ExprKind::MethodCall(method, receiver, [], _) => { + if method.ident.name.as_str() == "is_ascii" + && path_to_local_id(receiver, first_param) + && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() + && *char_arg_ty.kind() == ty::Char + && let Some(snippet) = snippet_opt(cx, before_chars) + { + span_lint_and_sugg( + cx, + NEEDLESS_CHARACTER_ITERATION, + span, + "checking if a string is ascii using iterators", + "try", + format!("{}{snippet}.is_ascii()", if revert { "!" } else { "" }), + Applicability::MachineApplicable, + ); + } + }, + ExprKind::Block(block, _) => { + if block.stmts.iter().any(|stmt| !matches!(stmt.kind, StmtKind::Let(_))) { + // If there is something else than let bindings, then better not emit the lint. + return; + } + if let Some(block_expr) = block.expr + // First we ensure that this is a "binding chain" (each statement is a binding + // of the previous one) and that it is a binding of the closure argument. + && let Some(last_chain_binding_id) = + get_last_chain_binding_hir_id(first_param, block.stmts) + { + handle_expr(cx, block_expr, last_chain_binding_id, span, before_chars, revert); + } + }, + ExprKind::Unary(UnOp::Not, expr) => handle_expr(cx, expr, first_param, span, before_chars, !revert), + ExprKind::Call(fn_path, [arg]) => { + if let ExprKind::Path(path) = fn_path.kind + && let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id() + && match_def_path(cx, fn_def_id, &["core", "char", "methods", "", "is_ascii"]) + && path_to_local_id(peels_expr_ref(arg), first_param) + && let Some(snippet) = snippet_opt(cx, before_chars) + { + span_lint_and_sugg( + cx, + NEEDLESS_CHARACTER_ITERATION, + span, + "checking if a string is ascii using iterators", + "try", + format!("{}{snippet}.is_ascii()", if revert { "!" } else { "" }), + Applicability::MachineApplicable, + ); + } + }, + _ => {}, + } +} + +pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>) { + if let ExprKind::Closure(&Closure { body, .. }) = closure_arg.kind + && let body = cx.tcx.hir().body(body) + && let Some(first_param) = body.params.first() + && let ExprKind::MethodCall(method, mut recv, [], _) = recv.kind + && method.ident.name.as_str() == "chars" + && let str_ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs() + && *str_ty.kind() == ty::Str + { + let expr_start = recv.span; + while let ExprKind::MethodCall(_, new_recv, _, _) = recv.kind { + recv = new_recv; + } + let body_expr = peel_blocks(body.value); + + handle_expr( + cx, + body_expr, + first_param.pat.hir_id, + recv.span.with_hi(call_expr.span.hi()), + recv.span.with_hi(expr_start.hi()), + false, + ); + } +} diff --git a/clippy_lints/src/methods/unnecessary_result_map_or_else.rs b/clippy_lints/src/methods/unnecessary_result_map_or_else.rs index cdfaa690d5f..c14a87c1534 100644 --- a/clippy_lints/src/methods/unnecessary_result_map_or_else.rs +++ b/clippy_lints/src/methods/unnecessary_result_map_or_else.rs @@ -4,10 +4,11 @@ use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath, Stmt, StmtKind}; +use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; +use super::utils::get_last_chain_binding_hir_id; use super::UNNECESSARY_RESULT_MAP_OR_ELSE; fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) { @@ -25,22 +26,6 @@ fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &E ); } -fn get_last_chain_binding_hir_id(mut hir_id: HirId, statements: &[Stmt<'_>]) -> Option { - for stmt in statements { - if let StmtKind::Let(local) = stmt.kind - && let Some(init) = local.init - && let ExprKind::Path(QPath::Resolved(_, path)) = init.kind - && let hir::def::Res::Local(local_hir_id) = path.res - && local_hir_id == hir_id - { - hir_id = local.pat.hir_id; - } else { - return None; - } - } - Some(hir_id) -} - fn handle_qpath( cx: &LateContext<'_>, expr: &Expr<'_>, diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 34d7b9acbe4..a379f477995 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -4,7 +4,7 @@ use clippy_utils::{get_parent_expr, path_to_local_id, usage}; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat}; +use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, QPath, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; @@ -171,3 +171,19 @@ impl<'cx, 'tcx> CloneOrCopyVisitor<'cx, 'tcx> { .any(|hir_id| path_to_local_id(expr, *hir_id)) } } + +pub(super) fn get_last_chain_binding_hir_id(mut hir_id: HirId, statements: &[Stmt<'_>]) -> Option { + for stmt in statements { + if let StmtKind::Let(local) = stmt.kind + && let Some(init) = local.init + && let ExprKind::Path(QPath::Resolved(_, path)) = init.kind + && let rustc_hir::def::Res::Local(local_hir_id) = path.res + && local_hir_id == hir_id + { + hir_id = local.pat.hir_id; + } else { + return None; + } + } + Some(hir_id) +} diff --git a/tests/ui/needless_character_iteration.fixed b/tests/ui/needless_character_iteration.fixed new file mode 100644 index 00000000000..5a5da592987 --- /dev/null +++ b/tests/ui/needless_character_iteration.fixed @@ -0,0 +1,51 @@ +#![warn(clippy::needless_character_iteration)] +#![allow(clippy::map_identity, clippy::unnecessary_operation)] + +#[derive(Default)] +struct S { + field: &'static str, +} + +impl S { + fn field(&self) -> &str { + self.field + } +} + +fn magic(_: char) {} + +fn main() { + "foo".is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + !"foo".is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + "foo".is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + !"foo".is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + + let s = String::new(); + s.is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + !"foo".to_string().is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + + "foo".is_ascii(); + !"foo".is_ascii(); + + S::default().field().is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + + // Should not lint! + "foo".chars().all(|c| { + let x = c; + magic(x); + x.is_ascii() + }); + + // Should not lint! + "foo".chars().all(|c| c.is_ascii() && c.is_alphabetic()); + + // Should not lint! + "foo".chars().map(|c| c).all(|c| !char::is_ascii(&c)); +} diff --git a/tests/ui/needless_character_iteration.rs b/tests/ui/needless_character_iteration.rs new file mode 100644 index 00000000000..f6320ff22b7 --- /dev/null +++ b/tests/ui/needless_character_iteration.rs @@ -0,0 +1,59 @@ +#![warn(clippy::needless_character_iteration)] +#![allow(clippy::map_identity, clippy::unnecessary_operation)] + +#[derive(Default)] +struct S { + field: &'static str, +} + +impl S { + fn field(&self) -> &str { + self.field + } +} + +fn magic(_: char) {} + +fn main() { + "foo".chars().all(|c| c.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + "foo".chars().all(|c| !c.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + "foo".chars().all(|c| char::is_ascii(&c)); + //~^ ERROR: checking if a string is ascii using iterators + "foo".chars().all(|c| !char::is_ascii(&c)); + //~^ ERROR: checking if a string is ascii using iterators + + let s = String::new(); + s.chars().all(|c| c.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + "foo".to_string().chars().all(|c| !c.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + + "foo".chars().all(|c| { + //~^ ERROR: checking if a string is ascii using iterators + let x = c; + x.is_ascii() + }); + "foo".chars().all(|c| { + //~^ ERROR: checking if a string is ascii using iterators + let x = c; + !x.is_ascii() + }); + + S::default().field().chars().all(|x| x.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + + // Should not lint! + "foo".chars().all(|c| { + let x = c; + magic(x); + x.is_ascii() + }); + + // Should not lint! + "foo".chars().all(|c| c.is_ascii() && c.is_alphabetic()); + + // Should not lint! + "foo".chars().map(|c| c).all(|c| !char::is_ascii(&c)); +} diff --git a/tests/ui/needless_character_iteration.stderr b/tests/ui/needless_character_iteration.stderr new file mode 100644 index 00000000000..05055f75aa7 --- /dev/null +++ b/tests/ui/needless_character_iteration.stderr @@ -0,0 +1,67 @@ +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:18:5 + | +LL | "foo".chars().all(|c| c.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"foo".is_ascii()` + | + = note: `-D clippy::needless-character-iteration` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_character_iteration)]` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:20:5 + | +LL | "foo".chars().all(|c| !c.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:22:5 + | +LL | "foo".chars().all(|c| char::is_ascii(&c)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:24:5 + | +LL | "foo".chars().all(|c| !char::is_ascii(&c)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:28:5 + | +LL | s.chars().all(|c| c.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:30:5 + | +LL | "foo".to_string().chars().all(|c| !c.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".to_string().is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:33:5 + | +LL | / "foo".chars().all(|c| { +LL | | +LL | | let x = c; +LL | | x.is_ascii() +LL | | }); + | |______^ help: try: `"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:38:5 + | +LL | / "foo".chars().all(|c| { +LL | | +LL | | let x = c; +LL | | !x.is_ascii() +LL | | }); + | |______^ help: try: `!"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:44:5 + | +LL | S::default().field().chars().all(|x| x.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `S::default().field().is_ascii()` + +error: aborting due to 9 previous errors + -- cgit 1.4.1-3-g733a5 From 4dcab72c1c796c51afb3f68c554b22e7ff222a64 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 29 May 2024 09:18:09 +0700 Subject: add test for *&[a, b,...]` --- tests/ui/deref_addrof.fixed | 4 ++++ tests/ui/deref_addrof.rs | 4 ++++ tests/ui/deref_addrof.stderr | 18 +++++++++++++++--- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index aa1cf19b76f..db7c44c4c63 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -43,6 +43,10 @@ fn main() { let b = *aref; let _ = unsafe { *core::ptr::addr_of!(a) }; + + // do NOT lint for array as sematic differences with/out `*&`. + let _repeat = [0; 64]; + let _arr = [0, 1, 2, 3, 4]; } #[derive(Copy, Clone)] diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 38796aef390..79b82a76a13 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -43,6 +43,10 @@ fn main() { let b = **&aref; let _ = unsafe { *core::ptr::addr_of!(a) }; + + // do NOT lint for array as sematic differences with/out `*&`. + let _repeat = *&[0; 64]; + let _arr = *&[0, 1, 2, 3, 4]; } #[derive(Copy, Clone)] diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr index 5e3cb417aa0..856d775d932 100644 --- a/tests/ui/deref_addrof.stderr +++ b/tests/ui/deref_addrof.stderr @@ -50,7 +50,19 @@ LL | let b = **&aref; | ^^^^^^ help: try: `aref` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:53:17 + --> tests/ui/deref_addrof.rs:48:19 + | +LL | let _repeat = *&[0; 64]; + | ^^^^^^^^^ help: try: `[0; 64]` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:49:16 + | +LL | let _arr = *&[0, 1, 2, 3, 4]; + | ^^^^^^^^^^^^^^^^^ help: try: `[0, 1, 2, 3, 4]` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:57:17 | LL | inline!(*& $(@expr self)) | ^^^^^^^^^^^^^^^^ help: try: `$(@expr self)` @@ -58,12 +70,12 @@ LL | inline!(*& $(@expr self)) = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:57:17 + --> tests/ui/deref_addrof.rs:61:17 | LL | inline!(*&mut $(@expr self)) | ^^^^^^^^^^^^^^^^^^^ help: try: `$(@expr self)` | = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors -- cgit 1.4.1-3-g733a5 From db30f6ce9f71f73ce0f25a55e198a259a7bb1f92 Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Wed, 29 May 2024 16:21:59 +0800 Subject: fix [`redundant_closure`] suggesting incorrect code with `F: Fn()` --- clippy_lints/src/eta_reduction.rs | 27 +++++++++++++++++++-------- tests/ui/eta.fixed | 11 +++++++++++ tests/ui/eta.rs | 11 +++++++++++ tests/ui/eta.stderr | 14 +++++++++++++- 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 306a4a9e55c..df30351c155 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -123,7 +123,8 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..)) ) => { - let callee_ty = typeck.expr_ty(callee).peel_refs(); + let callee_ty_raw = typeck.expr_ty(callee); + let callee_ty = callee_ty_raw.peel_refs(); if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc)) || !check_inputs(typeck, body.params, None, args) { @@ -170,15 +171,25 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { { span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| { if let Some(mut snippet) = snippet_opt(cx, callee.span) { - if let Ok((ClosureKind::FnMut, _)) = cx.tcx.infer_ctxt().build().type_implements_fn_trait( - cx.param_env, - Binder::bind_with_vars(callee_ty_adjusted, List::empty()), - ty::PredicatePolarity::Positive, - ) && path_to_local(callee).map_or(false, |l| { + if path_to_local(callee).map_or(false, |l| { + // FIXME: Do we really need this `local_used_in` check? + // Isn't it checking something like... `callee(callee)`? + // If somehow this check is needed, add some test for it, + // 'cuz currently nothing changes after deleting this check. local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr) }) { - // Mutable closure is used after current expr; we cannot consume it. - snippet = format!("&mut {snippet}"); + match cx.tcx.infer_ctxt().build().type_implements_fn_trait( + cx.param_env, + Binder::bind_with_vars(callee_ty_adjusted, List::empty()), + ty::PredicatePolarity::Positive, + ) { + // Mutable closure is used after current expr; we cannot consume it. + Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"), + Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => { + snippet = format!("&{snippet}"); + }, + _ => (), + } } diag.span_suggestion( expr.span, diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index da28ec2e653..7126f279945 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -471,3 +471,14 @@ mod issue_10854 { } } } + +mod issue_12853 { + fn f_by_value(f: F) { + let x = Box::new(|| None.map(&f)); + x(); + } + fn f_by_ref(f: &F) { + let x = Box::new(|| None.map(f)); + x(); + } +} diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index f924100f8f4..0787abf5f3e 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -471,3 +471,14 @@ mod issue_10854 { } } } + +mod issue_12853 { + fn f_by_value(f: F) { + let x = Box::new(|| None.map(|x| f(x))); + x(); + } + fn f_by_ref(f: &F) { + let x = Box::new(|| None.map(|x| f(x))); + x(); + } +} diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index d9a8768a682..c757601042f 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -190,5 +190,17 @@ error: redundant closure LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method` -error: aborting due to 31 previous errors +error: redundant closure + --> tests/ui/eta.rs:477:38 + | +LL | let x = Box::new(|| None.map(|x| f(x))); + | ^^^^^^^^ help: replace the closure with the function itself: `&f` + +error: redundant closure + --> tests/ui/eta.rs:481:38 + | +LL | let x = Box::new(|| None.map(|x| f(x))); + | ^^^^^^^^ help: replace the closure with the function itself: `f` + +error: aborting due to 33 previous errors -- cgit 1.4.1-3-g733a5 From 7f66e567b2de4307ae49c01d832c93901e647a07 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 May 2024 09:08:22 +0000 Subject: Don't require `visit_body` to take a lifetime that must outlive the function call --- clippy_lints/src/default_numeric_fallback.rs | 2 +- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/implicit_hasher.rs | 2 +- clippy_lints/src/macro_metavars_in_unsafe.rs | 2 +- clippy_lints/src/needless_borrows_for_generic_args.rs | 2 +- clippy_lints/src/only_used_in_recursion.rs | 4 ++-- clippy_lints/src/operators/mod.rs | 4 ++-- clippy_lints/src/ptr.rs | 6 +++--- clippy_lints/src/question_mark.rs | 4 ++-- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 1d6c4ce72e1..4d8c066fea5 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -49,7 +49,7 @@ declare_clippy_lint! { declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]); impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback { - fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) { let hir = cx.tcx.hir(); let is_parent_const = matches!( hir.body_const_context(hir.body_owner_def_id(body.id())), diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index c6aef9ac2d6..297082354ff 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -641,7 +641,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { } } - fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { + fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &Body<'_>) { if Some(body.id()) == self.current_body { for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) { let replacements = pat.replacements; diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index a46aae36d5c..ca830af3b2f 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -328,7 +328,7 @@ impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> { impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; - fn visit_body(&mut self, body: &'tcx Body<'_>) { + fn visit_body(&mut self, body: &Body<'tcx>) { let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body.id())); walk_body(self, body); self.maybe_typeck_results = old_maybe_typeck_results; diff --git a/clippy_lints/src/macro_metavars_in_unsafe.rs b/clippy_lints/src/macro_metavars_in_unsafe.rs index aea3d26e187..d1ae243877d 100644 --- a/clippy_lints/src/macro_metavars_in_unsafe.rs +++ b/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -186,7 +186,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BodyVisitor<'a, 'tcx> { } impl<'tcx> LateLintPass<'tcx> for ExprMetavarsInUnsafe { - fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx rustc_hir::Body<'tcx>) { + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &rustc_hir::Body<'tcx>) { if is_lint_allowed(cx, MACRO_METAVARS_IN_UNSAFE, body.value.hir_id) { return; } diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index daf166bad90..5b5e1c23424 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -129,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { } } - fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { + fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &Body<'_>) { if self.possible_borrowers.last().map_or(false, |&(local_def_id, _)| { local_def_id == cx.tcx.hir().body_owner_def_id(body.id()) }) { diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index b3ff5ecae86..8b8aabe7acc 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -221,7 +221,7 @@ pub struct OnlyUsedInRecursion { } impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { - fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) { + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) { if body.value.span.from_expansion() { return; } @@ -350,7 +350,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { } } - fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) { + fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) { if self.entered_body == Some(body.value.hir_id) { self.entered_body = None; self.params.flag_for_linting(); diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index e002429e3a4..9e77d0e09c4 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -868,11 +868,11 @@ impl<'tcx> LateLintPass<'tcx> for Operators { self.arithmetic_context.expr_post(e.hir_id); } - fn check_body(&mut self, cx: &LateContext<'tcx>, b: &'tcx Body<'_>) { + fn check_body(&mut self, cx: &LateContext<'tcx>, b: &Body<'_>) { self.arithmetic_context.enter_body(cx, b); } - fn check_body_post(&mut self, cx: &LateContext<'tcx>, b: &'tcx Body<'_>) { + fn check_body_post(&mut self, cx: &LateContext<'tcx>, b: &Body<'_>) { self.arithmetic_context.body_post(cx, b); } } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 38580dc5822..02c05e0aaf9 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -188,7 +188,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { } } - fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) { let hir = cx.tcx.hir(); let mut parents = hir.parent_iter(body.value.hir_id); let (item_id, sig, is_trait_item) = match parents.next() { @@ -525,7 +525,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( }) } -fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Option<&'tcx Body<'_>>) { +fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Option<&Body<'tcx>>) { if let FnRetTy::Return(ty) = sig.decl.output && let Some((out, Mutability::Mut, _)) = get_ref_lm(ty) { @@ -559,7 +559,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio } #[expect(clippy::too_many_lines)] -fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: &[PtrArg<'tcx>]) -> Vec { +fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[PtrArg<'tcx>]) -> Vec { struct V<'cx, 'tcx> { cx: &'cx LateContext<'tcx>, /// Map from a local id to which argument it came from (index into `Self::args` and diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 1f1ce147ca2..7cf98ad9e09 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -370,11 +370,11 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark { } } - fn check_body(&mut self, _: &LateContext<'tcx>, _: &'tcx Body<'tcx>) { + fn check_body(&mut self, _: &LateContext<'tcx>, _: &Body<'tcx>) { self.try_block_depth_stack.push(0); } - fn check_body_post(&mut self, _: &LateContext<'tcx>, _: &'tcx Body<'tcx>) { + fn check_body_post(&mut self, _: &LateContext<'tcx>, _: &Body<'tcx>) { self.try_block_depth_stack.pop(); } -- cgit 1.4.1-3-g733a5 From f44a6a7cb59ddff2964e26c9eb0ad50a6c555c99 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 May 2024 10:03:40 +0000 Subject: Make `body_owned_by` return the body directly. Almost all callers want this anyway, and now we can use it to also return fed bodies --- clippy_lints/src/methods/option_map_unwrap_or.rs | 4 ++-- clippy_lints/src/single_call_fn.rs | 1 - clippy_lints/src/transmute/missing_transmute_annotations.rs | 4 ++-- clippy_lints/src/unconditional_recursion.rs | 2 +- clippy_lints/src/utils/author.rs | 4 ++-- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index efec9dd716d..ca331f3e756 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -59,8 +59,8 @@ pub(super) fn check<'tcx>( }; let map = cx.tcx.hir(); - let body = map.body(map.body_owned_by(map.enclosing_body_owner(expr.hir_id))); - reference_visitor.visit_body(body); + let body = map.body_owned_by(map.enclosing_body_owner(expr.hir_id)); + reference_visitor.visit_body(&body); if reference_visitor.found_reference { return; diff --git a/clippy_lints/src/single_call_fn.rs b/clippy_lints/src/single_call_fn.rs index 2ce7e714c64..f8e09d517f5 100644 --- a/clippy_lints/src/single_call_fn.rs +++ b/clippy_lints/src/single_call_fn.rs @@ -79,7 +79,6 @@ impl SingleCallFn { .tcx .hir() .maybe_body_owned_by(fn_def_id) - .map(|body| cx.tcx.hir().body(body)) .map_or(true, |body| is_in_test_function(cx.tcx, body.value.hir_id)) || match cx.tcx.hir_node(fn_hir_id) { Node::Item(item) => is_from_proc_macro(cx, item), diff --git a/clippy_lints/src/transmute/missing_transmute_annotations.rs b/clippy_lints/src/transmute/missing_transmute_annotations.rs index cc6ff1cf3b4..f98ea59a15d 100644 --- a/clippy_lints/src/transmute/missing_transmute_annotations.rs +++ b/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -30,8 +30,8 @@ fn get_parent_local_binding_ty<'tcx>(cx: &LateContext<'tcx>, expr_hir_id: HirId) fn is_function_block(cx: &LateContext<'_>, expr_hir_id: HirId) -> bool { let def_id = cx.tcx.hir().enclosing_body_owner(expr_hir_id); - if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id) { - let body = cx.tcx.hir().body(body_id); + if let Some(body) = cx.tcx.hir().maybe_body_owned_by(def_id) { + let body = cx.tcx.hir().body(body.id()); return body.value.peel_blocks().hir_id == expr_hir_id; } false diff --git a/clippy_lints/src/unconditional_recursion.rs b/clippy_lints/src/unconditional_recursion.rs index 0c4e2c91aec..5e41b3f4914 100644 --- a/clippy_lints/src/unconditional_recursion.rs +++ b/clippy_lints/src/unconditional_recursion.rs @@ -336,7 +336,7 @@ impl UnconditionalRecursion { // We need to use typeck here to infer the actual function being called. && let body_def_id = cx.tcx.hir().enclosing_body_owner(call_expr.hir_id) && let Some(body_owner) = cx.tcx.hir().maybe_body_owned_by(body_def_id) - && let typeck = cx.tcx.typeck_body(body_owner) + && let typeck = cx.tcx.typeck_body(body_owner.id()) && let Some(call_def_id) = typeck.type_dependent_def_id(call_expr.hir_id) { self.default_impl_for_type.insert(self_def_id, call_def_id); diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 4448c9ae3df..18a31abddd0 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -137,9 +137,9 @@ impl<'tcx> LateLintPass<'tcx> for Author { fn check_item(cx: &LateContext<'_>, hir_id: HirId) { let hir = cx.tcx.hir(); - if let Some(body_id) = hir.maybe_body_owned_by(hir_id.expect_owner().def_id) { + if let Some(body) = hir.maybe_body_owned_by(hir_id.expect_owner().def_id) { check_node(cx, hir_id, |v| { - v.expr(&v.bind("expr", hir.body(body_id).value)); + v.expr(&v.bind("expr", body.value)); }); } } -- cgit 1.4.1-3-g733a5 From 14c1f740f2def175ad7332b0bae85906e590d6a7 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 29 May 2024 13:38:00 +0200 Subject: make `ptr::rotate` smaller when using `optimize_for_size` code to reproduce https://github.com/folkertdev/optimize_for_size-slice-rotate In the example the size of `.text` goes down from 1624 to 276 bytes. --- library/core/src/slice/rotate.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/rotate.rs b/library/core/src/slice/rotate.rs index fa8c238f8e7..1d7b8633979 100644 --- a/library/core/src/slice/rotate.rs +++ b/library/core/src/slice/rotate.rs @@ -71,7 +71,9 @@ pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) if (right == 0) || (left == 0) { return; } - if (left + right < 24) || (mem::size_of::() > mem::size_of::<[usize; 4]>()) { + if !cfg!(feature = "optimize_for_size") + && ((left + right < 24) || (mem::size_of::() > mem::size_of::<[usize; 4]>())) + { // Algorithm 1 // Microbenchmarks indicate that the average performance for random shifts is better all // the way until about `left + right == 32`, but the worst case performance breaks even @@ -158,7 +160,9 @@ pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) } return; // `T` is not a zero-sized type, so it's okay to divide by its size. - } else if cmp::min(left, right) <= mem::size_of::() / mem::size_of::() { + } else if !cfg!(feature = "optimize_for_size") + && cmp::min(left, right) <= mem::size_of::() / mem::size_of::() + { // Algorithm 2 // The `[T; 0]` here is to ensure this is appropriately aligned for T let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); -- cgit 1.4.1-3-g733a5 From c4c8bda689b3cb4474ef0aaad4bbcfaeeef434c1 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 29 May 2024 14:47:01 +0200 Subject: non_local_defs: indicate that the macro needs to change aaa --- compiler/rustc_lint/messages.ftl | 1 + compiler/rustc_lint/src/lints.rs | 8 ++++++++ compiler/rustc_lint/src/non_local_def.rs | 8 ++++++++ tests/ui/lint/non-local-defs/cargo-update.stderr | 1 + tests/ui/lint/non-local-defs/inside-macro_rules.stderr | 1 + 5 files changed, 19 insertions(+) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index d2b1f50d79c..28f75a8193b 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -550,6 +550,7 @@ lint_non_local_definitions_impl = non-local `impl` definition, `impl` blocks sho .bounds = `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type .exception = items in an anonymous const item (`const _: () = {"{"} ... {"}"}`) are treated as in the same scope as the anonymous const's declaration .const_anon = use a const-anon item to suppress this lint + .macro_to_change = the {$macro_kind} `{$macro_to_change}` defines the non-local `impl`, and may need to be changed lint_non_local_definitions_impl_move_help = move the `impl` block outside of this {$body_kind_descr} {$depth -> diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c365e68ba44..91a600e754f 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1355,6 +1355,7 @@ pub enum NonLocalDefinitionsDiag { has_trait: bool, self_ty_str: String, of_trait_str: Option, + macro_to_change: Option<(String, &'static str)>, }, MacroRules { depth: u32, @@ -1380,6 +1381,7 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { has_trait, self_ty_str, of_trait_str, + macro_to_change, } => { diag.primary_message(fluent::lint_non_local_definitions_impl); diag.arg("depth", depth); @@ -1390,6 +1392,12 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { diag.arg("of_trait_str", of_trait_str); } + if let Some((macro_to_change, macro_kind)) = macro_to_change { + diag.arg("macro_to_change", macro_to_change); + diag.arg("macro_kind", macro_kind); + diag.note(fluent::lint_macro_to_change); + } + if has_trait { diag.note(fluent::lint_bounds); diag.note(fluent::lint_with_trait); diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 42b03f47a5b..ac5ed9d2190 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -258,6 +258,13 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { Some((cx.tcx.def_span(parent), may_move)) }; + let macro_to_change = + if let ExpnKind::Macro(kind, name) = item.span.ctxt().outer_expn_data().kind { + Some((name.to_string(), kind.descr())) + } else { + None + }; + cx.emit_span_lint( NON_LOCAL_DEFINITIONS, ms, @@ -274,6 +281,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { move_to, may_remove, has_trait: impl_.of_trait.is_some(), + macro_to_change, }, ) } diff --git a/tests/ui/lint/non-local-defs/cargo-update.stderr b/tests/ui/lint/non-local-defs/cargo-update.stderr index 888fd2e6183..c1f224edeba 100644 --- a/tests/ui/lint/non-local-defs/cargo-update.stderr +++ b/tests/ui/lint/non-local-defs/cargo-update.stderr @@ -8,6 +8,7 @@ LL | non_local_macro::non_local_impl!(LocalStruct); | `Debug` is not local | move the `impl` block outside of this constant `_IMPL_DEBUG` | + = note: the macro `non_local_macro::non_local_impl` defines the non-local `impl`, and may need to be changed = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` diff --git a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr index b52301d1aa0..fa9ba2cb785 100644 --- a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr +++ b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr @@ -12,6 +12,7 @@ LL | impl MacroTrait for OutsideStruct {} LL | m!(); | ---- in this macro invocation | + = note: the macro `m` defines the non-local `impl`, and may need to be changed = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -- cgit 1.4.1-3-g733a5 From b5d486793647ef4df01259639cae2ee908bde659 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 29 May 2024 17:01:43 +0200 Subject: non_local_defs: move cargo update suggestion upper --- compiler/rustc_lint/src/lints.rs | 6 +++--- tests/ui/lint/non-local-defs/cargo-update.stderr | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 91a600e754f..d45d71ff8fe 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1397,6 +1397,9 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { diag.arg("macro_kind", macro_kind); diag.note(fluent::lint_macro_to_change); } + if let Some(cargo_update) = cargo_update { + diag.subdiagnostic(&diag.dcx, cargo_update); + } if has_trait { diag.note(fluent::lint_bounds); @@ -1423,9 +1426,6 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { ); } - if let Some(cargo_update) = cargo_update { - diag.subdiagnostic(&diag.dcx, cargo_update); - } if let Some(const_anon) = const_anon { diag.note(fluent::lint_exception); if let Some(const_anon) = const_anon { diff --git a/tests/ui/lint/non-local-defs/cargo-update.stderr b/tests/ui/lint/non-local-defs/cargo-update.stderr index c1f224edeba..afd37d03a23 100644 --- a/tests/ui/lint/non-local-defs/cargo-update.stderr +++ b/tests/ui/lint/non-local-defs/cargo-update.stderr @@ -9,9 +9,9 @@ LL | non_local_macro::non_local_impl!(LocalStruct); | move the `impl` block outside of this constant `_IMPL_DEBUG` | = note: the macro `non_local_macro::non_local_impl` defines the non-local `impl`, and may need to be changed + = note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: `#[warn(non_local_definitions)]` on by default -- cgit 1.4.1-3-g733a5 From d38920f67752c270dcdbf7444f668c019864f12f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 29 May 2024 21:30:21 +0300 Subject: ast: Revert a breaking attribute visiting order change --- tests/ui/tabs_in_doc_comments.stderr | 48 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/tests/ui/tabs_in_doc_comments.stderr b/tests/ui/tabs_in_doc_comments.stderr index aef6c391452..23d5dcd3a8d 100644 --- a/tests/ui/tabs_in_doc_comments.stderr +++ b/tests/ui/tabs_in_doc_comments.stderr @@ -1,53 +1,53 @@ error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:5 + --> tests/ui/tabs_in_doc_comments.rs:10:9 | -LL | /// - first one - | ^^^^ help: consider using four spaces per tab +LL | /// - First String: + | ^^^^ help: consider using four spaces per tab | = note: `-D clippy::tabs-in-doc-comments` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::tabs_in_doc_comments)]` error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:13 + --> tests/ui/tabs_in_doc_comments.rs:11:9 | -LL | /// - first one - | ^^^^^^^^ help: consider using four spaces per tab +LL | /// - needs to be inside here + | ^^^^^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:7:5 + --> tests/ui/tabs_in_doc_comments.rs:14:9 | -LL | /// - second one - | ^^^^ help: consider using four spaces per tab +LL | /// - Second String: + | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:7:14 + --> tests/ui/tabs_in_doc_comments.rs:15:9 | -LL | /// - second one - | ^^^^ help: consider using four spaces per tab +LL | /// - needs to be inside here + | ^^^^^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:10:9 + --> tests/ui/tabs_in_doc_comments.rs:6:5 | -LL | /// - First String: - | ^^^^ help: consider using four spaces per tab +LL | /// - first one + | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:11:9 + --> tests/ui/tabs_in_doc_comments.rs:6:13 | -LL | /// - needs to be inside here - | ^^^^^^^^ help: consider using four spaces per tab +LL | /// - first one + | ^^^^^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:14:9 + --> tests/ui/tabs_in_doc_comments.rs:7:5 | -LL | /// - Second String: - | ^^^^ help: consider using four spaces per tab +LL | /// - second one + | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:15:9 + --> tests/ui/tabs_in_doc_comments.rs:7:14 | -LL | /// - needs to be inside here - | ^^^^^^^^ help: consider using four spaces per tab +LL | /// - second one + | ^^^^ help: consider using four spaces per tab error: aborting due to 8 previous errors -- cgit 1.4.1-3-g733a5 From 8bd2a17dfe1b5089b942c44db6b152f5d4b30a3e Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 29 May 2024 09:19:33 +0700 Subject: ignore array from `deref_addrof` lint Note that semantics of repeat expr in array are the same --- clippy_lints/src/reference.rs | 3 +++ tests/ui/deref_addrof.fixed | 4 ++-- tests/ui/deref_addrof.rs | 2 +- tests/ui/deref_addrof.stderr | 10 ++-------- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 16086ba6637..8f32cf5f2a1 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -48,6 +48,9 @@ impl EarlyLintPass for DerefAddrOf { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind && let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind + // NOTE(tesuji): `*&` forces rustc to const-promote the array to `.rodata` section. + // See #12854 for details. + && !matches!(addrof_target.kind, ExprKind::Array(_)) && deref_target.span.eq_ctxt(e.span) && !addrof_target.span.from_expansion() { diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index db7c44c4c63..b6278c6ca8a 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -44,9 +44,9 @@ fn main() { let _ = unsafe { *core::ptr::addr_of!(a) }; - // do NOT lint for array as sematic differences with/out `*&`. let _repeat = [0; 64]; - let _arr = [0, 1, 2, 3, 4]; + // do NOT lint for array as sematic differences with/out `*&`. + let _arr = *&[0, 1, 2, 3, 4]; } #[derive(Copy, Clone)] diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 79b82a76a13..572b0fdb102 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -44,8 +44,8 @@ fn main() { let _ = unsafe { *core::ptr::addr_of!(a) }; - // do NOT lint for array as sematic differences with/out `*&`. let _repeat = *&[0; 64]; + // do NOT lint for array as sematic differences with/out `*&`. let _arr = *&[0, 1, 2, 3, 4]; } diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr index 856d775d932..20069f746c8 100644 --- a/tests/ui/deref_addrof.stderr +++ b/tests/ui/deref_addrof.stderr @@ -50,17 +50,11 @@ LL | let b = **&aref; | ^^^^^^ help: try: `aref` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:48:19 + --> tests/ui/deref_addrof.rs:47:19 | LL | let _repeat = *&[0; 64]; | ^^^^^^^^^ help: try: `[0; 64]` -error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:49:16 - | -LL | let _arr = *&[0, 1, 2, 3, 4]; - | ^^^^^^^^^^^^^^^^^ help: try: `[0, 1, 2, 3, 4]` - error: immediately dereferencing a reference --> tests/ui/deref_addrof.rs:57:17 | @@ -77,5 +71,5 @@ LL | inline!(*&mut $(@expr self)) | = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors -- cgit 1.4.1-3-g733a5 From f67f72695a2ac5e7a1d39383583a6abb1cf9f4ad Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 30 May 2024 10:49:05 +0200 Subject: Merge commit 'c9139bd546d9cd69df817faeab62c5f9b1a51337' into clippy-subtree-update --- book/src/configuration.md | 2 +- book/src/development/adding_lints.md | 5 + clippy_dev/src/new_lint.rs | 7 +- clippy_lints/src/absolute_paths.rs | 2 +- clippy_lints/src/allow_attributes.rs | 7 +- clippy_lints/src/as_conversions.rs | 2 +- clippy_lints/src/asm_syntax.rs | 10 +- clippy_lints/src/assertions_on_result_states.rs | 20 +- clippy_lints/src/attrs/mod.rs | 6 +- clippy_lints/src/casts/mod.rs | 6 +- clippy_lints/src/create_dir.rs | 6 +- clippy_lints/src/dbg_macro.rs | 2 +- clippy_lints/src/default_numeric_fallback.rs | 5 +- clippy_lints/src/default_union_representation.rs | 2 +- clippy_lints/src/dereference.rs | 14 +- clippy_lints/src/derive.rs | 31 +- clippy_lints/src/disallowed_script_idents.rs | 4 +- clippy_lints/src/doc/markdown.rs | 28 +- clippy_lints/src/doc/mod.rs | 2 +- clippy_lints/src/drop_forget_ref.rs | 7 +- clippy_lints/src/else_if_without_else.rs | 2 +- clippy_lints/src/empty_drop.rs | 2 +- clippy_lints/src/empty_enum.rs | 45 ++- clippy_lints/src/empty_with_brackets.rs | 24 +- clippy_lints/src/endian_bytes.rs | 15 +- clippy_lints/src/error_impl_error.rs | 2 +- clippy_lints/src/exhaustive_items.rs | 16 +- clippy_lints/src/exit.rs | 12 +- clippy_lints/src/float_literal.rs | 6 +- clippy_lints/src/format_push_string.rs | 2 +- clippy_lints/src/functions/misnamed_getters.rs | 2 +- clippy_lints/src/functions/mod.rs | 11 +- clippy_lints/src/if_then_some_else_none.rs | 2 +- clippy_lints/src/implicit_return.rs | 13 +- clippy_lints/src/indexing_slicing.rs | 7 +- clippy_lints/src/inherent_impl.rs | 2 +- clippy_lints/src/init_numbered_fields.rs | 4 +- .../src/integer_division_remainder_used.rs | 6 +- clippy_lints/src/iter_over_hash_type.rs | 4 +- clippy_lints/src/large_include_file.rs | 8 +- clippy_lints/src/let_underscore.rs | 9 +- clippy_lints/src/literal_representation.rs | 4 +- clippy_lints/src/loops/mod.rs | 6 +- clippy_lints/src/matches/mod.rs | 6 +- .../src/matches/significant_drop_in_scrutinee.rs | 418 +++++++++++---------- .../methods/iter_on_single_or_empty_collections.rs | 47 ++- clippy_lints/src/methods/mod.rs | 21 +- .../src/methods/unnecessary_iter_cloned.rs | 16 +- clippy_lints/src/methods/utils.rs | 16 +- clippy_lints/src/min_ident_chars.rs | 7 +- clippy_lints/src/misc_early/mod.rs | 6 +- clippy_lints/src/missing_assert_message.rs | 2 +- clippy_lints/src/missing_asserts_for_indexing.rs | 2 +- clippy_lints/src/missing_doc.rs | 4 +- clippy_lints/src/missing_inline.rs | 19 +- clippy_lints/src/missing_trait_methods.rs | 10 +- clippy_lints/src/mixed_read_write_in_expression.rs | 9 +- clippy_lints/src/module_style.rs | 6 +- clippy_lints/src/multiple_unsafe_ops_per_block.rs | 4 +- clippy_lints/src/mutex_atomic.rs | 2 +- clippy_lints/src/needless_bool.rs | 13 +- clippy_lints/src/non_expressive_names.rs | 4 + clippy_lints/src/operators/mod.rs | 12 +- clippy_lints/src/panic_in_result_fn.rs | 4 +- clippy_lints/src/panic_unimplemented.rs | 18 +- clippy_lints/src/partial_pub_fields.rs | 9 +- clippy_lints/src/pattern_type_mismatch.rs | 5 +- clippy_lints/src/pub_use.rs | 8 +- clippy_lints/src/question_mark_used.rs | 2 +- clippy_lints/src/raw_strings.rs | 6 +- clippy_lints/src/redundant_slicing.rs | 2 +- clippy_lints/src/redundant_type_annotations.rs | 2 +- clippy_lints/src/ref_patterns.rs | 4 +- clippy_lints/src/returns.rs | 34 +- clippy_lints/src/same_name_method.rs | 2 +- clippy_lints/src/semicolon_block.rs | 6 +- clippy_lints/src/shadow.rs | 26 +- clippy_lints/src/single_call_fn.rs | 19 +- clippy_lints/src/single_char_lifetime_names.rs | 5 +- clippy_lints/src/std_instead_of_core.rs | 12 +- clippy_lints/src/strings.rs | 19 +- clippy_lints/src/suspicious_xor_used_as_pow.rs | 4 +- clippy_lints/src/tests_outside_test_module.rs | 4 +- clippy_lints/src/types/mod.rs | 4 +- clippy_lints/src/undocumented_unsafe_blocks.rs | 9 +- clippy_lints/src/unicode.rs | 2 +- clippy_lints/src/unnecessary_self_imports.rs | 2 +- clippy_lints/src/unwrap_in_result.rs | 6 +- clippy_lints/src/visibility.rs | 4 +- clippy_lints/src/write.rs | 13 +- clippy_utils/src/consts.rs | 6 +- clippy_utils/src/hir_utils.rs | 2 +- clippy_utils/src/lib.rs | 22 ++ clippy_utils/src/ty.rs | 6 +- rust-toolchain | 2 +- tests/ui-internal/disallow_span_lint.rs | 8 +- tests/ui-internal/disallow_span_lint.stderr | 14 +- tests/ui/derive_partial_eq_without_eq.fixed | 17 + tests/ui/derive_partial_eq_without_eq.rs | 17 + tests/ui/derive_partial_eq_without_eq.stderr | 26 +- tests/ui/doc/doc-fixable.fixed | 3 + tests/ui/doc/doc-fixable.rs | 3 + tests/ui/doc/doc-fixable.stderr | 8 +- tests/ui/doc/issue_12795.fixed | 9 + tests/ui/doc/issue_12795.rs | 9 + tests/ui/doc/issue_12795.stderr | 48 +++ tests/ui/iter_on_empty_collections.fixed | 22 ++ tests/ui/iter_on_empty_collections.rs | 22 ++ tests/ui/iter_on_empty_collections.stderr | 8 +- tests/ui/let_and_return.fixed | 34 ++ tests/ui/let_and_return.rs | 34 ++ tests/ui/let_and_return.stderr | 72 +++- tests/ui/many_single_char_names.rs | 2 - tests/ui/many_single_char_names.stderr | 10 +- tests/ui/needless_return.fixed | 4 + tests/ui/needless_return.rs | 4 + tests/ui/needless_return.stderr | 14 +- tests/ui/numbered_fields.fixed | 5 + tests/ui/numbered_fields.rs | 5 + tests/ui/numbered_fields.stderr | 8 +- tests/ui/significant_drop_in_scrutinee.rs | 98 ++++- tests/ui/significant_drop_in_scrutinee.stderr | 206 +++++----- tests/ui/unnecessary_iter_cloned.fixed | 29 ++ tests/ui/unnecessary_iter_cloned.rs | 29 ++ tests/ui/unnecessary_iter_cloned.stderr | 44 ++- tests/ui/unnecessary_to_owned.stderr | 2 +- tests/ui/unsafe_derive_deserialize.rs | 11 + tests/ui/unsafe_derive_deserialize.stderr | 8 +- 128 files changed, 1422 insertions(+), 676 deletions(-) create mode 100644 tests/ui/doc/issue_12795.fixed create mode 100644 tests/ui/doc/issue_12795.rs create mode 100644 tests/ui/doc/issue_12795.stderr diff --git a/book/src/configuration.md b/book/src/configuration.md index 9eb067abd91..ea549e4df4a 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -133,7 +133,7 @@ Very rarely, you may wish to prevent Clippy from evaluating certain sections of `clippy` cfg is not set. You may need to provide a stub so that the code compiles: ```rust -#[cfg(not(clippy)] +#[cfg(not(clippy))] include!(concat!(env!("OUT_DIR"), "/my_big_function-generated.rs")); #[cfg(clippy)] diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 415022612ca..48c00bcbf34 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -587,6 +587,11 @@ declare_clippy_lint! { } ``` +If the lint is in the `restriction` group because it lints things that are not +necessarily “bad” but are more of a style choice, then replace the +“Why is this bad?” section heading with “Why restrict this?”, to avoid writing +“Why is this bad? It isn't, but ...”. + Once your lint is merged, this documentation will show up in the [lint list][lint_list]. diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index b6481dde4dd..2e56eb8ec15 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -331,12 +331,17 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { } fn get_lint_declaration(name_upper: &str, category: &str) -> String { + let justification_heading = if category == "restriction" { + "Why restrict this?" + } else { + "Why is this bad?" + }; formatdoc!( r#" declare_clippy_lint! {{ /// ### What it does /// - /// ### Why is this bad? + /// ### {justification_heading} /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs index 8ba661afeeb..461117cf965 100644 --- a/clippy_lints/src/absolute_paths.rs +++ b/clippy_lints/src/absolute_paths.rs @@ -12,7 +12,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of items through absolute paths, like `std::env::current_dir`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Many codebases have their own style when it comes to importing, but one that is seldom used /// is using absolute paths *everywhere*. This is generally considered unidiomatic, and you /// should add a `use` statement. diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index 39fc49dee37..123d0e51eee 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -19,10 +19,11 @@ declare_clippy_lint! { /// This lint only warns outer attributes (`#[allow]`), as inner attributes /// (`#![allow]`) are usually used to enable or disable lints on a global scale. /// - /// ### Why is this bad? - /// `#[expect]` attributes suppress the lint emission, but emit a warning, if + /// ### Why restrict this? + /// `#[allow]` attributes can linger after their reason for existence is gone. + /// `#[expect]` attributes suppress the lint emission, but emit a warning if /// the expectation is unfulfilled. This can be useful to be notified when the - /// lint is no longer triggered. + /// lint is no longer triggered, which may indicate the attribute can be removed. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index e3daf75c3eb..cfa25005a05 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// There is a good explanation the reason why this lint should work in this way and how it is useful /// [in this issue](https://github.com/rust-lang/rust-clippy/issues/5122). /// - /// ### Why is this bad? + /// ### Why restrict this? /// `as` conversions will perform many kinds of /// conversions, including silently lossy conversions and dangerous coercions. /// There are cases when it makes sense to use `as`, so the lint is diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index 7c88bfc97ca..0db1456d40b 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -65,9 +65,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of Intel x86 assembly syntax. /// - /// ### Why is this bad? - /// The lint has been enabled to indicate a preference - /// for AT&T x86 assembly syntax. + /// ### Why restrict this? + /// To enforce consistent use of AT&T x86 assembly syntax. /// /// ### Example /// @@ -114,9 +113,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of AT&T x86 assembly syntax. /// - /// ### Why is this bad? - /// The lint has been enabled to indicate a preference - /// for Intel x86 assembly syntax. + /// ### Why restrict this? + /// To enforce consistent use of Intel x86 assembly syntax. /// /// ### Example /// diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index aec22965b1b..7217686dcca 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -16,23 +16,33 @@ declare_clippy_lint! { /// ### What it does /// Checks for `assert!(r.is_ok())` or `assert!(r.is_err())` calls. /// - /// ### Why is this bad? - /// An assertion failure cannot output an useful message of the error. + /// ### Why restrict this? + /// This form of assertion does not show any of the information present in the `Result` + /// other than which variant it isn’t. /// /// ### Known problems /// The suggested replacement decreases the readability of code and log output. /// /// ### Example - /// ```rust,ignore + /// ```rust,no_run /// # let r = Ok::<_, ()>(()); /// assert!(r.is_ok()); - /// # let r = Err::<_, ()>(()); + /// # let r = Err::<(), _>(()); /// assert!(r.is_err()); /// ``` + /// + /// Use instead: + /// + /// ```rust,no_run + /// # let r = Ok::<_, ()>(()); + /// r.unwrap(); + /// # let r = Err::<(), _>(()); + /// r.unwrap_err(); + /// ``` #[clippy::version = "1.64.0"] pub ASSERTIONS_ON_RESULT_STATES, restriction, - "`assert!(r.is_ok())`/`assert!(r.is_err())` gives worse error message than directly calling `r.unwrap()`/`r.unwrap_err()`" + "`assert!(r.is_ok())` or `assert!(r.is_err())` gives worse panic messages than directly calling `r.unwrap()` or `r.unwrap_err()`" } declare_lint_pass!(AssertionsOnResultStates => [ASSERTIONS_ON_RESULT_STATES]); diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 39f40607799..a24bd5ed44b 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -309,9 +309,9 @@ declare_clippy_lint! { /// /// (This requires the `lint_reasons` feature) /// - /// ### Why is this bad? - /// Allowing a lint should always have a reason. This reason should be documented to - /// ensure that others understand the reasoning + /// ### Why restrict this? + /// Justifying each `allow` helps readers understand the reasoning, + /// and may allow removing `allow` attributes if their purpose is obsolete. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index bd2c96f01f6..e60c36ced75 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -303,7 +303,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for casts of a function pointer to any integer type. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Casting a function pointer to an integer can have surprising results and can occur /// accidentally if parentheses are omitted from a function call. If you aren't doing anything /// low-level with function pointers then you can opt-out of casting functions to integers in @@ -535,8 +535,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for the usage of `as _` conversion using inferred type. /// - /// ### Why is this bad? - /// The conversion might include lossy conversion and dangerous cast that might go + /// ### Why restrict this? + /// The conversion might include lossy conversion or a dangerous cast that might go /// undetected due to the type being inferred. /// /// The lint is allowed by default as using `_` is less wordy than always specifying the type. diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 7a3d5a07091..27c00948a8f 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -10,8 +10,10 @@ declare_clippy_lint! { /// ### What it does /// Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead. /// - /// ### Why is this bad? - /// Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`. + /// ### Why restrict this? + /// Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`, + /// resulting in failure when more than one directory needs to be created or when the directory already exists. + /// Crates which never need to specifically create a single directory may wish to prevent this mistake. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index db593726604..b0590b0a71c 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of the [`dbg!`](https://doc.rust-lang.org/std/macro.dbg.html) macro. /// - /// ### Why is this bad? + /// ### Why restrict this? /// The `dbg!` macro is intended as a debugging tool. It should not be present in released /// software or committed to a version control system. /// diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 1d6c4ce72e1..fbc4ede37b1 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -22,9 +22,8 @@ declare_clippy_lint! { /// /// See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-int-fallback.md) for more information about the fallback. /// - /// ### Why is this bad? - /// For those who are very careful about types, default numeric fallback - /// can be a pitfall that cause unexpected runtime behavior. + /// ### Why restrict this? + /// To ensure that every numeric type is chosen explicitly rather than implicitly. /// /// ### Known problems /// This lint can only be allowed at the function level or above. diff --git a/clippy_lints/src/default_union_representation.rs b/clippy_lints/src/default_union_representation.rs index b4290b6437f..3fa9bad0d03 100644 --- a/clippy_lints/src/default_union_representation.rs +++ b/clippy_lints/src/default_union_representation.rs @@ -10,7 +10,7 @@ declare_clippy_lint! { /// ### What it does /// Displays a warning when a union is declared with the default representation (without a `#[repr(C)]` attribute). /// - /// ### Why is this bad? + /// ### Why restrict this? /// Unions in Rust have unspecified layout by default, despite many people thinking that they /// lay out each field at the start of the union (like C does). That is, there are no guarantees /// about the offset of the fields for unions with multiple non-ZST fields without an explicitly diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index c6aef9ac2d6..0276c64ef9b 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -2,7 +2,9 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs}; -use clippy_utils::{expr_use_ctxt, get_parent_expr, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode}; +use clippy_utils::{ + expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode, +}; use core::mem; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; @@ -1038,14 +1040,8 @@ fn report<'tcx>( ); }, State::ExplicitDeref { mutability } => { - if matches!( - expr.kind, - ExprKind::Block(..) - | ExprKind::ConstBlock(_) - | ExprKind::If(..) - | ExprKind::Loop(..) - | ExprKind::Match(..) - ) && let ty::Ref(_, ty, _) = data.adjusted_ty.kind() + if is_block_like(expr) + && let ty::Ref(_, ty, _) = data.adjusted_ty.kind() && ty.is_sized(cx.tcx, cx.param_env) { // Rustc bug: auto deref doesn't work on block expression when targeting sized types. diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 2a644922fb1..636698e96f6 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,17 +1,17 @@ -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy}; use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; use rustc_hir::{ - self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Safety, Impl, Item, ItemKind, UnsafeSource, + self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, Safety, UnsafeSource, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::traits::Reveal; use rustc_middle::ty::{ - self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, Upcast, TraitPredicate, Ty, TyCtxt, + self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, TraitPredicate, Ty, TyCtxt, Upcast, }; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; @@ -390,13 +390,17 @@ fn check_unsafe_derive_deserialize<'tcx>( .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local())) .any(|imp| has_unsafe(cx, imp)) { - span_lint_and_help( + span_lint_hir_and_then( cx, UNSAFE_DERIVE_DESERIALIZE, + adt_hir_id, item.span, "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`", - None, - "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html", + |diag| { + diag.help( + "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html", + ); + }, ); } } @@ -452,20 +456,27 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r && !has_non_exhaustive_attr(cx.tcx, *adt) && !ty_implements_eq_trait(cx.tcx, ty, eq_trait_def_id) && let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id) + && let Some(local_def_id) = adt.did().as_local() // If all of our fields implement `Eq`, we can implement `Eq` too && adt .all_fields() .map(|f| f.ty(cx.tcx, args)) .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, None, &[])) { - span_lint_and_sugg( + span_lint_hir_and_then( cx, DERIVE_PARTIAL_EQ_WITHOUT_EQ, + cx.tcx.local_def_id_to_hir_id(local_def_id), span.ctxt().outer_expn_data().call_site, "you are deriving `PartialEq` and can implement `Eq`", - "consider deriving `Eq` as well", - "PartialEq, Eq".to_string(), - Applicability::MachineApplicable, + |diag| { + diag.span_suggestion( + span.ctxt().outer_expn_data().call_site, + "consider deriving `Eq` as well", + "PartialEq, Eq", + Applicability::MachineApplicable, + ); + }, ); } } diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index def4b5932b4..a995f06fb73 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -20,11 +20,11 @@ declare_clippy_lint! { /// [aliases]: http://www.unicode.org/reports/tr24/tr24-31.html#Script_Value_Aliases /// [supported_scripts]: https://www.unicode.org/iso15924/iso15924-codes.html /// - /// ### Why is this bad? + /// ### Why restrict this? /// It may be not desired to have many different scripts for /// identifiers in the codebase. /// - /// Note that if you only want to allow plain English, you might want to use + /// Note that if you only want to allow typical English, you might want to use /// built-in [`non_ascii_idents`] lint instead. /// /// [`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents diff --git a/clippy_lints/src/doc/markdown.rs b/clippy_lints/src/doc/markdown.rs index 1add02af310..41c0bcd55ad 100644 --- a/clippy_lints/src/doc/markdown.rs +++ b/clippy_lints/src/doc/markdown.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, SuggestionStyle}; @@ -30,6 +30,7 @@ pub fn check( word = tmp_word; } + let original_len = word.len(); word = word.trim_start_matches(trim_pattern); // Remove leading or trailing single `:` which may be part of a sentence. @@ -44,6 +45,25 @@ pub fn check( continue; } + // Ensure that all reachable matching closing parens are included as well. + let size_diff = original_len - word.len(); + let mut open_parens = 0; + let mut close_parens = 0; + for c in word.chars() { + if c == '(' { + open_parens += 1; + } else if c == ')' { + close_parens += 1; + } + } + while close_parens < open_parens + && let Some(tmp_word) = orig_word.get(size_diff..=(word.len() + size_diff)) + && tmp_word.ends_with(')') + { + word = tmp_word; + close_parens += 1; + } + // Adjust for the current word let offset = word.as_ptr() as usize - text.as_ptr() as usize; let span = Span::new( @@ -92,13 +112,15 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b if let Ok(url) = Url::parse(word) { // try to get around the fact that `foo::bar` parses as a valid URL if !url.cannot_be_a_base() { - span_lint( + span_lint_and_sugg( cx, DOC_MARKDOWN, span, "you should put bare URLs between `<`/`>` or make a proper Markdown link", + "try", + format!("<{word}>"), + Applicability::MachineApplicable, ); - return; } } diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 9f08973948a..3d875e7ac2d 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -261,7 +261,7 @@ declare_clippy_lint! { /// Checks for the doc comments of publicly visible /// safe functions and traits and warns if there is a `# Safety` section. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Safe functions and traits are safe to implement and therefore do not /// need to describe safety preconditions that users are required to uphold. /// diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 119473c2454..4a6ffcd9a78 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -52,9 +52,10 @@ declare_clippy_lint! { /// Checks for usage of `std::mem::forget(t)` where `t` is /// `Drop` or has a field that implements `Drop`. /// - /// ### Why is this bad? - /// `std::mem::forget(t)` prevents `t` from running its - /// destructor, possibly causing leaks. + /// ### Why restrict this? + /// `std::mem::forget(t)` prevents `t` from running its destructor, possibly causing leaks. + /// It is not possible to detect all means of creating leaks, but it may be desirable to + /// prohibit the simple ones. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index a6ca7fe9e0b..bb6f9aac223 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -11,7 +11,7 @@ declare_clippy_lint! { /// Checks for usage of if expressions with an `else if` branch, /// but without a final `else` branch. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10). /// /// ### Example diff --git a/clippy_lints/src/empty_drop.rs b/clippy_lints/src/empty_drop.rs index 74db250b3ae..c5fc72b5e2d 100644 --- a/clippy_lints/src/empty_drop.rs +++ b/clippy_lints/src/empty_drop.rs @@ -9,7 +9,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for empty `Drop` implementations. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Empty `Drop` implementations have no effect when dropping an instance of the type. They are /// most likely useless. However, an empty `Drop` implementation prevents a type from being /// destructured, which might be the intention behind adding the implementation as a marker. diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 420888b6ccb..d16714695cb 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -7,32 +7,53 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for `enum`s with no variants. + /// Checks for `enum`s with no variants, which therefore are uninhabited types + /// (cannot be instantiated). /// - /// As of this writing, the `never_type` is still a - /// nightly-only experimental API. Therefore, this lint is only triggered - /// if the `never_type` is enabled. + /// As of this writing, the `never_type` is still a nightly-only experimental API. + /// Therefore, this lint is only triggered if `#![feature(never_type)]` is enabled. /// /// ### Why is this bad? - /// If you want to introduce a type which - /// can't be instantiated, you should use `!` (the primitive type "never"), - /// or a wrapper around it, because `!` has more extensive - /// compiler support (type inference, etc...) and wrappers - /// around it are the conventional way to define an uninhabited type. - /// For further information visit [never type documentation](https://doc.rust-lang.org/std/primitive.never.html) + /// * If you only want a type which can’t be instantiated, you should use [`!`] + /// (the primitive type "never"), because [`!`] has more extensive compiler support + /// (type inference, etc.) and implementations of common traits. /// + /// * If you need to introduce a distinct type, consider using a [newtype] `struct` + /// containing [`!`] instead (`struct MyType(pub !)`), because it is more idiomatic + /// to use a `struct` rather than an `enum` when an `enum` is unnecessary. + /// + /// If you do this, note that the [visibility] of the [`!`] field determines whether + /// the uninhabitedness is visible in documentation, and whether it can be pattern + /// matched to mark code unreachable. If the field is not visible, then the struct + /// acts like any other struct with private fields. + /// + /// * If the enum has no variants only because all variants happen to be + /// [disabled by conditional compilation][cfg], then it would be appropriate + /// to allow the lint, with `#[allow(empty_enum)]`. + /// + /// For further information, visit + /// [the never type’s documentation][`!`]. /// /// ### Example /// ```no_run - /// enum Test {} + /// enum CannotExist {} /// ``` /// /// Use instead: /// ```no_run /// #![feature(never_type)] /// - /// struct Test(!); + /// /// Use the `!` type directly... + /// type CannotExist = !; + /// + /// /// ...or define a newtype which is distinct. + /// struct CannotExist2(pub !); /// ``` + /// + /// [`!`]: https://doc.rust-lang.org/std/primitive.never.html + /// [cfg]: https://doc.rust-lang.org/reference/conditional-compilation.html + /// [newtype]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction + /// [visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html #[clippy::version = "pre 1.29.0"] pub EMPTY_ENUM, pedantic, diff --git a/clippy_lints/src/empty_with_brackets.rs b/clippy_lints/src/empty_with_brackets.rs index 969df6d85b5..745599b0e57 100644 --- a/clippy_lints/src/empty_with_brackets.rs +++ b/clippy_lints/src/empty_with_brackets.rs @@ -11,16 +11,23 @@ declare_clippy_lint! { /// ### What it does /// Finds structs without fields (a so-called "empty struct") that are declared with brackets. /// - /// ### Why is this bad? - /// Empty brackets after a struct declaration can be omitted. + /// ### Why restrict this? + /// Empty brackets after a struct declaration can be omitted, + /// and it may be desirable to do so consistently for style. + /// + /// However, removing the brackets also introduces a public constant named after the struct, + /// so this is not just a syntactic simplification but an an API change, and adding them back + /// is a *breaking* API change. /// /// ### Example /// ```no_run /// struct Cookie {} + /// struct Biscuit(); /// ``` /// Use instead: /// ```no_run /// struct Cookie; + /// struct Biscuit; /// ``` #[clippy::version = "1.62.0"] pub EMPTY_STRUCTS_WITH_BRACKETS, @@ -32,14 +39,20 @@ declare_clippy_lint! { /// ### What it does /// Finds enum variants without fields that are declared with empty brackets. /// - /// ### Why is this bad? - /// Empty brackets while defining enum variants are redundant and can be omitted. + /// ### Why restrict this? + /// Empty brackets after a enum variant declaration are redundant and can be omitted, + /// and it may be desirable to do so consistently for style. + /// + /// However, removing the brackets also introduces a public constant named after the variant, + /// so this is not just a syntactic simplification but an an API change, and adding them back + /// is a *breaking* API change. /// /// ### Example /// ```no_run /// enum MyEnum { /// HasData(u8), - /// HasNoData(), // redundant parentheses + /// HasNoData(), // redundant parentheses + /// NoneHereEither {}, // redundant braces /// } /// ``` /// @@ -48,6 +61,7 @@ declare_clippy_lint! { /// enum MyEnum { /// HasData(u8), /// HasNoData, + /// NoneHereEither, /// } /// ``` #[clippy::version = "1.77.0"] diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index dd03df797de..bb766e96338 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -13,8 +13,9 @@ declare_clippy_lint! { /// ### What it does /// Checks for the usage of the `to_ne_bytes` method and/or the function `from_ne_bytes`. /// - /// ### Why is this bad? - /// It's not, but some may prefer to specify the target endianness explicitly. + /// ### Why restrict this? + /// To ensure use of explicitly chosen endianness rather than the target’s endianness, + /// such as when implementing network protocols or file formats rather than FFI. /// /// ### Example /// ```rust,ignore @@ -31,9 +32,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`. /// - /// ### Why is this bad? - /// It's not, but some may wish to lint usage of this method, either to suggest using the host - /// endianness or big endian. + /// ### Why restrict this? + /// To ensure use of big endian or the target’s endianness rather than little endian. /// /// ### Example /// ```rust,ignore @@ -50,9 +50,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`. /// - /// ### Why is this bad? - /// It's not, but some may wish to lint usage of this method, either to suggest using the host - /// endianness or little endian. + /// ### Why restrict this? + /// To ensure use of little endian or the target’s endianness rather than big endian. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/error_impl_error.rs b/clippy_lints/src/error_impl_error.rs index 8dbb47fadc5..8e49138cd26 100644 --- a/clippy_lints/src/error_impl_error.rs +++ b/clippy_lints/src/error_impl_error.rs @@ -12,7 +12,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for types named `Error` that implement `Error`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// It can become confusing when a codebase has 20 types all named `Error`, requiring either /// aliasing them in the `use` statement or qualifying them like `my_module::Error`. This /// hinders comprehension, as it requires you to memorize every variation of importing `Error` diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 9ffda645742..436dc8611bd 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -10,10 +10,10 @@ declare_clippy_lint! { /// ### What it does /// Warns on any exported `enum`s that are not tagged `#[non_exhaustive]` /// - /// ### Why is this bad? - /// Exhaustive enums are typically fine, but a project which does - /// not wish to make a stability commitment around exported enums may wish to - /// disable them by default. + /// ### Why restrict this? + /// Making an `enum` exhaustive is a stability commitment: adding a variant is a breaking change. + /// A project may wish to ensure that there are no exhaustive enums or that every exhaustive + /// `enum` is explicitly `#[allow]`ed. /// /// ### Example /// ```no_run @@ -40,10 +40,10 @@ declare_clippy_lint! { /// ### What it does /// Warns on any exported `struct`s that are not tagged `#[non_exhaustive]` /// - /// ### Why is this bad? - /// Exhaustive structs are typically fine, but a project which does - /// not wish to make a stability commitment around exported structs may wish to - /// disable them by default. + /// ### Why restrict this? + /// Making a `struct` exhaustive is a stability commitment: adding a field is a breaking change. + /// A project may wish to ensure that there are no exhaustive structs or that every exhaustive + /// `struct` is explicitly `#[allow]`ed. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 106844dd434..91c94d66458 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -9,11 +9,13 @@ declare_clippy_lint! { /// ### What it does /// Detects calls to the `exit()` function which terminates the program. /// - /// ### Why is this bad? - /// Exit terminates the program at the location it is called. For unrecoverable - /// errors `panics` should be used to provide a stacktrace and potentially other - /// information. A normal termination or one with an error code should happen in - /// the main function. + /// ### Why restrict this? + /// `exit()` immediately terminates the program with no information other than an exit code. + /// This provides no means to troubleshoot a problem, and may be an unexpected side effect. + /// + /// Codebases may use this lint to require that all exits are performed either by panicking + /// (which produces a message, a code location, and optionally a backtrace) + /// or by returning from `main()` (which is a single place to look). /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 2cd4e9e99a5..4ec9bd757ff 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -38,9 +38,9 @@ declare_clippy_lint! { /// Checks for whole number float literals that /// cannot be represented as the underlying type without loss. /// - /// ### Why is this bad? - /// Rust will silently lose precision during - /// conversion to a float. + /// ### Why restrict this? + /// If the value was intended to be exact, it will not be. + /// This may be especially surprising when the lost precision is to the left of the decimal point. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index 2b08437d827..a75538dd329 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -11,7 +11,7 @@ declare_clippy_lint! { /// Detects cases where the result of a `format!` call is /// appended to an existing `String`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Introduces an extra, avoidable heap allocation. /// /// ### Known problems diff --git a/clippy_lints/src/functions/misnamed_getters.rs b/clippy_lints/src/functions/misnamed_getters.rs index 7729c556e1f..2cbc4b07234 100644 --- a/clippy_lints/src/functions/misnamed_getters.rs +++ b/clippy_lints/src/functions/misnamed_getters.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, ExprKind, FnDecl, Safety, ImplicitSelfKind}; +use rustc_hir::{Body, ExprKind, FnDecl, ImplicitSelfKind, Safety}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index dfcaac9abef..26534492ddd 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -338,8 +338,10 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Lints when `impl Trait` is being used in a function's parameters. - /// ### Why is this bad? - /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor. + /// + /// ### Why restrict this? + /// Turbofish syntax (`::<>`) cannot be used to specify the type of an `impl Trait` parameter, + /// making `impl Trait` less powerful. Readability may also be a factor. /// /// ### Example /// ```no_run @@ -366,9 +368,8 @@ declare_clippy_lint! { /// Lints when the name of function parameters from trait impl is /// different than its default implementation. /// - /// ### Why is this bad? - /// Using the default name for parameters of a trait method is often - /// more desirable for consistency's sake. + /// ### Why restrict this? + /// Using the default name for parameters of a trait method is more consistent. /// /// ### Example /// ```rust diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index f5ba62ae432..0b200815219 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for if-else that could be written using either `bool::then` or `bool::then_some`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Looks a little redundant. Using `bool::then` is more concise and incurs no loss of clarity. /// For simple calculations and known values, use `bool::then_some`, which is eagerly evaluated /// in comparison to `bool::then`. diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 5288efd8df8..cc342007ec6 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -16,12 +16,13 @@ declare_clippy_lint! { /// ### What it does /// Checks for missing return statements at the end of a block. /// - /// ### Why is this bad? - /// Actually omitting the return keyword is idiomatic Rust code. Programmers - /// coming from other languages might prefer the expressiveness of `return`. It's possible to miss - /// the last returning statement because the only difference is a missing `;`. Especially in bigger - /// code with multiple return paths having a `return` keyword makes it easier to find the - /// corresponding statements. + /// ### Why restrict this? + /// Omitting the return keyword whenever possible is idiomatic Rust code, but: + /// + /// * Programmers coming from other languages might prefer the expressiveness of `return`. + /// * It's possible to miss the last returning statement because the only difference is a missing `;`. + /// * Especially in bigger code with multiple return paths, having a `return` keyword makes it easier to find the + /// corresponding statements. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 35fcd8cdd35..e3e79749bea 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -45,9 +45,10 @@ declare_clippy_lint! { /// does report on arrays if we can tell that slicing operations are in bounds and does not /// lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint. /// - /// ### Why is this bad? - /// Indexing and slicing can panic at runtime and there are - /// safe alternatives. + /// ### Why restrict this? + /// To avoid implicit panics from indexing and slicing. + /// There are “checked” alternatives which do not panic, and can be used with `unwrap()` to make + /// an explicit panic when it is desired. /// /// ### Example /// ```rust,no_run diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 1127f00abde..95ae591884b 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for multiple inherent implementations of a struct /// - /// ### Why is this bad? + /// ### Why restrict this? /// Splitting the implementation of a type makes the code harder to navigate. /// /// ### Example diff --git a/clippy_lints/src/init_numbered_fields.rs b/clippy_lints/src/init_numbered_fields.rs index e486563808a..1c8fd0a27f9 100644 --- a/clippy_lints/src/init_numbered_fields.rs +++ b/clippy_lints/src/init_numbered_fields.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields { snippet_with_applicability(cx, path.span(), "..", &mut appl), expr_spans .into_iter_sorted() - .map(|(_, span)| snippet_with_applicability(cx, span, "..", &mut appl)) + .map(|(_, span)| snippet_with_context(cx, span, path.span().ctxt(), "..", &mut appl).0) .intersperse(Cow::Borrowed(", ")) .collect::() ); diff --git a/clippy_lints/src/integer_division_remainder_used.rs b/clippy_lints/src/integer_division_remainder_used.rs index a3577b765c0..cf598d5045e 100644 --- a/clippy_lints/src/integer_division_remainder_used.rs +++ b/clippy_lints/src/integer_division_remainder_used.rs @@ -7,10 +7,10 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for the usage of division (/) and remainder (%) operations - /// when performed on any integer types using the default Div and Rem trait implementations. + /// Checks for the usage of division (`/`) and remainder (`%`) operations + /// when performed on any integer types using the default `Div` and `Rem` trait implementations. /// - /// ### Why is this bad? + /// ### Why restrict this? /// In cryptographic contexts, division can result in timing sidechannel vulnerabilities, /// and needs to be replaced with constant-time code instead (e.g. Barrett reduction). /// diff --git a/clippy_lints/src/iter_over_hash_type.rs b/clippy_lints/src/iter_over_hash_type.rs index 6c6eff9ba48..fb29d982417 100644 --- a/clippy_lints/src/iter_over_hash_type.rs +++ b/clippy_lints/src/iter_over_hash_type.rs @@ -14,8 +14,8 @@ declare_clippy_lint! { /// ### What it does /// This is a restriction lint which prevents the use of hash types (i.e., `HashSet` and `HashMap`) in for loops. /// - /// ### Why is this bad? - /// Because hash types are unordered, when iterated through such as in a for loop, the values are returned in + /// ### Why restrict this? + /// Because hash types are unordered, when iterated through such as in a `for` loop, the values are returned in /// an undefined order. As a result, on redundant systems this may cause inconsistencies and anomalies. /// In addition, the unknown order of the elements may reduce readability or introduce other undesired /// side effects. diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 790bed580fd..07efee159aa 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -10,10 +10,12 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does /// Checks for the inclusion of large files via `include_bytes!()` - /// and `include_str!()` + /// or `include_str!()`. /// - /// ### Why is this bad? - /// Including large files can increase the size of the binary + /// ### Why restrict this? + /// Including large files can undesirably increase the size of the binary produced by the compiler. + /// This lint may be used to catch mistakes where an unexpectedly large file is included, or + /// temporarily to obtain a list of all large files. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 619e933b4ff..9fd4f509aa4 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -12,9 +12,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for `let _ = ` where expr is `#[must_use]` /// - /// ### Why is this bad? - /// It's better to explicitly handle the value of a `#[must_use]` - /// expr + /// ### Why restrict this? + /// To ensure that all `#[must_use]` types are used rather than ignored. /// /// ### Example /// ```no_run @@ -96,8 +95,8 @@ declare_clippy_lint! { /// Checks for `let _ = ` without a type annotation, and suggests to either provide one, /// or remove the `let` keyword altogether. /// - /// ### Why is this bad? - /// The `let _ = ` expression ignores the value of `` but will remain doing so even + /// ### Why restrict this? + /// The `let _ = ` expression ignores the value of ``, but will continue to do so even /// if the type were to change, thus potentially introducing subtle bugs. By supplying a type /// annotation, one will be forced to re-visit the decision to ignore the value in such cases. /// diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 2348dd18220..d2a140a36a8 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -132,8 +132,8 @@ declare_clippy_lint! { /// ### What it does /// Warns if there is a better representation for a numeric literal. /// - /// ### Why is this bad? - /// Especially for big powers of 2 a hexadecimal representation is more + /// ### Why restrict this? + /// Especially for big powers of 2, a hexadecimal representation is usually more /// readable than a decimal representation. /// /// ### Example diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 3dcb050d77e..08682942153 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -675,9 +675,9 @@ declare_clippy_lint! { /// Checks for infinite loops in a function where the return type is not `!` /// and lint accordingly. /// - /// ### Why is this bad? - /// A loop should be gently exited somewhere, or at least mark its parent function as - /// never return (`!`). + /// ### Why restrict this? + /// Making the return type `!` serves as documentation that the function does not return. + /// If the function is not intended to loop infinitely, then this lint may detect a bug. /// /// ### Example /// ```no_run,ignore diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index ee9f48d71ad..691ecd57535 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -260,7 +260,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for wildcard enum matches using `_`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// New enum variants added by library updates can be missed. /// /// ### Known problems @@ -435,7 +435,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Correctness and readability. It's like having a wildcard pattern after /// matching all enum variants explicitly. /// @@ -861,7 +861,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `Err(x)?`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// The `?` operator is designed to allow calls that /// can fail to be easily chained. For example, `foo()?.bar()` or /// `foo(bar()?)`. Because `Err(x)?` can't be used that way (it will diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 6ac0705abb2..2f72e59834f 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -1,12 +1,17 @@ +use std::ops::ControlFlow; + use crate::FxHashSet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{indent_of, snippet}; +use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy}; use clippy_utils::{get_attr, is_lint_allowed}; +use itertools::Itertools; +use rustc_ast::Mutability; use rustc_errors::{Applicability, Diag}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::ty::{GenericArgKind, Ty}; +use rustc_middle::ty::{GenericArgKind, Region, RegionKind, Ty, TyCtxt, TypeVisitable, TypeVisitor}; use rustc_span::Span; use super::SIGNIFICANT_DROP_IN_SCRUTINEE; @@ -22,43 +27,34 @@ pub(super) fn check<'tcx>( return; } - if let Some((suggestions, message)) = has_significant_drop_in_scrutinee(cx, scrutinee, source) { - for found in suggestions { - span_lint_and_then(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, found.found_span, message, |diag| { - set_diagnostic(diag, cx, expr, found); - let s = Span::new(expr.span.hi(), expr.span.hi(), expr.span.ctxt(), None); - diag.span_label(s, "temporary lives until here"); - for span in has_significant_drop_in_arms(cx, arms) { - diag.span_label(span, "another value with significant `Drop` created here"); - } - diag.note("this might lead to deadlocks or other unexpected behavior"); - }); - } + let (suggestions, message) = has_significant_drop_in_scrutinee(cx, scrutinee, source); + for found in suggestions { + span_lint_and_then(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, found.found_span, message, |diag| { + set_diagnostic(diag, cx, expr, found); + let s = Span::new(expr.span.hi(), expr.span.hi(), expr.span.ctxt(), None); + diag.span_label(s, "temporary lives until here"); + for span in has_significant_drop_in_arms(cx, arms) { + diag.span_label(span, "another value with significant `Drop` created here"); + } + diag.note("this might lead to deadlocks or other unexpected behavior"); + }); } } fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) { - if found.lint_suggestion == LintSuggestion::MoveAndClone { - // If our suggestion is to move and clone, then we want to leave it to the user to - // decide how to address this lint, since it may be that cloning is inappropriate. - // Therefore, we won't to emit a suggestion. - return; - } - let original = snippet(cx, found.found_span, ".."); let trailing_indent = " ".repeat(indent_of(cx, found.found_span).unwrap_or(0)); - let replacement = if found.lint_suggestion == LintSuggestion::MoveAndDerefToCopy { - format!("let value = *{original};\n{trailing_indent}") - } else if found.is_unit_return_val { - // If the return value of the expression to be moved is unit, then we don't need to - // capture the result in a temporary -- we can just replace it completely with `()`. - format!("{original};\n{trailing_indent}") - } else { - format!("let value = {original};\n{trailing_indent}") + let replacement = { + let (def_part, deref_part) = if found.is_unit_return_val { + ("", String::new()) + } else { + ("let value = ", "*".repeat(found.peel_ref_times)) + }; + format!("{def_part}{deref_part}{original};\n{trailing_indent}") }; - let suggestion_message = if found.lint_suggestion == LintSuggestion::MoveOnly { + let suggestion_message = if found.peel_ref_times == 0 { "try moving the temporary above the match" } else { "try moving the temporary above the match and create a copy" @@ -66,8 +62,11 @@ fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: & let scrutinee_replacement = if found.is_unit_return_val { "()".to_owned() - } else { + } else if found.peel_ref_times == 0 { "value".to_owned() + } else { + let ref_part = "&".repeat(found.peel_ref_times); + format!("({ref_part}value)") }; diag.multipart_suggestion( @@ -86,20 +85,18 @@ fn has_significant_drop_in_scrutinee<'tcx>( cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>, source: MatchSource, -) -> Option<(Vec, &'static str)> { +) -> (Vec, &'static str) { let mut helper = SigDropHelper::new(cx); let scrutinee = match (source, &scrutinee.kind) { (MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e, _ => scrutinee, }; - helper.find_sig_drop(scrutinee).map(|drops| { - let message = if source == MatchSource::Normal { - "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression" - } else { - "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression" - }; - (drops, message) - }) + let message = if source == MatchSource::Normal { + "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression" + } else { + "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression" + }; + (helper.find_sig_drop(scrutinee), message) } struct SigDropChecker<'a, 'tcx> { @@ -172,205 +169,248 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> { } } +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +enum SigDropHolder { + /// No values with significant drop present in this expression. + /// + /// Expressions that we've emited lints do not count. + None, + /// Some field in this expression references to values with significant drop. + /// + /// Example: `(1, &data.lock().field)`. + PackedRef, + /// The value of this expression references to values with significant drop. + /// + /// Example: `data.lock().field`. + DirectRef, + /// This expression should be moved out to avoid significant drop in scrutinee. + Moved, +} + +impl Default for SigDropHolder { + fn default() -> Self { + Self::None + } +} + struct SigDropHelper<'a, 'tcx> { cx: &'a LateContext<'tcx>, - is_chain_end: bool, - has_significant_drop: bool, - current_sig_drop: Option, - sig_drop_spans: Option>, - special_handling_for_binary_op: bool, + parent_expr: Option<&'tcx Expr<'tcx>>, + sig_drop_holder: SigDropHolder, + sig_drop_spans: Vec, sig_drop_checker: SigDropChecker<'a, 'tcx>, } -#[expect(clippy::enum_variant_names)] -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -enum LintSuggestion { - MoveOnly, - MoveAndDerefToCopy, - MoveAndClone, -} - -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] struct FoundSigDrop { found_span: Span, is_unit_return_val: bool, - lint_suggestion: LintSuggestion, + peel_ref_times: usize, } impl<'a, 'tcx> SigDropHelper<'a, 'tcx> { fn new(cx: &'a LateContext<'tcx>) -> SigDropHelper<'a, 'tcx> { SigDropHelper { cx, - is_chain_end: true, - has_significant_drop: false, - current_sig_drop: None, - sig_drop_spans: None, - special_handling_for_binary_op: false, + parent_expr: None, + sig_drop_holder: SigDropHolder::None, + sig_drop_spans: Vec::new(), sig_drop_checker: SigDropChecker::new(cx), } } - fn find_sig_drop(&mut self, match_expr: &'tcx Expr<'_>) -> Option> { + fn find_sig_drop(&mut self, match_expr: &'tcx Expr<'_>) -> Vec { self.visit_expr(match_expr); - // If sig drop spans is empty but we found a significant drop, it means that we didn't find - // a type that was trivially copyable as we moved up the chain after finding a significant - // drop, so move the entire scrutinee. - if self.has_significant_drop && self.sig_drop_spans.is_none() { - self.try_setting_current_suggestion(match_expr, true); - self.move_current_suggestion(); - } - - self.sig_drop_spans.take() + core::mem::take(&mut self.sig_drop_spans) } - fn replace_current_sig_drop( - &mut self, - found_span: Span, - is_unit_return_val: bool, - lint_suggestion: LintSuggestion, - ) { - self.current_sig_drop.replace(FoundSigDrop { + fn replace_current_sig_drop(&mut self, found_span: Span, is_unit_return_val: bool, peel_ref_times: usize) { + self.sig_drop_spans.clear(); + self.sig_drop_spans.push(FoundSigDrop { found_span, is_unit_return_val, - lint_suggestion, + peel_ref_times, }); } - /// This will try to set the current suggestion (so it can be moved into the suggestions vec - /// later). If `allow_move_and_clone` is false, the suggestion *won't* be set -- this gives us - /// an opportunity to look for another type in the chain that will be trivially copyable. - /// However, if we are at the end of the chain, we want to accept whatever is there. (The - /// suggestion won't actually be output, but the diagnostic message will be output, so the user - /// can determine the best way to handle the lint.) - fn try_setting_current_suggestion(&mut self, expr: &'tcx Expr<'_>, allow_move_and_clone: bool) { - if self.current_sig_drop.is_some() { - return; + fn try_move_sig_drop(&mut self, expr: &'tcx Expr<'_>, parent_expr: &'tcx Expr<'_>) { + if self.sig_drop_holder == SigDropHolder::Moved { + self.sig_drop_holder = SigDropHolder::None; } - let ty = self.cx.typeck_results().expr_ty(expr); - if ty.is_ref() { - // We checked that the type was ref, so builtin_deref will return Some, - // but let's avoid any chance of an ICE. - if let Some(ty) = ty.builtin_deref(true) { - if ty.is_trivially_pure_clone_copy() { - self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndDerefToCopy); - } else if allow_move_and_clone { - self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndClone); - } + + if self.sig_drop_holder == SigDropHolder::DirectRef { + self.sig_drop_holder = SigDropHolder::PackedRef; + self.try_move_sig_drop_direct_ref(expr, parent_expr); + } else if self.sig_drop_checker.is_sig_drop_expr(expr) { + // The values with significant drop can be moved to some other functions. For example, consider + // `drop(data.lock())`. We use `SigDropHolder::None` here to avoid emitting lints in such scenarios. + self.sig_drop_holder = SigDropHolder::None; + self.try_move_sig_drop_direct_ref(expr, parent_expr); + } + + if self.sig_drop_holder != SigDropHolder::None { + let parent_ty = self.cx.typeck_results().expr_ty(parent_expr); + if !ty_has_erased_regions(parent_ty) && !parent_expr.is_syntactic_place_expr() { + self.replace_current_sig_drop(parent_expr.span, parent_ty.is_unit(), 0); + self.sig_drop_holder = SigDropHolder::Moved; + } + + let (peel_ref_ty, peel_ref_times) = ty_peel_refs(parent_ty); + if !ty_has_erased_regions(peel_ref_ty) && is_copy(self.cx, peel_ref_ty) { + self.replace_current_sig_drop(parent_expr.span, peel_ref_ty.is_unit(), peel_ref_times); + self.sig_drop_holder = SigDropHolder::Moved; } - } else if ty.is_trivially_pure_clone_copy() { - self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveOnly); - } else if allow_move_and_clone { - self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndClone); } } - fn move_current_suggestion(&mut self) { - if let Some(current) = self.current_sig_drop.take() { - self.sig_drop_spans.get_or_insert_with(Vec::new).push(current); + fn try_move_sig_drop_direct_ref(&mut self, expr: &'tcx Expr<'_>, parent_expr: &'tcx Expr<'_>) { + let arg_idx = match parent_expr.kind { + ExprKind::MethodCall(_, receiver, exprs, _) => std::iter::once(receiver) + .chain(exprs.iter()) + .find_position(|ex| ex.hir_id == expr.hir_id) + .map(|(idx, _)| idx), + ExprKind::Call(_, exprs) => exprs + .iter() + .find_position(|ex| ex.hir_id == expr.hir_id) + .map(|(idx, _)| idx), + ExprKind::Binary(_, lhs, rhs) | ExprKind::AssignOp(_, lhs, rhs) => [lhs, rhs] + .iter() + .find_position(|ex| ex.hir_id == expr.hir_id) + .map(|(idx, _)| idx), + ExprKind::Unary(_, ex) => (ex.hir_id == expr.hir_id).then_some(0), + _ => { + // Here we assume that all other expressions create or propagate the reference to the value with + // significant drop. + self.sig_drop_holder = SigDropHolder::DirectRef; + return; + }, + }; + let Some(arg_idx) = arg_idx else { + return; + }; + + let fn_sig = if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(parent_expr.hir_id) { + self.cx.tcx.fn_sig(def_id).instantiate_identity() + } else { + return; + }; + + let input_re = if let Some(input_ty) = fn_sig.skip_binder().inputs().get(arg_idx) + && let rustc_middle::ty::Ref(input_re, _, _) = input_ty.kind() + { + input_re + } else { + return; + }; + + // Late bound lifetime parameters are not related to any constraints, so we can track them in a very + // simple manner. For other lifetime parameters, we give up and update the state to `PackedRef`. + let RegionKind::ReBound(_, input_re_bound) = input_re.kind() else { + self.sig_drop_holder = SigDropHolder::PackedRef; + return; + }; + let contains_input_re = |re_bound| { + if re_bound == input_re_bound { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }; + + let output_ty = fn_sig.skip_binder().output(); + if let rustc_middle::ty::Ref(output_re, peel_ref_ty, _) = output_ty.kind() + && input_re == output_re + && for_each_top_level_late_bound_region(*peel_ref_ty, contains_input_re).is_continue() + { + // We're lucky! The output type is still a direct reference to the value with significant drop. + self.sig_drop_holder = SigDropHolder::DirectRef; + } else if for_each_top_level_late_bound_region(output_ty, contains_input_re).is_continue() { + // The lifetime to the value with significant drop goes away. So we can emit a lint that suggests to + // move the expression out. + self.replace_current_sig_drop(parent_expr.span, output_ty.is_unit(), 0); + self.sig_drop_holder = SigDropHolder::Moved; + } else { + // TODO: The lifetime is still there but it's for a inner type. For instance, consider + // `Some(&mutex.lock().field)`, which has a type of `Option<&u32>`. How to address this scenario? + self.sig_drop_holder = SigDropHolder::PackedRef; } } +} - fn visit_exprs_for_binary_ops( - &mut self, - left: &'tcx Expr<'_>, - right: &'tcx Expr<'_>, - is_unit_return_val: bool, - span: Span, - ) { - self.special_handling_for_binary_op = true; - self.visit_expr(left); - self.visit_expr(right); - - // If either side had a significant drop, suggest moving the entire scrutinee to avoid - // unnecessary copies and to simplify cases where both sides have significant drops. - if self.has_significant_drop { - self.replace_current_sig_drop(span, is_unit_return_val, LintSuggestion::MoveOnly); - } +fn ty_peel_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { + let mut n = 0; + while let rustc_middle::ty::Ref(_, new_ty, Mutability::Not) = ty.kind() { + ty = *new_ty; + n += 1; + } + (ty, n) +} + +fn ty_has_erased_regions(ty: Ty<'_>) -> bool { + struct V; - self.special_handling_for_binary_op = false; + impl<'tcx> TypeVisitor> for V { + type Result = ControlFlow<()>; + + fn visit_region(&mut self, region: Region<'tcx>) -> Self::Result { + if region.is_erased() { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + } } + + ty.visit_with(&mut V).is_break() } impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { - if !self.is_chain_end && self.sig_drop_checker.is_sig_drop_expr(ex) { - self.has_significant_drop = true; + // We've emited a lint on some neighborhood expression. That lint will suggest to move out the + // _parent_ expression (not the expression itself). Since we decide to move out the parent + // expression, it is pointless to continue to process the current expression. + if self.sig_drop_holder == SigDropHolder::Moved { return; } - self.is_chain_end = false; + + // These states are of neighborhood expressions. We save and clear them here, and we'll later merge + // the states of the current expression with them at the end of the method. + let sig_drop_holder_before = core::mem::take(&mut self.sig_drop_holder); + let sig_drop_spans_before = core::mem::take(&mut self.sig_drop_spans); + let parent_expr_before = self.parent_expr.replace(ex); match ex.kind { - ExprKind::MethodCall(_, expr, ..) => { - self.visit_expr(expr); - } - ExprKind::Binary(_, left, right) => { - self.visit_exprs_for_binary_ops(left, right, false, ex.span); - } - ExprKind::Assign(left, right, _) | ExprKind::AssignOp(_, left, right) => { - self.visit_exprs_for_binary_ops(left, right, true, ex.span); - } - ExprKind::Tup(exprs) => { - for expr in exprs { - self.visit_expr(expr); - if self.has_significant_drop { - // We may have not have set current_sig_drop if all the suggestions were - // MoveAndClone, so add this tuple item's full expression in that case. - if self.current_sig_drop.is_none() { - self.try_setting_current_suggestion(expr, true); - } - - // Now we are guaranteed to have something, so add it to the final vec. - self.move_current_suggestion(); - } - // Reset `has_significant_drop` after each tuple expression so we can look for - // additional cases. - self.has_significant_drop = false; - } - if self.sig_drop_spans.is_some() { - self.has_significant_drop = true; - } - } - ExprKind::Array(..) | - ExprKind::Call(..) | - ExprKind::Unary(..) | - ExprKind::If(..) | - ExprKind::Match(..) | - ExprKind::Field(..) | - ExprKind::Index(..) | - ExprKind::Ret(..) | - ExprKind::Become(..) | - ExprKind::Repeat(..) | - ExprKind::Yield(..) => walk_expr(self, ex), - ExprKind::AddrOf(_, _, _) | - ExprKind::Block(_, _) | - ExprKind::Break(_, _) | - ExprKind::Cast(_, _) | - // Don't want to check the closure itself, only invocation, which is covered by MethodCall - ExprKind::Closure { .. } | - ExprKind::ConstBlock(_) | - ExprKind::Continue(_) | - ExprKind::DropTemps(_) | - ExprKind::Err(_) | - ExprKind::InlineAsm(_) | - ExprKind::OffsetOf(_, _) | - ExprKind::Let(_) | - ExprKind::Lit(_) | - ExprKind::Loop(_, _, _, _) | - ExprKind::Path(_) | - ExprKind::Struct(_, _, _) | - ExprKind::Type(_, _) => { - return; + // Skip blocks because values in blocks will be dropped as usual. + ExprKind::Block(..) => (), + _ => walk_expr(self, ex), + } + + if let Some(parent_ex) = parent_expr_before { + match parent_ex.kind { + ExprKind::Assign(lhs, _, _) | ExprKind::AssignOp(_, lhs, _) + if lhs.hir_id == ex.hir_id && self.sig_drop_holder == SigDropHolder::Moved => + { + // Never move out only the assignee. Instead, we should always move out the whole assigment. + self.replace_current_sig_drop(parent_ex.span, true, 0); + }, + _ => { + self.try_move_sig_drop(ex, parent_ex); + }, } } - // Once a significant temporary has been found, we need to go back up at least 1 level to - // find the span to extract for replacement, so the temporary gets dropped. However, for - // binary ops, we want to move the whole scrutinee so we avoid unnecessary copies and to - // simplify cases where both sides have significant drops. - if self.has_significant_drop && !self.special_handling_for_binary_op { - self.try_setting_current_suggestion(ex, false); + self.sig_drop_holder = std::cmp::max(self.sig_drop_holder, sig_drop_holder_before); + + // We do not need those old spans in neighborhood expressions if we emit a lint that suggests to + // move out the _parent_ expression (i.e., `self.sig_drop_holder == SigDropHolder::Moved`). + if self.sig_drop_holder != SigDropHolder::Moved { + let mut sig_drop_spans = sig_drop_spans_before; + sig_drop_spans.append(&mut self.sig_drop_spans); + self.sig_drop_spans = sig_drop_spans; } + + self.parent_expr = parent_expr_before; } } diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 6c9bdcff826..f4397212cf6 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -1,8 +1,12 @@ +use std::iter::once; + use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core}; use rustc_errors::Applicability; +use rustc_hir::def_id::DefId; +use rustc_hir::hir_id::HirId; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; @@ -25,7 +29,29 @@ impl IterType { } } -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { +fn is_arg_ty_unified_in_fn<'tcx>( + cx: &LateContext<'tcx>, + fn_id: DefId, + arg_id: HirId, + args: impl IntoIterator>, +) -> bool { + let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity(); + let arg_id_in_args = args.into_iter().position(|e| e.hir_id == arg_id).unwrap(); + let arg_ty_in_args = fn_sig.input(arg_id_in_args).skip_binder(); + + cx.tcx.predicates_of(fn_id).predicates.iter().any(|(clause, _)| { + clause + .as_projection_clause() + .and_then(|p| p.map_bound(|p| p.term.ty()).transpose()) + .is_some_and(|ty| ty.skip_binder() == arg_ty_in_args) + }) || fn_sig + .inputs() + .iter() + .enumerate() + .any(|(i, ty)| i != arg_id_in_args && ty.skip_binder().walk().any(|arg| arg.as_type() == Some(arg_ty_in_args))) +} + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: &str, recv: &'tcx Expr<'tcx>) { let item = match recv.kind { ExprKind::Array([]) => None, ExprKind::Array([e]) => Some(e), @@ -43,6 +69,25 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re let is_unified = match get_expr_use_or_unification_node(cx.tcx, expr) { Some((Node::Expr(parent), child_id)) => match parent.kind { ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id == child_id => false, + ExprKind::Call( + Expr { + kind: ExprKind::Path(path), + hir_id, + .. + }, + args, + ) => cx + .typeck_results() + .qpath_res(path, *hir_id) + .opt_def_id() + .filter(|fn_id| cx.tcx.def_kind(fn_id).is_fn_like()) + .is_some_and(|fn_id| is_arg_ty_unified_in_fn(cx, fn_id, child_id, args)), + ExprKind::MethodCall(_name, recv, args, _span) => is_arg_ty_unified_in_fn( + cx, + cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(), + child_id, + once(recv).chain(args.iter()), + ), ExprKind::If(_, _, _) | ExprKind::Match(_, _, _) | ExprKind::Closure(_) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9d67aa23379..75a86c0c834 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -257,7 +257,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s. /// - /// ### Why is this bad? + /// ### Why restrict this? /// It is better to handle the `None` or `Err` case, /// or at least call `.expect(_)` with a more helpful message. Still, for a lot of /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is @@ -333,7 +333,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Usually it is better to handle the `None` or `Err` case. /// Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why /// this lint is `Allow` by default. @@ -1029,8 +1029,8 @@ declare_clippy_lint! { /// (`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified /// function syntax instead (e.g., `Rc::clone(foo)`). /// - /// ### Why is this bad? - /// Calling '.clone()' on an Rc, Arc, or Weak + /// ### Why restrict this? + /// Calling `.clone()` on an `Rc`, `Arc`, or `Weak` /// can obscure the fact that only the pointer is being cloned, not the underlying /// data. /// @@ -1051,7 +1051,7 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub CLONE_ON_REF_PTR, restriction, - "using 'clone' on a ref-counted pointer" + "using `clone` on a ref-counted pointer" } declare_clippy_lint! { @@ -1359,7 +1359,7 @@ declare_clippy_lint! { /// Checks for usage of `.get().unwrap()` (or /// `.get_mut().unwrap`) on a standard library type which implements `Index` /// - /// ### Why is this bad? + /// ### Why restrict this? /// Using the Index trait (`[]`) is more clear and more /// concise. /// @@ -1743,7 +1743,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `FileType::is_file()`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// When people testing a file type with `FileType::is_file` /// they are testing whether a path is something they can get bytes from. But /// `is_file` doesn't cover special file types in unix-like systems, and doesn't cover @@ -2688,8 +2688,9 @@ declare_clippy_lint! { /// ### What it does /// Checks for instances of `map_err(|_| Some::Enum)` /// - /// ### Why is this bad? - /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error + /// ### Why restrict this? + /// This `map_err` throws away the original error rather than allowing the enum to + /// contain and report the cause of the error. /// /// ### Example /// Before: @@ -3145,7 +3146,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of File::read_to_end and File::read_to_string. /// - /// ### Why is this bad? + /// ### Why restrict this? /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html) /// diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 7431dc1cf0b..d1300dd43c2 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -38,7 +38,7 @@ pub fn check_for_loop_iter( ) -> bool { if let Some(grandparent) = get_parent_expr(cx, expr).and_then(|parent| get_parent_expr(cx, parent)) && let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent) - && let (clone_or_copy_needed, addr_of_exprs) = clone_or_copy_needed(cx, pat, body) + && let (clone_or_copy_needed, references_to_binding) = clone_or_copy_needed(cx, pat, body) && !clone_or_copy_needed && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) { @@ -123,14 +123,12 @@ pub fn check_for_loop_iter( Applicability::MachineApplicable }; diag.span_suggestion(expr.span, "use", snippet, applicability); - for addr_of_expr in addr_of_exprs { - match addr_of_expr.kind { - ExprKind::AddrOf(_, _, referent) => { - let span = addr_of_expr.span.with_hi(referent.span.lo()); - diag.span_suggestion(span, "remove this `&`", "", applicability); - }, - _ => unreachable!(), - } + if !references_to_binding.is_empty() { + diag.multipart_suggestion( + "remove any references to the binding", + references_to_binding, + applicability, + ); } }, ); diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 34d7b9acbe4..1a55b7160fb 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -9,6 +9,7 @@ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::sym; +use rustc_span::Span; pub(super) fn derefs_to_slice<'tcx>( cx: &LateContext<'tcx>, @@ -96,15 +97,15 @@ pub(super) fn clone_or_copy_needed<'tcx>( cx: &LateContext<'tcx>, pat: &Pat<'tcx>, body: &'tcx Expr<'tcx>, -) -> (bool, Vec<&'tcx Expr<'tcx>>) { +) -> (bool, Vec<(Span, String)>) { let mut visitor = CloneOrCopyVisitor { cx, binding_hir_ids: pat_bindings(pat), clone_or_copy_needed: false, - addr_of_exprs: Vec::new(), + references_to_binding: Vec::new(), }; visitor.visit_expr(body); - (visitor.clone_or_copy_needed, visitor.addr_of_exprs) + (visitor.clone_or_copy_needed, visitor.references_to_binding) } /// Returns a vector of all `HirId`s bound by the pattern. @@ -127,7 +128,7 @@ struct CloneOrCopyVisitor<'cx, 'tcx> { cx: &'cx LateContext<'tcx>, binding_hir_ids: Vec, clone_or_copy_needed: bool, - addr_of_exprs: Vec<&'tcx Expr<'tcx>>, + references_to_binding: Vec<(Span, String)>, } impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { @@ -142,8 +143,11 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { if self.is_binding(expr) { if let Some(parent) = get_parent_expr(self.cx, expr) { match parent.kind { - ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) => { - self.addr_of_exprs.push(parent); + ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, referent) => { + if !parent.span.from_expansion() { + self.references_to_binding + .push((parent.span.until(referent.span), String::new())); + } return; }, ExprKind::MethodCall(.., args, _) => { diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs index c6b7f5b0ce2..e43b712021a 100644 --- a/clippy_lints/src/min_ident_chars.rs +++ b/clippy_lints/src/min_ident_chars.rs @@ -12,14 +12,13 @@ use std::borrow::Cow; declare_clippy_lint! { /// ### What it does - /// Checks for idents which comprise of a single letter. + /// Checks for identifiers which consist of a single character (or fewer than the configured threshold). /// /// Note: This lint can be very noisy when enabled; it may be desirable to only enable it /// temporarily. /// - /// ### Why is this bad? - /// In many cases it's not, but at times it can severely hinder readability. Some codebases may - /// wish to disallow this to improve readability. + /// ### Why restrict this? + /// To improve readability by requiring that every variable has a name more specific than a single letter can be. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index 2f5499d7656..fedcfd11fdc 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for structure field patterns bound to wildcards. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Using `..` instead is shorter and leaves the focus on /// the fields that are actually bound. /// @@ -138,7 +138,7 @@ declare_clippy_lint! { /// To enforce unseparated literal suffix style, /// see the `separated_literal_suffix` lint. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Suffix style should be consistent. /// /// ### Example @@ -166,7 +166,7 @@ declare_clippy_lint! { /// To enforce separated literal suffix style, /// see the `unseparated_literal_suffix` lint. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Suffix style should be consistent. /// /// ### Example diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index 04df7b7a7e5..dd98352da86 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -10,7 +10,7 @@ declare_clippy_lint! { /// ### What it does /// Checks assertions without a custom panic message. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Without a good custom message, it'd be hard to understand what went wrong when the assertion fails. /// A good custom message should be more about why the failure of the assertion is problematic /// and not what is failed because the assertion already conveys that. diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index c29e46b941c..752723a0c68 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// Checks for repeated slice indexing without asserting beforehand that the length /// is greater than the largest index used to index into the slice. /// - /// ### Why is this bad? + /// ### Why restrict this? /// In the general case where the compiler does not have a lot of information /// about the length of a slice, indexing it repeatedly will generate a bounds check /// for every single index. diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 2fb784dae1c..ca344dc5c81 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -20,9 +20,9 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// Warns if there is missing doc for any private documentable item + /// Warns if there is missing documentation for any private documentable item. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Doc is good. *rustc* has a `MISSING_DOCS` /// allowed-by-default lint for /// public members, but has no way to enforce documentation of private items. diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index c6a76478806..33a14d8b7fe 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -10,13 +10,16 @@ declare_clippy_lint! { /// It lints if an exported function, method, trait method with default impl, /// or trait method impl is not `#[inline]`. /// - /// ### Why is this bad? - /// In general, it is not. Functions can be inlined across - /// crates when that's profitable as long as any form of LTO is used. When LTO is disabled, - /// functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates - /// might intend for most of the methods in their public API to be able to be inlined across - /// crates even when LTO is disabled. For these types of crates, enabling this lint might make - /// sense. It allows the crate to require all exported methods to be `#[inline]` by default, and + /// ### Why restrict this? + /// When a function is not marked `#[inline]`, it is not + /// [a “small” candidate for automatic inlining][small], and LTO is not in use, then it is not + /// possible for the function to be inlined into the code of any crate other than the one in + /// which it is defined. Depending on the role of the function and the relationship of the crates, + /// this could significantly reduce performance. + /// + /// Certain types of crates might intend for most of the methods in their public API to be able + /// to be inlined across crates even when LTO is disabled. + /// This lint allows those crates to require all exported methods to be `#[inline]` by default, and /// then opt out for specific methods where this might not make sense. /// /// ### Example @@ -51,6 +54,8 @@ declare_clippy_lint! { /// fn def_bar() {} // missing #[inline] /// } /// ``` + /// + /// [small]: https://github.com/rust-lang/rust/pull/116505 #[clippy::version = "pre 1.29.0"] pub MISSING_INLINE_IN_PUBLIC_ITEMS, restriction, diff --git a/clippy_lints/src/missing_trait_methods.rs b/clippy_lints/src/missing_trait_methods.rs index 6f844bc646a..85029a5e6a0 100644 --- a/clippy_lints/src/missing_trait_methods.rs +++ b/clippy_lints/src/missing_trait_methods.rs @@ -10,16 +10,16 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does /// Checks if a provided method is used implicitly by a trait - /// implementation. A usage example would be a wrapper where every method - /// should perform some operation before delegating to the inner type's /// implementation. /// + /// ### Why restrict this? + /// To ensure that a certain implementation implements every method; for example, + /// a wrapper type where every method should delegate to the corresponding method of + /// the inner type's implementation. + /// /// This lint should typically be enabled on a specific trait `impl` item /// rather than globally. /// - /// ### Why is this bad? - /// Indicates that a method is missing. - /// /// ### Example /// ```no_run /// trait Trait { diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 181351910db..9c5a8a0cfcd 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -12,9 +12,10 @@ declare_clippy_lint! { /// whether the read occurs before or after the write depends on the evaluation /// order of sub-expressions. /// - /// ### Why is this bad? - /// It is often confusing to read. As described [here](https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands), - /// the operands of these expressions are evaluated before applying the effects of the expression. + /// ### Why restrict this? + /// While [the evaluation order of sub-expressions] is fully specified in Rust, + /// it still may be confusing to read an expression where the evaluation order + /// affects its behavior. /// /// ### Known problems /// Code which intentionally depends on the evaluation @@ -40,6 +41,8 @@ declare_clippy_lint! { /// }; /// let a = tmp + x; /// ``` + /// + /// [order]: (https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands) #[clippy::version = "pre 1.29.0"] pub MIXED_READ_WRITE_IN_EXPRESSION, restriction, diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index 6c031c08175..305499f9da4 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -10,9 +10,9 @@ use std::path::{Component, Path}; declare_clippy_lint! { /// ### What it does - /// Checks that module layout uses only self named module files, bans `mod.rs` files. + /// Checks that module layout uses only self named module files; bans `mod.rs` files. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Having multiple module layout styles in a project can be confusing. /// /// ### Example @@ -41,7 +41,7 @@ declare_clippy_lint! { /// ### What it does /// Checks that module layout uses only `mod.rs` files. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Having multiple module layout styles in a project can be confusing. /// /// ### Example diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 5306205aed7..5b4ef852f0d 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::visitors::{for_each_expr_with_closures, Descend, Visitable}; use core::ops::ControlFlow::Continue; use hir::def::{DefKind, Res}; -use hir::{BlockCheckMode, ExprKind, Safety, QPath, UnOp}; +use hir::{BlockCheckMode, ExprKind, QPath, Safety, UnOp}; use rustc_ast::Mutability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -15,7 +15,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `unsafe` blocks that contain more than one unsafe operation. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Combined with `undocumented_unsafe_blocks`, /// this lint ensures that each unsafe operation must be independently justified. /// Combined with `unused_unsafe`, this lint also ensures diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 7ecc8617694..853e476a006 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `Mutex` where an atomic will do. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Using a mutex just to make access to a plain bool or /// reference sequential is shooting flies with cannons. /// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index f9ee4a3dc93..e1866eaa18a 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -6,8 +6,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{ - higher, is_else_clause, is_expn_of, is_parent_stmt, peel_blocks, peel_blocks_with_stmt, span_extract_comment, - SpanlessEq, + higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, peel_blocks, peel_blocks_with_stmt, + span_extract_comment, SpanlessEq, }; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -121,14 +121,7 @@ fn condition_needs_parentheses(e: &Expr<'_>) -> bool { | ExprKind::Type(i, _) | ExprKind::Index(i, _, _) = inner.kind { - if matches!( - i.kind, - ExprKind::Block(..) - | ExprKind::ConstBlock(..) - | ExprKind::If(..) - | ExprKind::Loop(..) - | ExprKind::Match(..) - ) { + if is_block_like(i) { return true; } inner = i; diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 7b26235291a..eacfe9ff328 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -98,6 +98,10 @@ struct SimilarNamesLocalVisitor<'a, 'tcx> { impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> { fn check_single_char_names(&self) { + if self.single_char_names.last().map(Vec::len) == Some(0) { + return; + } + let num_single_char_names = self.single_char_names.iter().flatten().count(); let threshold = self.lint.single_char_binding_names_threshold; if num_single_char_names as u64 > threshold { diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index e002429e3a4..0948973df5a 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -70,7 +70,7 @@ declare_clippy_lint! { /// Known safe built-in types like `Wrapping` or `Saturating`, floats, operations in constant /// environments, allowed types and non-constant operations that won't overflow are ignored. /// - /// ### Why is this bad? + /// ### Why restrict this? /// For integers, overflow will trigger a panic in debug builds or wrap the result in /// release mode; division by zero will cause a panic in either mode. As a result, it is /// desirable to explicitly call checked, wrapping or saturating arithmetic methods. @@ -100,7 +100,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for float arithmetic. /// - /// ### Why is this bad? + /// ### Why restrict this? /// For some embedded systems or kernel development, it /// can be useful to rule out floating-point numbers. /// @@ -502,7 +502,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for division of integers /// - /// ### Why is this bad? + /// ### Why restrict this? /// When outside of some very specific algorithms, /// integer division is very often a mistake because it discards the /// remainder. @@ -596,7 +596,7 @@ declare_clippy_lint! { /// value and constant, except in functions called `*eq*` (which probably /// implement equality for a type involving floats). /// - /// ### Why is this bad? + /// ### Why restrict this? /// Floating point calculations are usually imprecise, so /// asking if two values are *exactly* equal is asking for trouble. For a good /// guide on what to do, see [the floating point @@ -653,8 +653,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for modulo arithmetic. /// - /// ### Why is this bad? - /// The results of modulo (%) operation might differ + /// ### Why restrict this? + /// The results of modulo (`%`) operation might differ /// depending on the language, when negative numbers are involved. /// If you interop with different languages it might be beneficial /// to double check all places that use modulo arithmetic. diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index f821a4efee7..806638c0505 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -13,9 +13,9 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for usage of `panic!` or assertions in a function of type result. + /// Checks for usage of `panic!` or assertions in a function whose return type is `Result`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided. /// /// ### Known problems diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 75066c1f0d2..80ef761906e 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -14,8 +14,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `panic!`. /// - /// ### Why is this bad? - /// `panic!` will stop the execution of the executable. + /// ### Why restrict this? + /// This macro, or panics in general, may be unwanted in production code. /// /// ### Example /// ```no_run @@ -31,8 +31,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `unimplemented!`. /// - /// ### Why is this bad? - /// This macro should not be present in production code. + /// ### Why restrict this? + /// This macro, or panics in general, may be unwanted in production code. /// /// ### Example /// ```no_run @@ -48,9 +48,9 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `todo!`. /// - /// ### Why is this bad? - /// The `todo!` macro is often used for unfinished code, and it causes - /// code to panic. It should not be present in production code. + /// ### Why restrict this? + /// The `todo!` macro indicates the presence of unfinished code, + /// so it should not be present in production code. /// /// ### Example /// ```no_run @@ -70,8 +70,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `unreachable!`. /// - /// ### Why is this bad? - /// This macro can cause code to panic. + /// ### Why restrict this? + /// This macro, or panics in general, may be unwanted in production code. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/partial_pub_fields.rs b/clippy_lints/src/partial_pub_fields.rs index ffa403e27ca..2d20cbea698 100644 --- a/clippy_lints/src/partial_pub_fields.rs +++ b/clippy_lints/src/partial_pub_fields.rs @@ -5,15 +5,16 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks whether partial fields of a struct are public. + /// Checks whether some but not all fields of a `struct` are public. /// /// Either make all fields of a type public, or make none of them public /// - /// ### Why is this bad? + /// ### Why restrict this? /// Most types should either be: /// * Abstract data types: complex objects with opaque implementation which guard - /// interior invariants and expose intentionally limited API to the outside world. - /// * Data: relatively simple objects which group a bunch of related attributes together. + /// interior invariants and expose intentionally limited API to the outside world. + /// * Data: relatively simple objects which group a bunch of related attributes together, + /// but have no invariants. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index 44db061b8be..9661a57b8b9 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -30,9 +30,8 @@ declare_clippy_lint! { /// this lint can still be used to highlight areas of interest and ensure a good understanding /// of ownership semantics. /// - /// ### Why is this bad? - /// It isn't bad in general. But in some contexts it can be desirable - /// because it increases ownership hints in the code, and will guard against some changes + /// ### Why restrict this? + /// It increases ownership hints in the code, and will guard against some changes /// in ownership. /// /// ### Example diff --git a/clippy_lints/src/pub_use.rs b/clippy_lints/src/pub_use.rs index c0e999e76ef..ab8f8a1689d 100644 --- a/clippy_lints/src/pub_use.rs +++ b/clippy_lints/src/pub_use.rs @@ -5,13 +5,11 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// /// Restricts the usage of `pub use ...` /// - /// ### Why is this bad? - /// - /// `pub use` is usually fine, but a project may wish to limit `pub use` instances to prevent - /// unintentional exports or to encourage placing exported items directly in public modules + /// ### Why restrict this? + /// A project may wish to limit `pub use` instances to prevent + /// unintentional exports, or to encourage placing exported items directly in public modules. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/question_mark_used.rs b/clippy_lints/src/question_mark_used.rs index ddfc53083c4..f5e6cb804da 100644 --- a/clippy_lints/src/question_mark_used.rs +++ b/clippy_lints/src/question_mark_used.rs @@ -9,7 +9,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for expressions that use the question mark operator and rejects them. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Sometimes code wants to avoid the question mark operator because for instance a local /// block requires a macro to re-throw errors to attach additional information to the /// error. diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index 7e71f48c6d9..3a004245459 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -15,8 +15,10 @@ declare_clippy_lint! { /// ### What it does /// Checks for raw string literals where a string literal can be used instead. /// - /// ### Why is this bad? - /// It's just unnecessary, but there are many cases where using a raw string literal is more + /// ### Why restrict this? + /// For consistent style by using simpler string literals whenever possible. + /// + /// However, there are many cases where using a raw string literal is more /// idiomatic than a string literal, so it's opt-in. /// /// ### Example diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index c99b657c23a..7f87d18e502 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -46,7 +46,7 @@ declare_clippy_lint! { /// Checks for slicing expressions which are equivalent to dereferencing the /// value. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Some people may prefer to dereference rather than slice. /// /// ### Example diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs index 11b95ee3a54..81556f39614 100644 --- a/clippy_lints/src/redundant_type_annotations.rs +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -11,7 +11,7 @@ declare_clippy_lint! { /// ### What it does /// Warns about needless / redundant type annotations. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Code without type annotations is shorter and in most cases /// more idiomatic and easier to modify. /// diff --git a/clippy_lints/src/ref_patterns.rs b/clippy_lints/src/ref_patterns.rs index 607a0740b84..467038523b4 100644 --- a/clippy_lints/src/ref_patterns.rs +++ b/clippy_lints/src/ref_patterns.rs @@ -6,9 +6,11 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does /// Checks for usages of the `ref` keyword. - /// ### Why is this bad? + /// + /// ### Why restrict this? /// The `ref` keyword can be confusing for people unfamiliar with it, and often /// it is more concise to use `&` instead. + /// /// ### Example /// ```no_run /// let opt = Some(5); diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index e8f9d438104..48d6fb3c037 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -3,8 +3,8 @@ use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; use clippy_utils::{ - fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg, - span_find_starting_semi, + binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, + path_to_local_id, span_contains_cfg, span_find_starting_semi, }; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -129,7 +129,7 @@ enum RetReplacement<'tcx> { Empty, Block, Unit, - IfSequence(Cow<'tcx, str>, Applicability), + NeedsPar(Cow<'tcx, str>, Applicability), Expr(Cow<'tcx, str>, Applicability), } @@ -139,13 +139,13 @@ impl<'tcx> RetReplacement<'tcx> { Self::Empty | Self::Expr(..) => "remove `return`", Self::Block => "replace `return` with an empty block", Self::Unit => "replace `return` with a unit value", - Self::IfSequence(..) => "remove `return` and wrap the sequence with parentheses", + Self::NeedsPar(..) => "remove `return` and wrap the sequence with parentheses", } } fn applicability(&self) -> Applicability { match self { - Self::Expr(_, ap) | Self::IfSequence(_, ap) => *ap, + Self::Expr(_, ap) | Self::NeedsPar(_, ap) => *ap, _ => Applicability::MachineApplicable, } } @@ -157,7 +157,7 @@ impl<'tcx> Display for RetReplacement<'tcx> { Self::Empty => write!(f, ""), Self::Block => write!(f, "{{}}"), Self::Unit => write!(f, "()"), - Self::IfSequence(inner, _) => write!(f, "({inner})"), + Self::NeedsPar(inner, _) => write!(f, "({inner})"), Self::Expr(inner, _) => write!(f, "{inner}"), } } @@ -244,7 +244,11 @@ impl<'tcx> LateLintPass<'tcx> for Return { err.span_label(local.span, "unnecessary `let` binding"); if let Some(mut snippet) = snippet_opt(cx, initexpr.span) { - if !cx.typeck_results().expr_adjustments(retexpr).is_empty() { + if binary_expr_needs_parentheses(initexpr) { + if !has_enclosing_paren(&snippet) { + snippet = format!("({snippet})"); + } + } else if !cx.typeck_results().expr_adjustments(retexpr).is_empty() { if !has_enclosing_paren(&snippet) { snippet = format!("({snippet})"); } @@ -349,8 +353,8 @@ fn check_final_expr<'tcx>( let mut applicability = Applicability::MachineApplicable; let (snippet, _) = snippet_with_context(cx, inner_expr.span, ret_span.ctxt(), "..", &mut applicability); - if expr_contains_conjunctive_ifs(inner_expr) { - RetReplacement::IfSequence(snippet, applicability) + if binary_expr_needs_parentheses(inner_expr) { + RetReplacement::NeedsPar(snippet, applicability) } else { RetReplacement::Expr(snippet, applicability) } @@ -404,18 +408,6 @@ fn check_final_expr<'tcx>( } } -fn expr_contains_conjunctive_ifs<'tcx>(expr: &'tcx Expr<'tcx>) -> bool { - fn contains_if(expr: &Expr<'_>, on_if: bool) -> bool { - match expr.kind { - ExprKind::If(..) => on_if, - ExprKind::Binary(_, left, right) => contains_if(left, true) || contains_if(right, true), - _ => false, - } - } - - contains_if(expr, false) -} - fn emit_return_lint( cx: &LateContext<'_>, ret_span: Span, diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 7e27f70bcf9..8fdd19c549f 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// It lints if a struct has two methods with the same name: /// one from a trait, another not from trait. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Confusing. /// /// ### Example diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index 0b3adfb7a4b..0e77acdfd77 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -11,8 +11,7 @@ declare_clippy_lint! { /// Suggests moving the semicolon after a block to the inside of the block, after its last /// expression. /// - /// ### Why is this bad? - /// + /// ### Why restrict this? /// For consistency it's best to have the semicolon inside/outside the block. Either way is fine /// and this lint suggests inside the block. /// Take a look at `semicolon_outside_block` for the other alternative. @@ -40,8 +39,7 @@ declare_clippy_lint! { /// /// Suggests moving the semicolon from a block's final expression outside of the block. /// - /// ### Why is this bad? - /// + /// ### Why restrict this? /// For consistency it's best to have the semicolon inside/outside the block. Either way is fine /// and this lint suggests outside the block. /// Take a look at `semicolon_inside_block` for the other alternative. diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 9db08acb03b..80f5fd0b494 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -15,10 +15,10 @@ declare_clippy_lint! { /// Checks for bindings that shadow other bindings already in /// scope, while just changing reference level or mutability. /// - /// ### Why is this bad? - /// Not much, in fact it's a very common pattern in Rust - /// code. Still, some may opt to avoid it in their code base, they can set this - /// lint to `Warn`. + /// ### Why restrict this? + /// To require that what are formally distinct variables be given distinct names. + /// + /// See also `shadow_reuse` and `shadow_unrelated` for other restrictions on shadowing. /// /// ### Example /// ```no_run @@ -42,12 +42,13 @@ declare_clippy_lint! { /// Checks for bindings that shadow other bindings already in /// scope, while reusing the original value. /// - /// ### Why is this bad? - /// Not too much, in fact it's a common pattern in Rust - /// code. Still, some argue that name shadowing like this hurts readability, + /// ### Why restrict this? + /// Some argue that name shadowing like this hurts readability, /// because a value may be bound to different things depending on position in /// the code. /// + /// See also `shadow_same` and `shadow_unrelated` for other restrictions on shadowing. + /// /// ### Example /// ```no_run /// let x = 2; @@ -70,11 +71,14 @@ declare_clippy_lint! { /// scope, either without an initialization or with one that does not even use /// the original value. /// - /// ### Why is this bad? - /// Name shadowing can hurt readability, especially in + /// ### Why restrict this? + /// Shadowing a binding with a closely related one is part of idiomatic Rust, + /// but shadowing a binding by accident with an unrelated one may indicate a mistake. + /// + /// Additionally, name shadowing in general can hurt readability, especially in /// large code bases, because it is easy to lose track of the active binding at - /// any place in the code. This can be alleviated by either giving more specific - /// names to bindings or introducing more scopes to contain the bindings. + /// any place in the code. If linting against all shadowing is desired, you may wish + /// to use the `shadow_same` and `shadow_reuse` lints as well. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/single_call_fn.rs b/clippy_lints/src/single_call_fn.rs index 2ce7e714c64..c71bc3f7fcd 100644 --- a/clippy_lints/src/single_call_fn.rs +++ b/clippy_lints/src/single_call_fn.rs @@ -13,13 +13,20 @@ declare_clippy_lint! { /// ### What it does /// Checks for functions that are only used once. Does not lint tests. /// - /// ### Why is this bad? - /// It's usually not, splitting a function into multiple parts often improves readability and in - /// the case of generics, can prevent the compiler from duplicating the function dozens of - /// time; instead, only duplicating a thunk. But this can prevent segmentation across a - /// codebase, where many small functions are used only once. + /// ### Why restrict this? + /// If a function is only used once (perhaps because it used to be used more widely), + /// then the code could be simplified by moving that function's code into its caller. /// - /// Note: If this lint is used, prepare to allow this a lot. + /// However, there are reasons not to do this everywhere: + /// + /// * Splitting a large function into multiple parts often improves readability + /// by giving names to its parts. + /// * A function’s signature might serve a necessary purpose, such as constraining + /// the type of a closure passed to it. + /// * Generic functions might call non-generic functions to reduce duplication + /// in the produced machine code. + /// + /// If this lint is used, prepare to `#[allow]` it a lot. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/single_char_lifetime_names.rs b/clippy_lints/src/single_char_lifetime_names.rs index 42f1564db35..72feb977c31 100644 --- a/clippy_lints/src/single_char_lifetime_names.rs +++ b/clippy_lints/src/single_char_lifetime_names.rs @@ -9,11 +9,10 @@ declare_clippy_lint! { /// Checks for lifetimes with names which are one character /// long. /// - /// ### Why is this bad? + /// ### Why restrict this? /// A single character is likely not enough to express the /// purpose of a lifetime. Using a longer name can make code - /// easier to understand, especially for those who are new to - /// Rust. + /// easier to understand. /// /// ### Known problems /// Rust programmers and learning resources tend to use single diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index 926c56332cc..12b70075a3d 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -12,11 +12,9 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// /// Finds items imported through `std` when available through `core`. /// - /// ### Why is this bad? - /// + /// ### Why restrict this? /// Crates which have `no_std` compatibility may wish to ensure types are imported from core to ensure /// disabling `std` does not cause the crate to fail to compile. This lint is also useful for crates /// migrating to become `no_std` compatible. @@ -37,11 +35,9 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// /// Finds items imported through `std` when available through `alloc`. /// - /// ### Why is this bad? - /// + /// ### Why restrict this? /// Crates which have `no_std` compatibility and require alloc may wish to ensure types are imported from /// alloc to ensure disabling `std` does not cause the crate to fail to compile. This lint is also useful /// for crates migrating to become `no_std` compatible. @@ -63,11 +59,9 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// /// Finds items imported through `alloc` when available through `core`. /// - /// ### Why is this bad? - /// + /// ### Why restrict this? /// Crates which have `no_std` compatibility and may optionally require alloc may wish to ensure types are /// imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint /// is also useful for crates migrating to become `no_std` compatible. diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 292124196ff..f8d36d6b92f 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -45,10 +45,10 @@ declare_clippy_lint! { /// `String`, but only if [`string_add_assign`](#string_add_assign) does *not* /// match. /// - /// ### Why is this bad? - /// It's not bad in and of itself. However, this particular + /// ### Why restrict this? + /// This particular /// `Add` implementation is asymmetric (the other operand need not be `String`, - /// but `x` does), while addition as mathematically defined is symmetric, also + /// but `x` does), while addition as mathematically defined is symmetric, and /// the `String::push_str(_)` function is a perfectly good replacement. /// Therefore, some dislike it and wish not to have it in their code. /// @@ -123,7 +123,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for slice operations on strings /// - /// ### Why is this bad? + /// ### Why restrict this? /// UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character /// counts and string indices. This may lead to panics, and should warrant some test cases /// containing wide UTF-8 characters. This lint is most useful in code that should avoid @@ -364,10 +364,10 @@ declare_clippy_lint! { /// ### What it does /// This lint checks for `.to_string()` method calls on values of type `&str`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// The `to_string` method is also used on other types to convert them to a string. - /// When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better - /// expressed with `.to_owned()`. + /// When called on a `&str` it turns the `&str` into the owned variant `String`, which can be + /// more specifically expressed with `.to_owned()`. /// /// ### Example /// ```no_run @@ -415,9 +415,10 @@ declare_clippy_lint! { /// ### What it does /// This lint checks for `.to_string()` method calls on values of type `String`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// The `to_string` method is also used on other types to convert them to a string. - /// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`. + /// When called on a `String` it only clones the `String`, which can be more specifically + /// expressed with `.clone()`. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/suspicious_xor_used_as_pow.rs b/clippy_lints/src/suspicious_xor_used_as_pow.rs index 1cc27670fa8..d150a5f858a 100644 --- a/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -11,8 +11,10 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does /// Warns for a Bitwise XOR (`^`) operator being probably confused as a powering. It will not trigger if any of the numbers are not in decimal. - /// ### Why is this bad? + /// + /// ### Why restrict this? /// It's most probably a typo and may lead to unexpected behaviours. + /// /// ### Example /// ```no_run /// let x = 3_i32 ^ 4_i32; diff --git a/clippy_lints/src/tests_outside_test_module.rs b/clippy_lints/src/tests_outside_test_module.rs index da557582647..58e42892c41 100644 --- a/clippy_lints/src/tests_outside_test_module.rs +++ b/clippy_lints/src/tests_outside_test_module.rs @@ -11,9 +11,11 @@ declare_clippy_lint! { /// ### What it does /// Triggers when a testing function (marked with the `#[test]` attribute) isn't inside a testing module /// (marked with `#[cfg(test)]`). - /// ### Why is this bad? + /// + /// ### Why restrict this? /// The idiomatic (and more performant) way of writing tests is inside a testing module (flagged with `#[cfg(test)]`), /// having test functions outside of this module is confusing and may lead to them being "hidden". + /// /// ### Example /// ```no_run /// #[test] diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 5e45ab211ef..62ef65ca122 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -217,7 +217,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `Rc` and `Arc` when `T` is a mutable buffer type such as `String` or `Vec`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Expressions such as `Rc` usually have no advantage over `Rc`, since /// it is larger and involves an extra level of indirection, and doesn't implement `Borrow`. /// @@ -274,7 +274,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `Rc>`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// `Rc` is used in single thread and `Mutex` is used in multi thread. /// Consider using `Rc>` in single thread or `Arc>` in multi thread. /// diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 4120bb1331b..6cf9229fdd0 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -38,10 +38,9 @@ declare_clippy_lint! { /// ); /// ``` /// - /// ### Why is this bad? - /// Undocumented unsafe blocks and impls can make it difficult to - /// read and maintain code, as well as uncover unsoundness - /// and bugs. + /// ### Why restrict this? + /// Undocumented unsafe blocks and impls can make it difficult to read and maintain code. + /// Writing out the safety justification may help in discovering unsoundness or bugs. /// /// ### Example /// ```no_run @@ -67,7 +66,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `// SAFETY: ` comments on safe code. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Safe code has no safety requirements, so there is no need to /// describe safety invariants. /// diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index 3d319b9fe76..d42697b31d1 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for non-ASCII characters in string and char literals. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Yeah, we know, the 90's called and wanted their charset /// back. Even so, there still are editors and other programs out there that /// don't work well with Unicode. So if the code is meant to be used diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs index 528a1dfcfc1..93dff1b8579 100644 --- a/clippy_lints/src/unnecessary_self_imports.rs +++ b/clippy_lints/src/unnecessary_self_imports.rs @@ -9,7 +9,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for imports ending in `::{self}`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// In most cases, this can be written much more cleanly by omitting `::{self}`. /// /// ### Known problems diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index aca500590ce..197ab0f173b 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -13,8 +13,10 @@ declare_clippy_lint! { /// ### What it does /// Checks for functions of type `Result` that contain `expect()` or `unwrap()` /// - /// ### Why is this bad? - /// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics. + /// ### Why restrict this? + /// These functions promote recoverable errors to non-recoverable errors, + /// which may be undesirable in code bases which wish to avoid panics, + /// or be a bug in the specific function. /// /// ### Known problems /// This can cause false positives in functions that handle both recoverable and non recoverable errors. diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 9818b98dd5b..11dcceca7ab 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `pub()` with `in`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Consistency. Use it or don't, just be consistent about it. /// /// Also see the `pub_without_shorthand` lint for an alternative. @@ -57,7 +57,7 @@ declare_clippy_lint! { /// Note: As you cannot write a module's path in `pub()`, this will only trigger on /// `pub(super)` and the like. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Consistency. Use it or don't, just be consistent about it. /// /// Also see the `pub_with_shorthand` lint for an alternative. diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index ff6ee0d10ad..652ce88bd95 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -66,7 +66,7 @@ declare_clippy_lint! { /// Checks for printing on *stdout*. The purpose of this lint /// is to catch debugging remnants. /// - /// ### Why is this bad? + /// ### Why restrict this? /// People often print on *stdout* while debugging an /// application and might forget to remove those prints afterward. /// @@ -88,7 +88,7 @@ declare_clippy_lint! { /// Checks for printing on *stderr*. The purpose of this lint /// is to catch debugging remnants. /// - /// ### Why is this bad? + /// ### Why restrict this? /// People often print on *stderr* while debugging an /// application and might forget to remove those prints afterward. /// @@ -110,15 +110,18 @@ declare_clippy_lint! { /// Checks for usage of `Debug` formatting. The purpose of this /// lint is to catch debugging remnants. /// - /// ### Why is this bad? - /// The purpose of the `Debug` trait is to facilitate - /// debugging Rust code. It should not be used in user-facing output. + /// ### Why restrict this? + /// The purpose of the `Debug` trait is to facilitate debugging Rust code, + /// and [no guarantees are made about its output][stability]. + /// It should not be used in user-facing output. /// /// ### Example /// ```no_run /// # let foo = "bar"; /// println!("{:?}", foo); /// ``` + /// + /// [stability]: https://doc.rust-lang.org/stable/std/fmt/trait.Debug.html#stability #[clippy::version = "pre 1.29.0"] pub USE_DEBUG, restriction, diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index f5d3967d130..cd88ccd87cf 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -412,8 +412,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// Simple constant folding: Insert an expression, get a constant or none. pub fn expr(&mut self, e: &Expr<'_>) -> Option> { match e.kind { - ExprKind::ConstBlock(e) | - ExprKind::DropTemps(e) => self.expr(e), + ExprKind::ConstBlock(e) | ExprKind::DropTemps(e) => self.expr(e), ExprKind::Path(ref qpath) => { self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| { let result = mir_to_const(this.lcx, result)?; @@ -491,8 +490,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// leaves the local crate. pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option { match e.kind { - ExprKind::ConstBlock(e) | - ExprKind::DropTemps(e) => self.expr_is_empty(e), + ExprKind::ConstBlock(e) | ExprKind::DropTemps(e) => self.expr_is_empty(e), ExprKind::Path(ref qpath) => { if !self .typeck_results diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index cc5ccd4053a..817d4095eb5 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -769,7 +769,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { // closures inherit TypeckResults self.hash_expr(self.cx.tcx.hir().body(body).value); }, - ExprKind::ConstBlock(ref l_id) => { + ExprKind::ConstBlock(l_id) => { self.hash_expr(l_id); }, ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 94d4656377f..b10830b24e1 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3370,3 +3370,25 @@ pub fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool { Node::Stmt(..) | Node::Block(Block { stmts: &[], .. }) ) } + +/// Returns true if the given `expr` is a block or resembled as a block, +/// such as `if`, `loop`, `match` expressions etc. +pub fn is_block_like(expr: &Expr<'_>) -> bool { + matches!( + expr.kind, + ExprKind::Block(..) | ExprKind::ConstBlock(..) | ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) + ) +} + +/// Returns true if the given `expr` is binary expression that needs to be wrapped in parentheses. +pub fn binary_expr_needs_parentheses(expr: &Expr<'_>) -> bool { + fn contains_block(expr: &Expr<'_>, is_operand: bool) -> bool { + match expr.kind { + ExprKind::Binary(_, lhs, _) => contains_block(lhs, true), + _ if is_block_like(expr) => is_operand, + _ => false, + } + } + + contains_block(expr, false) +} diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 2dacc34867f..3414b5ef680 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -9,7 +9,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{Expr, FnDecl, Safety, LangItem, TyKind}; +use rustc_hir::{Expr, FnDecl, LangItem, Safety, TyKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::interpret::Scalar; @@ -18,8 +18,8 @@ use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, - GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, Upcast, TraitRef, Ty, TyCtxt, - TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr, + GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; diff --git a/rust-toolchain b/rust-toolchain index a0585ffdb45..dd8b9ece773 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-05-16" +channel = "nightly-2024-05-30" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/tests/ui-internal/disallow_span_lint.rs b/tests/ui-internal/disallow_span_lint.rs index b91a83308b5..ca71dddcc24 100644 --- a/tests/ui-internal/disallow_span_lint.rs +++ b/tests/ui-internal/disallow_span_lint.rs @@ -11,11 +11,15 @@ use rustc_lint::{Lint, LintContext}; use rustc_middle::ty::TyCtxt; pub fn a(cx: impl LintContext, lint: &'static Lint, span: impl Into, msg: impl Into) { - cx.span_lint(lint, span, |lint| { lint.primary_message(msg); }); + cx.span_lint(lint, span, |lint| { + lint.primary_message(msg); + }); } pub fn b(tcx: TyCtxt<'_>, lint: &'static Lint, hir_id: HirId, span: impl Into, msg: impl Into) { - tcx.node_span_lint(lint, hir_id, span, |lint| { lint.primary_message(msg); }); + tcx.node_span_lint(lint, hir_id, span, |lint| { + lint.primary_message(msg); + }); } fn main() {} diff --git a/tests/ui-internal/disallow_span_lint.stderr b/tests/ui-internal/disallow_span_lint.stderr index 1cfbc8efc8e..1be4b665bcb 100644 --- a/tests/ui-internal/disallow_span_lint.stderr +++ b/tests/ui-internal/disallow_span_lint.stderr @@ -1,18 +1,22 @@ error: use of a disallowed method `rustc_lint::context::LintContext::span_lint` --> tests/ui-internal/disallow_span_lint.rs:14:5 | -LL | cx.span_lint(lint, span, |lint| { lint.primary_message(msg); }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / cx.span_lint(lint, span, |lint| { +LL | | lint.primary_message(msg); +LL | | }); + | |______^ | = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead (from clippy.toml) = note: `-D clippy::disallowed-methods` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint` - --> tests/ui-internal/disallow_span_lint.rs:18:5 + --> tests/ui-internal/disallow_span_lint.rs:20:5 | -LL | tcx.node_span_lint(lint, hir_id, span, |lint| { lint.primary_message(msg); }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / tcx.node_span_lint(lint, hir_id, span, |lint| { +LL | | lint.primary_message(msg); +LL | | }); + | |______^ | = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead (from clippy.toml) diff --git a/tests/ui/derive_partial_eq_without_eq.fixed b/tests/ui/derive_partial_eq_without_eq.fixed index 6f42487bbf4..eb93eb8e8ed 100644 --- a/tests/ui/derive_partial_eq_without_eq.fixed +++ b/tests/ui/derive_partial_eq_without_eq.fixed @@ -1,3 +1,4 @@ +#![feature(lint_reasons)] #![allow(unused)] #![warn(clippy::derive_partial_eq_without_eq)] @@ -14,6 +15,22 @@ pub struct MissingEq { bar: String, } +// Check that we honor the `allow` attribute +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, PartialEq)] +pub struct AllowedMissingEq { + foo: u32, + bar: String, +} + +// Check that we honor the `expect` attribute +#[expect(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, PartialEq)] +pub struct ExpectedMissingEq { + foo: u32, + bar: String, +} + // Eq is derived #[derive(PartialEq, Eq)] pub struct NotMissingEq { diff --git a/tests/ui/derive_partial_eq_without_eq.rs b/tests/ui/derive_partial_eq_without_eq.rs index 24f687c6c9d..42dc435bdd5 100644 --- a/tests/ui/derive_partial_eq_without_eq.rs +++ b/tests/ui/derive_partial_eq_without_eq.rs @@ -1,3 +1,4 @@ +#![feature(lint_reasons)] #![allow(unused)] #![warn(clippy::derive_partial_eq_without_eq)] @@ -14,6 +15,22 @@ pub struct MissingEq { bar: String, } +// Check that we honor the `allow` attribute +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, PartialEq)] +pub struct AllowedMissingEq { + foo: u32, + bar: String, +} + +// Check that we honor the `expect` attribute +#[expect(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, PartialEq)] +pub struct ExpectedMissingEq { + foo: u32, + bar: String, +} + // Eq is derived #[derive(PartialEq, Eq)] pub struct NotMissingEq { diff --git a/tests/ui/derive_partial_eq_without_eq.stderr b/tests/ui/derive_partial_eq_without_eq.stderr index 3d92112dc36..29cd7da6b77 100644 --- a/tests/ui/derive_partial_eq_without_eq.stderr +++ b/tests/ui/derive_partial_eq_without_eq.stderr @@ -1,5 +1,5 @@ error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:11:17 + --> tests/ui/derive_partial_eq_without_eq.rs:12:17 | LL | #[derive(Debug, PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` @@ -8,73 +8,73 @@ LL | #[derive(Debug, PartialEq)] = help: to override `-D warnings` add `#[allow(clippy::derive_partial_eq_without_eq)]` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:53:10 + --> tests/ui/derive_partial_eq_without_eq.rs:70:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:59:10 + --> tests/ui/derive_partial_eq_without_eq.rs:76:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:65:10 + --> tests/ui/derive_partial_eq_without_eq.rs:82:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:68:10 + --> tests/ui/derive_partial_eq_without_eq.rs:85:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:74:10 + --> tests/ui/derive_partial_eq_without_eq.rs:91:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:80:10 + --> tests/ui/derive_partial_eq_without_eq.rs:97:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:93:17 + --> tests/ui/derive_partial_eq_without_eq.rs:110:17 | LL | #[derive(Debug, PartialEq, Clone)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:96:10 + --> tests/ui/derive_partial_eq_without_eq.rs:113:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:103:14 + --> tests/ui/derive_partial_eq_without_eq.rs:120:14 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:106:14 + --> tests/ui/derive_partial_eq_without_eq.rs:123:14 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:166:14 + --> tests/ui/derive_partial_eq_without_eq.rs:183:14 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:174:14 + --> tests/ui/derive_partial_eq_without_eq.rs:191:14 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` diff --git a/tests/ui/doc/doc-fixable.fixed b/tests/ui/doc/doc-fixable.fixed index 7e22c847b1b..84673f1f43f 100644 --- a/tests/ui/doc/doc-fixable.fixed +++ b/tests/ui/doc/doc-fixable.fixed @@ -240,3 +240,6 @@ extern { /// `foo()` fn in_extern(); } + +/// +fn check_autofix_for_base_urls() {} diff --git a/tests/ui/doc/doc-fixable.rs b/tests/ui/doc/doc-fixable.rs index 3e2cb0df54b..4d017a99e0f 100644 --- a/tests/ui/doc/doc-fixable.rs +++ b/tests/ui/doc/doc-fixable.rs @@ -240,3 +240,6 @@ extern { /// foo() fn in_extern(); } + +/// https://github.com/rust-lang/rust-clippy/pull/12836 +fn check_autofix_for_base_urls() {} diff --git a/tests/ui/doc/doc-fixable.stderr b/tests/ui/doc/doc-fixable.stderr index cd2228c47e3..a9263f62d38 100644 --- a/tests/ui/doc/doc-fixable.stderr +++ b/tests/ui/doc/doc-fixable.stderr @@ -363,5 +363,11 @@ help: try LL | /// `foo()` | ~~~~~~~ -error: aborting due to 33 previous errors +error: you should put bare URLs between `<`/`>` or make a proper Markdown link + --> tests/ui/doc/doc-fixable.rs:244:5 + | +LL | /// https://github.com/rust-lang/rust-clippy/pull/12836 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `` + +error: aborting due to 34 previous errors diff --git a/tests/ui/doc/issue_12795.fixed b/tests/ui/doc/issue_12795.fixed new file mode 100644 index 00000000000..ade23bf975c --- /dev/null +++ b/tests/ui/doc/issue_12795.fixed @@ -0,0 +1,9 @@ +#![warn(clippy::doc_markdown)] + +//! A comment with `a_b(x)` and `a_c` in it and (`a_b((c))` ) too and (maybe `a_b((c))`) +//~^ ERROR: item in documentation is missing backticks +//~| ERROR: item in documentation is missing backticks +//~| ERROR: item in documentation is missing backticks +//~| ERROR: item in documentation is missing backticks + +pub fn main() {} diff --git a/tests/ui/doc/issue_12795.rs b/tests/ui/doc/issue_12795.rs new file mode 100644 index 00000000000..6d94a07e303 --- /dev/null +++ b/tests/ui/doc/issue_12795.rs @@ -0,0 +1,9 @@ +#![warn(clippy::doc_markdown)] + +//! A comment with a_b(x) and a_c in it and (a_b((c)) ) too and (maybe a_b((c))) +//~^ ERROR: item in documentation is missing backticks +//~| ERROR: item in documentation is missing backticks +//~| ERROR: item in documentation is missing backticks +//~| ERROR: item in documentation is missing backticks + +pub fn main() {} diff --git a/tests/ui/doc/issue_12795.stderr b/tests/ui/doc/issue_12795.stderr new file mode 100644 index 00000000000..5700145ec8f --- /dev/null +++ b/tests/ui/doc/issue_12795.stderr @@ -0,0 +1,48 @@ +error: item in documentation is missing backticks + --> tests/ui/doc/issue_12795.rs:3:20 + | +LL | //! A comment with a_b(x) and a_c in it and (a_b((c)) ) too and (maybe a_b((c))) + | ^^^^^^ + | + = note: `-D clippy::doc-markdown` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_markdown)]` +help: try + | +LL | //! A comment with `a_b(x)` and a_c in it and (a_b((c)) ) too and (maybe a_b((c))) + | ~~~~~~~~ + +error: item in documentation is missing backticks + --> tests/ui/doc/issue_12795.rs:3:31 + | +LL | //! A comment with a_b(x) and a_c in it and (a_b((c)) ) too and (maybe a_b((c))) + | ^^^ + | +help: try + | +LL | //! A comment with a_b(x) and `a_c` in it and (a_b((c)) ) too and (maybe a_b((c))) + | ~~~~~ + +error: item in documentation is missing backticks + --> tests/ui/doc/issue_12795.rs:3:46 + | +LL | //! A comment with a_b(x) and a_c in it and (a_b((c)) ) too and (maybe a_b((c))) + | ^^^^^^^^ + | +help: try + | +LL | //! A comment with a_b(x) and a_c in it and (`a_b((c))` ) too and (maybe a_b((c))) + | ~~~~~~~~~~ + +error: item in documentation is missing backticks + --> tests/ui/doc/issue_12795.rs:3:72 + | +LL | //! A comment with a_b(x) and a_c in it and (a_b((c)) ) too and (maybe a_b((c))) + | ^^^^^^^^ + | +help: try + | +LL | //! A comment with a_b(x) and a_c in it and (a_b((c)) ) too and (maybe `a_b((c))`) + | ~~~~~~~~~~ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/iter_on_empty_collections.fixed b/tests/ui/iter_on_empty_collections.fixed index 794629f240e..0f28b48d9ab 100644 --- a/tests/ui/iter_on_empty_collections.fixed +++ b/tests/ui/iter_on_empty_collections.fixed @@ -20,6 +20,28 @@ fn array() { }; let _ = if false { ["test"].iter() } else { [].iter() }; + + let smth = Some(vec![1, 2, 3]); + + // Don't trigger when the empty collection iter is relied upon for its concrete type + // But do trigger if it is just an iterator, despite being an argument to a method + for i in smth.as_ref().map_or([].iter(), |s| s.iter()).chain(std::iter::empty()) { + println!("{i}"); + } + + // Same as above, but for empty collection iters with extra layers + for i in smth.as_ref().map_or({ [].iter() }, |s| s.iter()) { + println!("{y}", y = i + 1); + } + + // Same as above, but for regular function calls + for i in Option::map_or(smth.as_ref(), [].iter(), |s| s.iter()) { + println!("{i}"); + } + + // Same as above, but when there are no predicates that mention the collection iter type. + let mut iter = [34, 228, 35].iter(); + let _ = std::mem::replace(&mut iter, [].iter()); } macro_rules! in_macros { diff --git a/tests/ui/iter_on_empty_collections.rs b/tests/ui/iter_on_empty_collections.rs index a6461a702eb..702da514df7 100644 --- a/tests/ui/iter_on_empty_collections.rs +++ b/tests/ui/iter_on_empty_collections.rs @@ -20,6 +20,28 @@ fn array() { }; let _ = if false { ["test"].iter() } else { [].iter() }; + + let smth = Some(vec![1, 2, 3]); + + // Don't trigger when the empty collection iter is relied upon for its concrete type + // But do trigger if it is just an iterator, despite being an argument to a method + for i in smth.as_ref().map_or([].iter(), |s| s.iter()).chain([].iter()) { + println!("{i}"); + } + + // Same as above, but for empty collection iters with extra layers + for i in smth.as_ref().map_or({ [].iter() }, |s| s.iter()) { + println!("{y}", y = i + 1); + } + + // Same as above, but for regular function calls + for i in Option::map_or(smth.as_ref(), [].iter(), |s| s.iter()) { + println!("{i}"); + } + + // Same as above, but when there are no predicates that mention the collection iter type. + let mut iter = [34, 228, 35].iter(); + let _ = std::mem::replace(&mut iter, [].iter()); } macro_rules! in_macros { diff --git a/tests/ui/iter_on_empty_collections.stderr b/tests/ui/iter_on_empty_collections.stderr index ade20ff26a0..da9caa6925b 100644 --- a/tests/ui/iter_on_empty_collections.stderr +++ b/tests/ui/iter_on_empty_collections.stderr @@ -37,5 +37,11 @@ error: `iter` call on an empty collection LL | assert_eq!(None.iter().next(), Option::<&i32>::None); | ^^^^^^^^^^^ help: try: `std::iter::empty()` -error: aborting due to 6 previous errors +error: `iter` call on an empty collection + --> tests/ui/iter_on_empty_collections.rs:28:66 + | +LL | for i in smth.as_ref().map_or([].iter(), |s| s.iter()).chain([].iter()) { + | ^^^^^^^^^ help: try: `std::iter::empty()` + +error: aborting due to 7 previous errors diff --git a/tests/ui/let_and_return.fixed b/tests/ui/let_and_return.fixed index 4187019e589..b68b41cdca2 100644 --- a/tests/ui/let_and_return.fixed +++ b/tests/ui/let_and_return.fixed @@ -210,4 +210,38 @@ fn issue9150() -> usize { x } +fn issue12801() { + fn left_is_if() -> String { + + (if true { "a".to_string() } else { "b".to_string() } + "c") + //~^ ERROR: returning the result of a `let` binding from a block + } + + fn no_par_needed() -> String { + + "c".to_string() + if true { "a" } else { "b" } + //~^ ERROR: returning the result of a `let` binding from a block + } + + fn conjunctive_blocks() -> String { + + ({ "a".to_string() } + "b" + { "c" } + "d") + //~^ ERROR: returning the result of a `let` binding from a block + } + + #[allow(clippy::overly_complex_bool_expr)] + fn other_ops() { + let _ = || { + + (if true { 2 } else { 3 } << 4) + //~^ ERROR: returning the result of a `let` binding from a block + }; + let _ = || { + + ({ true } || { false } && { 2 <= 3 }) + //~^ ERROR: returning the result of a `let` binding from a block + }; + } +} + fn main() {} diff --git a/tests/ui/let_and_return.rs b/tests/ui/let_and_return.rs index 54444957b7d..6b9035f9428 100644 --- a/tests/ui/let_and_return.rs +++ b/tests/ui/let_and_return.rs @@ -210,4 +210,38 @@ fn issue9150() -> usize { x } +fn issue12801() { + fn left_is_if() -> String { + let s = if true { "a".to_string() } else { "b".to_string() } + "c"; + s + //~^ ERROR: returning the result of a `let` binding from a block + } + + fn no_par_needed() -> String { + let s = "c".to_string() + if true { "a" } else { "b" }; + s + //~^ ERROR: returning the result of a `let` binding from a block + } + + fn conjunctive_blocks() -> String { + let s = { "a".to_string() } + "b" + { "c" } + "d"; + s + //~^ ERROR: returning the result of a `let` binding from a block + } + + #[allow(clippy::overly_complex_bool_expr)] + fn other_ops() { + let _ = || { + let s = if true { 2 } else { 3 } << 4; + s + //~^ ERROR: returning the result of a `let` binding from a block + }; + let _ = || { + let s = { true } || { false } && { 2 <= 3 }; + s + //~^ ERROR: returning the result of a `let` binding from a block + }; + } +} + fn main() {} diff --git a/tests/ui/let_and_return.stderr b/tests/ui/let_and_return.stderr index ff5962ec196..75efa05d770 100644 --- a/tests/ui/let_and_return.stderr +++ b/tests/ui/let_and_return.stderr @@ -78,5 +78,75 @@ LL + E::B(x) => x, LL + }) as _ | -error: aborting due to 5 previous errors +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:216:9 + | +LL | let s = if true { "a".to_string() } else { "b".to_string() } + "c"; + | ------------------------------------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ (if true { "a".to_string() } else { "b".to_string() } + "c") + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:222:9 + | +LL | let s = "c".to_string() + if true { "a" } else { "b" }; + | ------------------------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ "c".to_string() + if true { "a" } else { "b" } + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:228:9 + | +LL | let s = { "a".to_string() } + "b" + { "c" } + "d"; + | -------------------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ ({ "a".to_string() } + "b" + { "c" } + "d") + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:236:13 + | +LL | let s = if true { 2 } else { 3 } << 4; + | -------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ (if true { 2 } else { 3 } << 4) + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:241:13 + | +LL | let s = { true } || { false } && { 2 <= 3 }; + | -------------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ ({ true } || { false } && { 2 <= 3 }) + | + +error: aborting due to 10 previous errors diff --git a/tests/ui/many_single_char_names.rs b/tests/ui/many_single_char_names.rs index 2af45eaab8a..68578340d90 100644 --- a/tests/ui/many_single_char_names.rs +++ b/tests/ui/many_single_char_names.rs @@ -1,5 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #![allow(clippy::too_many_arguments, clippy::diverging_sub_expression)] #![warn(clippy::many_single_char_names)] diff --git a/tests/ui/many_single_char_names.stderr b/tests/ui/many_single_char_names.stderr index 3b2460b5c07..131836ef7c8 100644 --- a/tests/ui/many_single_char_names.stderr +++ b/tests/ui/many_single_char_names.stderr @@ -1,5 +1,5 @@ error: 5 bindings with single-character names in scope - --> tests/ui/many_single_char_names.rs:7:9 + --> tests/ui/many_single_char_names.rs:5:9 | LL | let a: i32; | ^ @@ -14,7 +14,7 @@ LL | let e: i32; = help: to override `-D warnings` add `#[allow(clippy::many_single_char_names)]` error: 6 bindings with single-character names in scope - --> tests/ui/many_single_char_names.rs:7:9 + --> tests/ui/many_single_char_names.rs:5:9 | LL | let a: i32; | ^ @@ -28,7 +28,7 @@ LL | let f: i32; | ^ error: 5 bindings with single-character names in scope - --> tests/ui/many_single_char_names.rs:7:9 + --> tests/ui/many_single_char_names.rs:5:9 | LL | let a: i32; | ^ @@ -40,13 +40,13 @@ LL | e => panic!(), | ^ error: 8 bindings with single-character names in scope - --> tests/ui/many_single_char_names.rs:36:13 + --> tests/ui/many_single_char_names.rs:34:13 | LL | fn bindings(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32) {} | ^ ^ ^ ^ ^ ^ ^ ^ error: 8 bindings with single-character names in scope - --> tests/ui/many_single_char_names.rs:40:10 + --> tests/ui/many_single_char_names.rs:38:10 | LL | let (a, b, c, d, e, f, g, h): (bool, bool, bool, bool, bool, bool, bool, bool) = unimplemented!(); | ^ ^ ^ ^ ^ ^ ^ ^ diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 2575f2449e1..a9271cb399d 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -323,4 +323,8 @@ fn allow_works() -> i32 { } } +fn conjunctive_blocks() -> String { + ({ "a".to_string() } + "b" + { "c" }) +} + fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 04f21834d88..dc888bf667f 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -333,4 +333,8 @@ fn allow_works() -> i32 { } } +fn conjunctive_blocks() -> String { + return { "a".to_string() } + "b" + { "c" }; +} + fn main() {} diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 758ff6d985c..bf5a89d8b75 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -653,5 +653,17 @@ LL - return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 LL + (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }) | -error: aborting due to 52 previous errors +error: unneeded `return` statement + --> tests/ui/needless_return.rs:337:5 + | +LL | return { "a".to_string() } + "b" + { "c" }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove `return` and wrap the sequence with parentheses + | +LL - return { "a".to_string() } + "b" + { "c" }; +LL + ({ "a".to_string() } + "b" + { "c" }) + | + +error: aborting due to 53 previous errors diff --git a/tests/ui/numbered_fields.fixed b/tests/ui/numbered_fields.fixed index dc88081ba0a..108520eed38 100644 --- a/tests/ui/numbered_fields.fixed +++ b/tests/ui/numbered_fields.fixed @@ -34,4 +34,9 @@ fn main() { // Aliases can't be tuple constructed #8638 let _ = Alias { 0: 0, 1: 1, 2: 2 }; + + // Issue #12367 + struct TupleStructVec(Vec); + + let _ = TupleStructVec(vec![0, 1, 2, 3]); } diff --git a/tests/ui/numbered_fields.rs b/tests/ui/numbered_fields.rs index e8fa652e3c1..c718661a682 100644 --- a/tests/ui/numbered_fields.rs +++ b/tests/ui/numbered_fields.rs @@ -42,4 +42,9 @@ fn main() { // Aliases can't be tuple constructed #8638 let _ = Alias { 0: 0, 1: 1, 2: 2 }; + + // Issue #12367 + struct TupleStructVec(Vec); + + let _ = TupleStructVec { 0: vec![0, 1, 2, 3] }; } diff --git a/tests/ui/numbered_fields.stderr b/tests/ui/numbered_fields.stderr index 96426cab1e6..9d3f59cd376 100644 --- a/tests/ui/numbered_fields.stderr +++ b/tests/ui/numbered_fields.stderr @@ -23,5 +23,11 @@ LL | | 1: 3u32, LL | | }; | |_____^ help: try: `TupleStruct(1u32, 3u32, 2u8)` -error: aborting due to 2 previous errors +error: used a field initializer for a tuple struct + --> tests/ui/numbered_fields.rs:49:13 + | +LL | let _ = TupleStructVec { 0: vec![0, 1, 2, 3] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `TupleStructVec(vec![0, 1, 2, 3])` + +error: aborting due to 3 previous errors diff --git a/tests/ui/significant_drop_in_scrutinee.rs b/tests/ui/significant_drop_in_scrutinee.rs index 7fc89bb9538..8ee15440ccf 100644 --- a/tests/ui/significant_drop_in_scrutinee.rs +++ b/tests/ui/significant_drop_in_scrutinee.rs @@ -274,11 +274,20 @@ fn should_trigger_lint_for_tuple_in_scrutinee() { }, (_, _, _) => {}, }; + } +} + +// Should not trigger lint since `String::as_str` returns a reference (i.e., `&str`) +// to the locked data (i.e., the `String`) and it is not surprising that matching such +// a reference needs to keep the data locked until the end of the match block. +fn should_not_trigger_lint_for_string_as_str() { + let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() }); + { + let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() }); let mutex3 = Mutex::new(StateWithField { s: "three".to_owned() }); + match mutex3.lock().unwrap().s.as_str() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until - //~| NOTE: this might lead to deadlocks or other unexpected behavior "three" => { println!("started"); mutex1.lock().unwrap().s.len(); @@ -289,8 +298,6 @@ fn should_trigger_lint_for_tuple_in_scrutinee() { }; match (true, mutex3.lock().unwrap().s.as_str()) { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until - //~| NOTE: this might lead to deadlocks or other unexpected behavior (_, "three") => { println!("started"); mutex1.lock().unwrap().s.len(); @@ -514,16 +521,15 @@ impl StateStringWithBoxedMutexGuard { } } -fn should_trigger_lint_for_boxed_mutex_guard_holding_string() { +fn should_not_trigger_lint_for_string_ref() { let s = StateStringWithBoxedMutexGuard::new(); let matcher = String::from("A String"); - // Should trigger lint because a temporary Box holding a type with a significant drop in a match - // scrutinee may have a potentially surprising lifetime. + // Should not trigger lint because the second `deref` returns a string reference (`&String`). + // So it is not surprising that matching the reference implies that the lock needs to be held + // until the end of the block. match s.lock().deref().deref() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior matcher => println!("Value is {}", s.lock().deref()), _ => println!("Value was not a match"), }; @@ -639,13 +645,12 @@ fn should_trigger_lint_for_non_ref_move_and_clone_suggestion() { }; } -fn should_trigger_lint_for_read_write_lock_for_loop() { - // For-in loops desugar to match expressions and are prone to the type of deadlock this lint is - // designed to look for. +fn should_not_trigger_lint_for_read_write_lock_for_loop() { let rwlock = RwLock::>::new(vec!["1".to_string()]); + // Should not trigger lint. Since we're iterating over the data, it's obvious that the lock + // has to be held until the iteration finishes. + // https://github.com/rust-lang/rust-clippy/issues/8987 for s in rwlock.read().unwrap().iter() { - //~^ ERROR: temporary with significant `Drop` in `for` loop condition will live until - //~| NOTE: this might lead to deadlocks or other unexpected behavior println!("{}", s); } } @@ -731,4 +736,69 @@ fn should_not_trigger_for_significant_drop_ref() { }; } +struct Foo<'a>(&'a Vec); + +impl<'a> Foo<'a> { + fn copy_old_lifetime(&self) -> &'a Vec { + self.0 + } + + fn reborrow_new_lifetime(&self) -> &Vec { + self.0 + } +} + +fn should_trigger_lint_if_and_only_if_lifetime_is_irrelevant() { + let vec = Vec::new(); + let mutex = Mutex::new(Foo(&vec)); + + // Should trigger lint even if `copy_old_lifetime()` has a lifetime, as the lifetime of + // `&vec` is unrelated to the temporary with significant drop (i.e., the `MutexGuard`). + for val in mutex.lock().unwrap().copy_old_lifetime() { + //~^ ERROR: temporary with significant `Drop` in `for` loop condition will live until the + //~| NOTE: this might lead to deadlocks or other unexpected behavior + println!("{}", val); + } + + // Should not trigger lint because `reborrow_new_lifetime()` has a lifetime and the + // lifetime is related to the temporary with significant drop (i.e., the `MutexGuard`). + for val in mutex.lock().unwrap().reborrow_new_lifetime() { + println!("{}", val); + } +} + +fn should_not_trigger_lint_for_complex_lifetime() { + let mutex = Mutex::new(vec!["hello".to_owned()]); + let string = "world".to_owned(); + + // Should not trigger lint due to the relevant lifetime. + for c in mutex.lock().unwrap().first().unwrap().chars() { + println!("{}", c); + } + + // Should trigger lint due to the irrelevant lifetime. + // + // FIXME: The lifetime is too complex to analyze. In order to avoid false positives, we do not + // trigger lint. + for c in mutex.lock().unwrap().first().map(|_| &string).unwrap().chars() { + println!("{}", c); + } +} + +fn should_not_trigger_lint_with_explicit_drop() { + let mutex = Mutex::new(vec![1]); + + // Should not trigger lint since the drop explicitly happens. + for val in [drop(mutex.lock().unwrap()), ()] { + println!("{:?}", val); + } + + // Should trigger lint if there is no explicit drop. + for val in [mutex.lock().unwrap()[0], 2] { + //~^ ERROR: temporary with significant `Drop` in `for` loop condition will live until the + //~| NOTE: this might lead to deadlocks or other unexpected behavior + println!("{:?}", val); + } +} + fn main() {} diff --git a/tests/ui/significant_drop_in_scrutinee.stderr b/tests/ui/significant_drop_in_scrutinee.stderr index 811bb065527..4a483e79d8a 100644 --- a/tests/ui/significant_drop_in_scrutinee.stderr +++ b/tests/ui/significant_drop_in_scrutinee.stderr @@ -160,45 +160,53 @@ LL ~ match (mutex1.lock().unwrap().s.len(), true, value) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:279:15 + --> tests/ui/significant_drop_in_scrutinee.rs:319:11 | -LL | match mutex3.lock().unwrap().s.as_str() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match mutex.lock().unwrap().s.len() > 1 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... -LL | mutex1.lock().unwrap().s.len(); - | ---------------------- another value with significant `Drop` created here -LL | mutex2.lock().unwrap().s.len(); - | ---------------------- another value with significant `Drop` created here +LL | mutex.lock().unwrap().s.len(); + | --------------------- another value with significant `Drop` created here ... -LL | }; - | - temporary lives until here +LL | }; + | - temporary lives until here | = note: this might lead to deadlocks or other unexpected behavior +help: try moving the temporary above the match + | +LL ~ let value = mutex.lock().unwrap().s.len(); +LL ~ match value > 1 { + | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:291:22 + --> tests/ui/significant_drop_in_scrutinee.rs:328:15 | -LL | match (true, mutex3.lock().unwrap().s.as_str()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match 1 < mutex.lock().unwrap().s.len() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... -LL | mutex1.lock().unwrap().s.len(); - | ---------------------- another value with significant `Drop` created here -LL | mutex2.lock().unwrap().s.len(); - | ---------------------- another value with significant `Drop` created here +LL | mutex.lock().unwrap().s.len(); + | --------------------- another value with significant `Drop` created here ... -LL | }; - | - temporary lives until here +LL | }; + | - temporary lives until here | = note: this might lead to deadlocks or other unexpected behavior +help: try moving the temporary above the match + | +LL ~ let value = mutex.lock().unwrap().s.len(); +LL ~ match 1 < value { + | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:312:11 + --> tests/ui/significant_drop_in_scrutinee.rs:348:11 | -LL | match mutex.lock().unwrap().s.len() > 1 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... -LL | mutex.lock().unwrap().s.len(); - | --------------------- another value with significant `Drop` created here +LL | mutex1.lock().unwrap().s.len(), + | ---------------------- another value with significant `Drop` created here +LL | mutex2.lock().unwrap().s.len() + | ---------------------- another value with significant `Drop` created here ... LL | }; | - temporary lives until here @@ -206,18 +214,20 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | -LL ~ let value = mutex.lock().unwrap().s.len() > 1; -LL ~ match value { +LL ~ let value = mutex1.lock().unwrap().s.len(); +LL ~ match value < mutex2.lock().unwrap().s.len() { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:321:11 + --> tests/ui/significant_drop_in_scrutinee.rs:348:44 | -LL | match 1 < mutex.lock().unwrap().s.len() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... -LL | mutex.lock().unwrap().s.len(); - | --------------------- another value with significant `Drop` created here +LL | mutex1.lock().unwrap().s.len(), + | ---------------------- another value with significant `Drop` created here +LL | mutex2.lock().unwrap().s.len() + | ---------------------- another value with significant `Drop` created here ... LL | }; | - temporary lives until here @@ -225,15 +235,15 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | -LL ~ let value = 1 < mutex.lock().unwrap().s.len(); -LL ~ match value { +LL ~ let value = mutex2.lock().unwrap().s.len(); +LL ~ match mutex1.lock().unwrap().s.len() < value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:341:11 + --> tests/ui/significant_drop_in_scrutinee.rs:361:11 | -LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | mutex1.lock().unwrap().s.len(), | ---------------------- another value with significant `Drop` created here @@ -246,15 +256,15 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | -LL ~ let value = mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len(); -LL ~ match value { +LL ~ let value = mutex1.lock().unwrap().s.len(); +LL ~ match value >= mutex2.lock().unwrap().s.len() { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:354:11 + --> tests/ui/significant_drop_in_scrutinee.rs:361:45 | LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | mutex1.lock().unwrap().s.len(), | ---------------------- another value with significant `Drop` created here @@ -267,15 +277,15 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | -LL ~ let value = mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len(); -LL ~ match value { +LL ~ let value = mutex2.lock().unwrap().s.len(); +LL ~ match mutex1.lock().unwrap().s.len() >= value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:391:11 + --> tests/ui/significant_drop_in_scrutinee.rs:398:11 | LL | match get_mutex_guard().s.len() > 1 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | mutex1.lock().unwrap().s.len(); | ---------------------- another value with significant `Drop` created here @@ -286,12 +296,12 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | -LL ~ let value = get_mutex_guard().s.len() > 1; -LL ~ match value { +LL ~ let value = get_mutex_guard().s.len(); +LL ~ match value > 1 { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:410:11 + --> tests/ui/significant_drop_in_scrutinee.rs:417:11 | LL | match match i { | ___________^ @@ -299,9 +309,9 @@ LL | | LL | | LL | | 100 => mutex1.lock().unwrap(), ... | +LL | | .s LL | | .len() -LL | | > 1 - | |___________^ + | |__________^ ... LL | mutex1.lock().unwrap().s.len(); | ---------------------- another value with significant `Drop` created here @@ -319,13 +329,12 @@ LL + 100 => mutex1.lock().unwrap(), LL + _ => mutex2.lock().unwrap(), LL + } LL + .s -LL + .len() -LL + > 1; +LL + .len(); LL ~ match value | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:438:11 + --> tests/ui/significant_drop_in_scrutinee.rs:445:11 | LL | match if i > 1 { | ___________^ @@ -333,9 +342,9 @@ LL | | LL | | LL | | mutex1.lock().unwrap() ... | +LL | | .s LL | | .len() -LL | | > 1 - | |___________^ + | |__________^ ... LL | mutex1.lock().unwrap().s.len(); | ---------------------- another value with significant `Drop` created here @@ -354,13 +363,12 @@ LL + } else { LL + mutex2.lock().unwrap() LL + } LL + .s -LL + .len() -LL + > 1; +LL + .len(); LL ~ match value | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:494:11 + --> tests/ui/significant_drop_in_scrutinee.rs:501:11 | LL | match s.lock().deref().deref() { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -374,25 +382,11 @@ LL | }; help: try moving the temporary above the match and create a copy | LL ~ let value = *s.lock().deref().deref(); -LL ~ match value { +LL ~ match (&value) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:524:11 - | -LL | match s.lock().deref().deref() { - | ^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | matcher => println!("Value is {}", s.lock().deref()), - | -------- another value with significant `Drop` created here -LL | _ => println!("Value was not a match"), -LL | }; - | - temporary lives until here - | - = note: this might lead to deadlocks or other unexpected behavior - -error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:545:11 + --> tests/ui/significant_drop_in_scrutinee.rs:551:11 | LL | match mutex.lock().unwrap().i = i { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -411,10 +405,10 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:553:11 + --> tests/ui/significant_drop_in_scrutinee.rs:559:15 | LL | match i = mutex.lock().unwrap().i { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ ... LL | println!("{}", mutex.lock().unwrap().i); | --------------------- another value with significant `Drop` created here @@ -425,12 +419,12 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | -LL ~ i = mutex.lock().unwrap().i; -LL ~ match () { +LL ~ let value = mutex.lock().unwrap().i; +LL ~ match i = value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:561:11 + --> tests/ui/significant_drop_in_scrutinee.rs:567:11 | LL | match mutex.lock().unwrap().i += 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -449,10 +443,10 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:569:11 + --> tests/ui/significant_drop_in_scrutinee.rs:575:16 | LL | match i += mutex.lock().unwrap().i { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ ... LL | println!("{}", mutex.lock().unwrap().i); | --------------------- another value with significant `Drop` created here @@ -463,12 +457,12 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | -LL ~ i += mutex.lock().unwrap().i; -LL ~ match () { +LL ~ let value = mutex.lock().unwrap().i; +LL ~ match i += value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:634:11 + --> tests/ui/significant_drop_in_scrutinee.rs:640:11 | LL | match rwlock.read().unwrap().to_number() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -477,20 +471,14 @@ LL | }; | - temporary lives until here | = note: this might lead to deadlocks or other unexpected behavior - -error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression - --> tests/ui/significant_drop_in_scrutinee.rs:646:14 +help: try moving the temporary above the match | -LL | for s in rwlock.read().unwrap().iter() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | } - | - temporary lives until here +LL ~ let value = rwlock.read().unwrap().to_number(); +LL ~ match value { | - = note: this might lead to deadlocks or other unexpected behavior error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:663:11 + --> tests/ui/significant_drop_in_scrutinee.rs:668:11 | LL | match mutex.lock().unwrap().foo() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -506,7 +494,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:726:11 + --> tests/ui/significant_drop_in_scrutinee.rs:731:11 | LL | match guard.take().len() { | ^^^^^^^^^^^^^^^^^^ @@ -521,5 +509,37 @@ LL ~ let value = guard.take().len(); LL ~ match value { | +error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression + --> tests/ui/significant_drop_in_scrutinee.rs:757:16 + | +LL | for val in mutex.lock().unwrap().copy_old_lifetime() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | } + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior +help: try moving the temporary above the match + | +LL ~ let value = mutex.lock().unwrap().copy_old_lifetime(); +LL ~ for val in value { + | + +error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression + --> tests/ui/significant_drop_in_scrutinee.rs:797:17 + | +LL | for val in [mutex.lock().unwrap()[0], 2] { + | ^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | } + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior +help: try moving the temporary above the match + | +LL ~ let value = mutex.lock().unwrap()[0]; +LL ~ for val in [value, 2] { + | + error: aborting due to 27 previous errors diff --git a/tests/ui/unnecessary_iter_cloned.fixed b/tests/ui/unnecessary_iter_cloned.fixed index 2c582c90ba8..dc5e163ff04 100644 --- a/tests/ui/unnecessary_iter_cloned.fixed +++ b/tests/ui/unnecessary_iter_cloned.fixed @@ -170,3 +170,32 @@ fn check_mut_iteratee_and_modify_inner_variable() { } } } + +mod issue_12821 { + fn foo() { + let v: Vec<_> = "hello".chars().collect(); + for c in v.iter() { + //~^ ERROR: unnecessary use of `cloned` + println!("{c}"); // should not suggest to remove `&` + } + } + + fn bar() { + let v: Vec<_> = "hello".chars().collect(); + for c in v.iter() { + //~^ ERROR: unnecessary use of `cloned` + let ref_c = c; //~ HELP: remove any references to the binding + println!("{ref_c}"); + } + } + + fn baz() { + let v: Vec<_> = "hello".chars().enumerate().collect(); + for (i, c) in v.iter() { + //~^ ERROR: unnecessary use of `cloned` + let ref_c = c; //~ HELP: remove any references to the binding + let ref_i = i; + println!("{i} {ref_c}"); // should not suggest to remove `&` from `i` + } + } +} diff --git a/tests/ui/unnecessary_iter_cloned.rs b/tests/ui/unnecessary_iter_cloned.rs index a28ccd1efef..8f797ac717f 100644 --- a/tests/ui/unnecessary_iter_cloned.rs +++ b/tests/ui/unnecessary_iter_cloned.rs @@ -170,3 +170,32 @@ fn check_mut_iteratee_and_modify_inner_variable() { } } } + +mod issue_12821 { + fn foo() { + let v: Vec<_> = "hello".chars().collect(); + for c in v.iter().cloned() { + //~^ ERROR: unnecessary use of `cloned` + println!("{c}"); // should not suggest to remove `&` + } + } + + fn bar() { + let v: Vec<_> = "hello".chars().collect(); + for c in v.iter().cloned() { + //~^ ERROR: unnecessary use of `cloned` + let ref_c = &c; //~ HELP: remove any references to the binding + println!("{ref_c}"); + } + } + + fn baz() { + let v: Vec<_> = "hello".chars().enumerate().collect(); + for (i, c) in v.iter().cloned() { + //~^ ERROR: unnecessary use of `cloned` + let ref_c = &c; //~ HELP: remove any references to the binding + let ref_i = &i; + println!("{i} {ref_c}"); // should not suggest to remove `&` from `i` + } + } +} diff --git a/tests/ui/unnecessary_iter_cloned.stderr b/tests/ui/unnecessary_iter_cloned.stderr index fb98cfddc26..0bdb37a521f 100644 --- a/tests/ui/unnecessary_iter_cloned.stderr +++ b/tests/ui/unnecessary_iter_cloned.stderr @@ -10,7 +10,7 @@ help: use | LL | for (t, path) in files { | ~~~~~ -help: remove this `&` +help: remove any references to the binding | LL - let other = match get_file_path(&t) { LL + let other = match get_file_path(t) { @@ -26,11 +26,49 @@ help: use | LL | for (t, path) in files.iter() { | ~~~~~~~~~~~~ -help: remove this `&` +help: remove any references to the binding | LL - let other = match get_file_path(&t) { LL + let other = match get_file_path(t) { | -error: aborting due to 2 previous errors +error: unnecessary use of `cloned` + --> tests/ui/unnecessary_iter_cloned.rs:177:18 + | +LL | for c in v.iter().cloned() { + | ^^^^^^^^^^^^^^^^^ help: use: `v.iter()` + +error: unnecessary use of `cloned` + --> tests/ui/unnecessary_iter_cloned.rs:185:18 + | +LL | for c in v.iter().cloned() { + | ^^^^^^^^^^^^^^^^^ + | +help: use + | +LL | for c in v.iter() { + | ~~~~~~~~ +help: remove any references to the binding + | +LL - let ref_c = &c; +LL + let ref_c = c; + | + +error: unnecessary use of `cloned` + --> tests/ui/unnecessary_iter_cloned.rs:194:23 + | +LL | for (i, c) in v.iter().cloned() { + | ^^^^^^^^^^^^^^^^^ + | +help: use + | +LL | for (i, c) in v.iter() { + | ~~~~~~~~ +help: remove any references to the binding + | +LL ~ let ref_c = c; +LL ~ let ref_i = i; + | + +error: aborting due to 5 previous errors diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 5475df9c7b9..2829f3cd6e9 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -487,7 +487,7 @@ help: use | LL | for t in file_types { | ~~~~~~~~~~ -help: remove this `&` +help: remove any references to the binding | LL - let path = match get_file_path(&t) { LL + let path = match get_file_path(t) { diff --git a/tests/ui/unsafe_derive_deserialize.rs b/tests/ui/unsafe_derive_deserialize.rs index 70dcaa3afa4..5187e079042 100644 --- a/tests/ui/unsafe_derive_deserialize.rs +++ b/tests/ui/unsafe_derive_deserialize.rs @@ -1,3 +1,4 @@ +#![feature(lint_reasons)] #![warn(clippy::unsafe_derive_deserialize)] #![allow(unused, clippy::missing_safety_doc)] @@ -71,4 +72,14 @@ impl G { } } +// Check that we honor the `expect` attribute on the ADT +#[expect(clippy::unsafe_derive_deserialize)] +#[derive(Deserialize)] +pub struct H; +impl H { + pub fn unsafe_block(&self) { + unsafe {} + } +} + fn main() {} diff --git a/tests/ui/unsafe_derive_deserialize.stderr b/tests/ui/unsafe_derive_deserialize.stderr index f2d4429f707..06719f23d57 100644 --- a/tests/ui/unsafe_derive_deserialize.stderr +++ b/tests/ui/unsafe_derive_deserialize.stderr @@ -1,5 +1,5 @@ error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` - --> tests/ui/unsafe_derive_deserialize.rs:8:10 + --> tests/ui/unsafe_derive_deserialize.rs:9:10 | LL | #[derive(Deserialize)] | ^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | #[derive(Deserialize)] = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` - --> tests/ui/unsafe_derive_deserialize.rs:17:10 + --> tests/ui/unsafe_derive_deserialize.rs:18:10 | LL | #[derive(Deserialize)] | ^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | #[derive(Deserialize)] = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` - --> tests/ui/unsafe_derive_deserialize.rs:24:10 + --> tests/ui/unsafe_derive_deserialize.rs:25:10 | LL | #[derive(Deserialize)] | ^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | #[derive(Deserialize)] = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` - --> tests/ui/unsafe_derive_deserialize.rs:33:10 + --> tests/ui/unsafe_derive_deserialize.rs:34:10 | LL | #[derive(Deserialize)] | ^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 93b39d89102227b3d36f6524c9cec0c3c193970e Mon Sep 17 00:00:00 2001 From: Jacherr Date: Fri, 15 Mar 2024 00:04:27 +0000 Subject: disable indexing_slicing for custom Index impls --- clippy_lints/src/indexing_slicing.rs | 11 +++++++++- clippy_lints/src/iter_without_into_iter.rs | 32 ++---------------------------- clippy_utils/src/ty.rs | 30 ++++++++++++++++++++++++++++ tests/ui/indexing_slicing_slice.rs | 22 ++++++++++++++++++++ tests/ui/indexing_slicing_slice.stderr | 32 +++++++++++++++--------------- 5 files changed, 80 insertions(+), 47 deletions(-) diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index e3e79749bea..43797215ca5 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -3,6 +3,7 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::higher; +use clippy_utils::ty::{adt_has_inherent_method, deref_chain}; use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -104,7 +105,15 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { return; } - if let ExprKind::Index(array, index, _) = &expr.kind { + if let ExprKind::Index(array, index, _) = &expr.kind + && let expr_ty = cx.typeck_results().expr_ty(array) + && let mut deref = deref_chain(cx, expr_ty) + && deref.any(|l| { + l.peel_refs().is_slice() + || l.peel_refs().is_array() + || adt_has_inherent_method(cx, l.peel_refs(), sym!(get)) + }) + { let note = "the suggestion might not be applicable in constant blocks"; let ty = cx.typeck_results().expr_ty(array).peel_refs(); if let Some(range) = higher::Range::hir(index) { diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 601d0e151aa..02fefd1b6a1 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_parent_as_impl; use clippy_utils::source::snippet; -use clippy_utils::ty::{implements_trait, make_normalized_projection}; +use clippy_utils::ty::{adt_has_inherent_method, deref_chain, implements_trait, make_normalized_projection}; use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; @@ -9,8 +9,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Symbol}; -use std::iter; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -124,33 +123,6 @@ fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { .is_some_and(|did| cx.effective_visibilities.is_exported(did)) } -/// Returns the deref chain of a type, starting with the type itself. -fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator> + 'cx { - iter::successors(Some(ty), |&ty| { - if let Some(deref_did) = cx.tcx.lang_items().deref_trait() - && implements_trait(cx, ty, deref_did, &[]) - { - make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty]) - } else { - None - } - }) -} - -fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { - if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) { - cx.tcx.inherent_impls(ty_did).into_iter().flatten().any(|&did| { - cx.tcx - .associated_items(did) - .filter_by_name_unhygienic(method_name) - .next() - .is_some_and(|item| item.kind == ty::AssocKind::Fn) - }) - } else { - false - } -} - impl LateLintPass<'_> for IterWithoutIntoIter { fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { if !in_external_macro(cx.sess(), item.span) diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 3414b5ef680..295c10e4620 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -1328,3 +1328,33 @@ pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx> pub fn is_manually_drop(ty: Ty<'_>) -> bool { ty.ty_adt_def().map_or(false, AdtDef::is_manually_drop) } + +/// Returns the deref chain of a type, starting with the type itself. +pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator> + 'cx { + iter::successors(Some(ty), |&ty| { + if let Some(deref_did) = cx.tcx.lang_items().deref_trait() + && implements_trait(cx, ty, deref_did, &[]) + { + make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty]) + } else { + None + } + }) +} + +/// Checks if a Ty<'_> has some inherent method Symbol. +/// This does not look for impls in the type's Deref::Target type. +/// If you need this, you should wrap this call in clippy_utils::ty::deref_chain().any(...). +pub fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { + if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) { + cx.tcx.inherent_impls(ty_did).into_iter().flatten().any(|&did| { + cx.tcx + .associated_items(did) + .filter_by_name_unhygienic(method_name) + .next() + .is_some_and(|item| item.kind == ty::AssocKind::Fn) + }) + } else { + false + } +} diff --git a/tests/ui/indexing_slicing_slice.rs b/tests/ui/indexing_slicing_slice.rs index fc591021ed6..721ba8facec 100644 --- a/tests/ui/indexing_slicing_slice.rs +++ b/tests/ui/indexing_slicing_slice.rs @@ -3,6 +3,21 @@ // we want to avoid false positives. #![warn(clippy::out_of_bounds_indexing)] #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec)] +#![warn(clippy::indexing_slicing)] + +use std::ops::Index; + +struct BoolMap { + false_value: T, + true_value: T, +} + +impl Index for BoolMap { + type Output = T; + fn index(&self, index: bool) -> &T { + if index { &self.true_value } else { &self.false_value } + } +} fn main() { let x = [1, 2, 3, 4]; @@ -51,4 +66,11 @@ fn main() { //~^ ERROR: slicing may panic &v[..]; // Ok, should not produce stderr. + + let map = BoolMap { + false_value: 2, + true_value: 4, + }; + + map[true]; // Ok, because `get` does not exist (custom indexing) } diff --git a/tests/ui/indexing_slicing_slice.stderr b/tests/ui/indexing_slicing_slice.stderr index 790d4a41f5b..43fa44051c6 100644 --- a/tests/ui/indexing_slicing_slice.stderr +++ b/tests/ui/indexing_slicing_slice.stderr @@ -1,5 +1,5 @@ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:12:6 + --> tests/ui/indexing_slicing_slice.rs:27:6 | LL | &x[index..]; | ^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | &x[index..]; = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:14:6 + --> tests/ui/indexing_slicing_slice.rs:29:6 | LL | &x[..index]; | ^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | &x[..index]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:16:6 + --> tests/ui/indexing_slicing_slice.rs:31:6 | LL | &x[index_from..index_to]; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | &x[index_from..index_to]; = help: consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:18:6 + --> tests/ui/indexing_slicing_slice.rs:33:6 | LL | &x[index_from..][..index_to]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | &x[index_from..][..index_to]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:18:6 + --> tests/ui/indexing_slicing_slice.rs:33:6 | LL | &x[index_from..][..index_to]; | ^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | &x[index_from..][..index_to]; = help: consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:21:6 + --> tests/ui/indexing_slicing_slice.rs:36:6 | LL | &x[5..][..10]; | ^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | &x[5..][..10]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:21:8 + --> tests/ui/indexing_slicing_slice.rs:36:8 | LL | &x[5..][..10]; | ^ @@ -58,7 +58,7 @@ LL | &x[5..][..10]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:25:6 + --> tests/ui/indexing_slicing_slice.rs:40:6 | LL | &x[0..][..3]; | ^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | &x[0..][..3]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:27:6 + --> tests/ui/indexing_slicing_slice.rs:42:6 | LL | &x[1..][..5]; | ^^^^^^^^^^^ @@ -74,19 +74,19 @@ LL | &x[1..][..5]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:35:12 + --> tests/ui/indexing_slicing_slice.rs:50:12 | LL | &y[0..=4]; | ^ error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:37:11 + --> tests/ui/indexing_slicing_slice.rs:52:11 | LL | &y[..=4]; | ^ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:43:6 + --> tests/ui/indexing_slicing_slice.rs:58:6 | LL | &v[10..100]; | ^^^^^^^^^^ @@ -94,7 +94,7 @@ LL | &v[10..100]; = help: consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:45:6 + --> tests/ui/indexing_slicing_slice.rs:60:6 | LL | &x[10..][..100]; | ^^^^^^^^^^^^^^ @@ -102,13 +102,13 @@ LL | &x[10..][..100]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:45:8 + --> tests/ui/indexing_slicing_slice.rs:60:8 | LL | &x[10..][..100]; | ^^ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:48:6 + --> tests/ui/indexing_slicing_slice.rs:63:6 | LL | &v[10..]; | ^^^^^^^ @@ -116,7 +116,7 @@ LL | &v[10..]; = help: consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:50:6 + --> tests/ui/indexing_slicing_slice.rs:65:6 | LL | &v[..100]; | ^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 46b3264131f9e465cabba119ceccd61fe5617612 Mon Sep 17 00:00:00 2001 From: Jacherr Date: Fri, 15 Mar 2024 00:07:40 +0000 Subject: add backticks to doc comments --- clippy_utils/src/ty.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 295c10e4620..7dda01102c2 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -1343,8 +1343,8 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl } /// Checks if a Ty<'_> has some inherent method Symbol. -/// This does not look for impls in the type's Deref::Target type. -/// If you need this, you should wrap this call in clippy_utils::ty::deref_chain().any(...). +/// This does not look for impls in the type's `Deref::Target` type. +/// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`. pub fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) { cx.tcx.inherent_impls(ty_did).into_iter().flatten().any(|&did| { -- cgit 1.4.1-3-g733a5 From e186ed2ad1bdac3190e8ff3e35331249a4527fea Mon Sep 17 00:00:00 2001 From: Jacherr Date: Tue, 19 Mar 2024 10:41:56 +0000 Subject: check return type of get and indexing --- clippy_lints/src/indexing_slicing.rs | 40 +++++++++++++++++++++++++++--- clippy_lints/src/iter_without_into_iter.rs | 4 +-- clippy_utils/src/ty.rs | 30 +++++++++++++--------- tests/ui/indexing_slicing_slice.rs | 38 +++++++++++++++++++++++++++- 4 files changed, 94 insertions(+), 18 deletions(-) diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 43797215ca5..7dee30547a0 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -3,12 +3,13 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::higher; -use clippy_utils::ty::{adt_has_inherent_method, deref_chain}; +use clippy_utils::ty::{deref_chain, get_adt_inherent_method}; use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; +use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -111,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { && deref.any(|l| { l.peel_refs().is_slice() || l.peel_refs().is_array() - || adt_has_inherent_method(cx, l.peel_refs(), sym!(get)) + || ty_has_appliciable_get_function(cx, l.peel_refs(), expr_ty, expr) }) { let note = "the suggestion might not be applicable in constant blocks"; @@ -240,3 +241,36 @@ fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u1 (start, end) } + +/// Checks if the output Ty of the `get` method on this Ty (if any) matches the Ty returned by the +/// indexing operation (if any). +fn ty_has_appliciable_get_function<'tcx>( + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + array_ty: Ty<'tcx>, + index_expr: &Expr<'_>, +) -> bool { + if let ty::Adt(_, array_args) = array_ty.kind() + && let Some(get_output_ty) = get_adt_inherent_method(cx, ty, sym!(get)).map(|m| { + cx.tcx + .fn_sig(m.def_id) + .instantiate(cx.tcx, array_args) + .output() + .skip_binder() + }) + && let ty::Adt(def, args) = get_output_ty.kind() + && cx.tcx.is_diagnostic_item(sym::Option, def.0.did) + && let Some(option_generic_param) = args.get(0) + && let generic_ty = option_generic_param.expect_ty().peel_refs() + && let _ = println!( + "{}, {}", + cx.typeck_results().expr_ty(index_expr).peel_refs(), + generic_ty.peel_refs() + ) + && cx.typeck_results().expr_ty(index_expr).peel_refs() == generic_ty.peel_refs() + { + true + } else { + false + } +} diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 02fefd1b6a1..6b03f2597b0 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_parent_as_impl; use clippy_utils::source::snippet; -use clippy_utils::ty::{adt_has_inherent_method, deref_chain, implements_trait, make_normalized_projection}; +use clippy_utils::ty::{deref_chain, get_adt_inherent_method, implements_trait, make_normalized_projection}; use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; @@ -139,7 +139,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter { } && !deref_chain(cx, ty).any(|ty| { // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method - ty.peel_refs().is_slice() || adt_has_inherent_method(cx, ty, expected_method_name) + ty.peel_refs().is_slice() || get_adt_inherent_method(cx, ty, expected_method_name).is_some() }) && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| { if item.ident.name == sym!(IntoIter) { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 7dda01102c2..90360e85d8d 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -17,9 +17,9 @@ use rustc_middle::mir::ConstValue; use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ - self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, - GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, + self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, + GenericArgsRef, GenericParamDefKind, IntTy, List, ParamEnv, Region, RegionKind, ToPredicate, TraitRef, Ty, TyCtxt, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; @@ -1345,16 +1345,22 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl /// Checks if a Ty<'_> has some inherent method Symbol. /// This does not look for impls in the type's `Deref::Target` type. /// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`. -pub fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { +pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> { if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) { - cx.tcx.inherent_impls(ty_did).into_iter().flatten().any(|&did| { - cx.tcx - .associated_items(did) - .filter_by_name_unhygienic(method_name) - .next() - .is_some_and(|item| item.kind == ty::AssocKind::Fn) - }) + cx.tcx + .inherent_impls(ty_did) + .into_iter() + .flatten() + .map(|&did| { + cx.tcx + .associated_items(did) + .filter_by_name_unhygienic(method_name) + .next() + .filter(|item| item.kind == ty::AssocKind::Fn) + }) + .next() + .flatten() } else { - false + None } } diff --git a/tests/ui/indexing_slicing_slice.rs b/tests/ui/indexing_slicing_slice.rs index 721ba8facec..87a914db6fd 100644 --- a/tests/ui/indexing_slicing_slice.rs +++ b/tests/ui/indexing_slicing_slice.rs @@ -2,7 +2,13 @@ // We also check the out_of_bounds_indexing lint here, because it lints similar things and // we want to avoid false positives. #![warn(clippy::out_of_bounds_indexing)] -#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec)] +#![allow( + clippy::no_effect, + clippy::unnecessary_operation, + clippy::useless_vec, + unused_must_use, + unused +)] #![warn(clippy::indexing_slicing)] use std::ops::Index; @@ -19,6 +25,28 @@ impl Index for BoolMap { } } +struct BoolMapWithGet { + false_value: T, + true_value: T, +} + +impl Index for BoolMapWithGet { + type Output = T; + fn index(&self, index: bool) -> &Self::Output { + if index { &self.true_value } else { &self.false_value } + } +} + +impl BoolMapWithGet { + fn get(&self, index: bool) -> Option<&T> { + if index { + Some(&self.true_value) + } else { + Some(&self.false_value) + } + } +} + fn main() { let x = [1, 2, 3, 4]; let index: usize = 1; @@ -73,4 +101,12 @@ fn main() { }; map[true]; // Ok, because `get` does not exist (custom indexing) + + let map_with_get = BoolMapWithGet { + false_value: 2, + true_value: 4, + }; + + // Lint on this, because `get` does exist with same signature + map_with_get[true]; } -- cgit 1.4.1-3-g733a5 From ae59f5002dd7b872df10437cbf09f1af6f599a69 Mon Sep 17 00:00:00 2001 From: Jacherr Date: Wed, 27 Mar 2024 10:13:27 +0000 Subject: add additional testcases --- clippy_lints/src/indexing_slicing.rs | 5 --- tests/ui/indexing_slicing_slice.rs | 48 ++++++++++++++++++++++++++++ tests/ui/indexing_slicing_slice.stderr | 58 ++++++++++++++++++++++++---------- 3 files changed, 89 insertions(+), 22 deletions(-) diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 7dee30547a0..a1dcaa0c43a 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -262,11 +262,6 @@ fn ty_has_appliciable_get_function<'tcx>( && cx.tcx.is_diagnostic_item(sym::Option, def.0.did) && let Some(option_generic_param) = args.get(0) && let generic_ty = option_generic_param.expect_ty().peel_refs() - && let _ = println!( - "{}, {}", - cx.typeck_results().expr_ty(index_expr).peel_refs(), - generic_ty.peel_refs() - ) && cx.typeck_results().expr_ty(index_expr).peel_refs() == generic_ty.peel_refs() { true diff --git a/tests/ui/indexing_slicing_slice.rs b/tests/ui/indexing_slicing_slice.rs index 87a914db6fd..fba794aeaa6 100644 --- a/tests/ui/indexing_slicing_slice.rs +++ b/tests/ui/indexing_slicing_slice.rs @@ -47,6 +47,45 @@ impl BoolMapWithGet { } } +struct S(T); +impl S { + fn get() -> Option { + unimplemented!() + } +} +impl Index for S { + type Output = T; + fn index(&self, _index: i32) -> &Self::Output { + &self.0 + } +} + +struct Y(T); +impl Y { + fn get() -> Option { + unimplemented!() + } +} +impl Index for Y { + type Output = T; + fn index(&self, _index: i32) -> &Self::Output { + &self.0 + } +} + +struct Z(T); +impl Z { + fn get() -> T2 { + todo!() + } +} +impl Index for Z { + type Output = T; + fn index(&self, _index: i32) -> &Self::Output { + &self.0 + } +} + fn main() { let x = [1, 2, 3, 4]; let index: usize = 1; @@ -109,4 +148,13 @@ fn main() { // Lint on this, because `get` does exist with same signature map_with_get[true]; + + let s = S::(1); + s[0]; + + let y = Y::(1); + y[0]; + + let z = Z::(1); + z[0]; } diff --git a/tests/ui/indexing_slicing_slice.stderr b/tests/ui/indexing_slicing_slice.stderr index 43fa44051c6..a149d2a8fdb 100644 --- a/tests/ui/indexing_slicing_slice.stderr +++ b/tests/ui/indexing_slicing_slice.stderr @@ -1,5 +1,5 @@ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:27:6 + --> tests/ui/indexing_slicing_slice.rs:81:6 | LL | &x[index..]; | ^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | &x[index..]; = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:29:6 + --> tests/ui/indexing_slicing_slice.rs:83:6 | LL | &x[..index]; | ^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | &x[..index]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:31:6 + --> tests/ui/indexing_slicing_slice.rs:85:6 | LL | &x[index_from..index_to]; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | &x[index_from..index_to]; = help: consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:33:6 + --> tests/ui/indexing_slicing_slice.rs:87:6 | LL | &x[index_from..][..index_to]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | &x[index_from..][..index_to]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:33:6 + --> tests/ui/indexing_slicing_slice.rs:87:6 | LL | &x[index_from..][..index_to]; | ^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | &x[index_from..][..index_to]; = help: consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:36:6 + --> tests/ui/indexing_slicing_slice.rs:90:6 | LL | &x[5..][..10]; | ^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | &x[5..][..10]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:36:8 + --> tests/ui/indexing_slicing_slice.rs:90:8 | LL | &x[5..][..10]; | ^ @@ -58,7 +58,7 @@ LL | &x[5..][..10]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:40:6 + --> tests/ui/indexing_slicing_slice.rs:94:6 | LL | &x[0..][..3]; | ^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | &x[0..][..3]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:42:6 + --> tests/ui/indexing_slicing_slice.rs:96:6 | LL | &x[1..][..5]; | ^^^^^^^^^^^ @@ -74,19 +74,19 @@ LL | &x[1..][..5]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:50:12 + --> tests/ui/indexing_slicing_slice.rs:104:12 | LL | &y[0..=4]; | ^ error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:52:11 + --> tests/ui/indexing_slicing_slice.rs:106:11 | LL | &y[..=4]; | ^ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:58:6 + --> tests/ui/indexing_slicing_slice.rs:112:6 | LL | &v[10..100]; | ^^^^^^^^^^ @@ -94,7 +94,7 @@ LL | &v[10..100]; = help: consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:60:6 + --> tests/ui/indexing_slicing_slice.rs:114:6 | LL | &x[10..][..100]; | ^^^^^^^^^^^^^^ @@ -102,13 +102,13 @@ LL | &x[10..][..100]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:60:8 + --> tests/ui/indexing_slicing_slice.rs:114:8 | LL | &x[10..][..100]; | ^^ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:63:6 + --> tests/ui/indexing_slicing_slice.rs:117:6 | LL | &v[10..]; | ^^^^^^^ @@ -116,12 +116,36 @@ LL | &v[10..]; = help: consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:65:6 + --> tests/ui/indexing_slicing_slice.rs:119:6 | LL | &v[..100]; | ^^^^^^^^ | = help: consider using `.get(..n)`or `.get_mut(..n)` instead -error: aborting due to 16 previous errors +error: indexing may panic + --> tests/ui/indexing_slicing_slice.rs:137:5 + | +LL | map_with_get[true]; + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using `.get(n)` or `.get_mut(n)` instead + +error: indexing may panic + --> tests/ui/indexing_slicing_slice.rs:140:5 + | +LL | s[0]; + | ^^^^ + | + = help: consider using `.get(n)` or `.get_mut(n)` instead + +error: indexing may panic + --> tests/ui/indexing_slicing_slice.rs:143:5 + | +LL | y[0]; + | ^^^^ + | + = help: consider using `.get(n)` or `.get_mut(n)` instead + +error: aborting due to 19 previous errors -- cgit 1.4.1-3-g733a5 From 1c117f12eaa94070cf18487a9283167c6b1d8e1d Mon Sep 17 00:00:00 2001 From: Jacher Date: Thu, 30 May 2024 13:15:25 +0000 Subject: ignore generics in handling --- clippy_lints/src/indexing_slicing.rs | 14 +++++++------ clippy_utils/src/ty.rs | 8 +++---- tests/ui/indexing_slicing_slice.rs | 2 +- tests/ui/indexing_slicing_slice.stderr | 38 +++++++++++++++++----------------- 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index a1dcaa0c43a..b13b4d145df 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { && deref.any(|l| { l.peel_refs().is_slice() || l.peel_refs().is_array() - || ty_has_appliciable_get_function(cx, l.peel_refs(), expr_ty, expr) + || ty_has_applicable_get_function(cx, l.peel_refs(), expr_ty, expr) }) { let note = "the suggestion might not be applicable in constant blocks"; @@ -244,25 +244,27 @@ fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u1 /// Checks if the output Ty of the `get` method on this Ty (if any) matches the Ty returned by the /// indexing operation (if any). -fn ty_has_appliciable_get_function<'tcx>( +fn ty_has_applicable_get_function<'tcx>( cx: &LateContext<'tcx>, ty: Ty<'tcx>, array_ty: Ty<'tcx>, index_expr: &Expr<'_>, ) -> bool { - if let ty::Adt(_, array_args) = array_ty.kind() + if let ty::Adt(_, _) = array_ty.kind() && let Some(get_output_ty) = get_adt_inherent_method(cx, ty, sym!(get)).map(|m| { cx.tcx .fn_sig(m.def_id) - .instantiate(cx.tcx, array_args) + .skip_binder() .output() .skip_binder() }) && let ty::Adt(def, args) = get_output_ty.kind() && cx.tcx.is_diagnostic_item(sym::Option, def.0.did) - && let Some(option_generic_param) = args.get(0) + && let Some(option_generic_param) = args.first() && let generic_ty = option_generic_param.expect_ty().peel_refs() - && cx.typeck_results().expr_ty(index_expr).peel_refs() == generic_ty.peel_refs() + // FIXME: ideally this would handle type params and projections properly, for now just assume it's the same type + && (cx.typeck_results().expr_ty(index_expr).peel_refs() == generic_ty.peel_refs() + || matches!(generic_ty.peel_refs().kind(), ty::Param(_) | ty::Alias(_, _))) { true } else { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 90360e85d8d..07a1719cb1b 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -18,8 +18,8 @@ use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, - GenericArgsRef, GenericParamDefKind, IntTy, List, ParamEnv, Region, RegionKind, ToPredicate, TraitRef, Ty, TyCtxt, - TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr, + GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, + TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; @@ -1346,7 +1346,7 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl /// This does not look for impls in the type's `Deref::Target` type. /// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`. pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> { - if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) { + if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) { cx.tcx .inherent_impls(ty_did) .into_iter() @@ -1356,7 +1356,7 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n .associated_items(did) .filter_by_name_unhygienic(method_name) .next() - .filter(|item| item.kind == ty::AssocKind::Fn) + .filter(|item| item.kind == AssocKind::Fn) }) .next() .flatten() diff --git a/tests/ui/indexing_slicing_slice.rs b/tests/ui/indexing_slicing_slice.rs index fba794aeaa6..69291acd9c7 100644 --- a/tests/ui/indexing_slicing_slice.rs +++ b/tests/ui/indexing_slicing_slice.rs @@ -76,7 +76,7 @@ impl Index for Y { struct Z(T); impl Z { fn get() -> T2 { - todo!() + unimplemented!() } } impl Index for Z { diff --git a/tests/ui/indexing_slicing_slice.stderr b/tests/ui/indexing_slicing_slice.stderr index a149d2a8fdb..a7da3fe3faa 100644 --- a/tests/ui/indexing_slicing_slice.stderr +++ b/tests/ui/indexing_slicing_slice.stderr @@ -1,5 +1,5 @@ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:81:6 + --> tests/ui/indexing_slicing_slice.rs:94:6 | LL | &x[index..]; | ^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | &x[index..]; = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:83:6 + --> tests/ui/indexing_slicing_slice.rs:96:6 | LL | &x[..index]; | ^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | &x[..index]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:85:6 + --> tests/ui/indexing_slicing_slice.rs:98:6 | LL | &x[index_from..index_to]; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | &x[index_from..index_to]; = help: consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:87:6 + --> tests/ui/indexing_slicing_slice.rs:100:6 | LL | &x[index_from..][..index_to]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | &x[index_from..][..index_to]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:87:6 + --> tests/ui/indexing_slicing_slice.rs:100:6 | LL | &x[index_from..][..index_to]; | ^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | &x[index_from..][..index_to]; = help: consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:90:6 + --> tests/ui/indexing_slicing_slice.rs:103:6 | LL | &x[5..][..10]; | ^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | &x[5..][..10]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:90:8 + --> tests/ui/indexing_slicing_slice.rs:103:8 | LL | &x[5..][..10]; | ^ @@ -58,7 +58,7 @@ LL | &x[5..][..10]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:94:6 + --> tests/ui/indexing_slicing_slice.rs:107:6 | LL | &x[0..][..3]; | ^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | &x[0..][..3]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:96:6 + --> tests/ui/indexing_slicing_slice.rs:109:6 | LL | &x[1..][..5]; | ^^^^^^^^^^^ @@ -74,19 +74,19 @@ LL | &x[1..][..5]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:104:12 + --> tests/ui/indexing_slicing_slice.rs:117:12 | LL | &y[0..=4]; | ^ error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:106:11 + --> tests/ui/indexing_slicing_slice.rs:119:11 | LL | &y[..=4]; | ^ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:112:6 + --> tests/ui/indexing_slicing_slice.rs:125:6 | LL | &v[10..100]; | ^^^^^^^^^^ @@ -94,7 +94,7 @@ LL | &v[10..100]; = help: consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:114:6 + --> tests/ui/indexing_slicing_slice.rs:127:6 | LL | &x[10..][..100]; | ^^^^^^^^^^^^^^ @@ -102,13 +102,13 @@ LL | &x[10..][..100]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:114:8 + --> tests/ui/indexing_slicing_slice.rs:127:8 | LL | &x[10..][..100]; | ^^ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:117:6 + --> tests/ui/indexing_slicing_slice.rs:130:6 | LL | &v[10..]; | ^^^^^^^ @@ -116,7 +116,7 @@ LL | &v[10..]; = help: consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:119:6 + --> tests/ui/indexing_slicing_slice.rs:132:6 | LL | &v[..100]; | ^^^^^^^^ @@ -124,7 +124,7 @@ LL | &v[..100]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_slice.rs:137:5 + --> tests/ui/indexing_slicing_slice.rs:150:5 | LL | map_with_get[true]; | ^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL | map_with_get[true]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_slice.rs:140:5 + --> tests/ui/indexing_slicing_slice.rs:153:5 | LL | s[0]; | ^^^^ @@ -140,7 +140,7 @@ LL | s[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_slice.rs:143:5 + --> tests/ui/indexing_slicing_slice.rs:156:5 | LL | y[0]; | ^^^^ -- cgit 1.4.1-3-g733a5 From b92501f124894c49aaffeec6649c927138df5049 Mon Sep 17 00:00:00 2001 From: VitalikButerinEth Date: Thu, 30 May 2024 15:54:58 +0800 Subject: chore: fix some comments Signed-off-by: VitalikButerinEth --- tests/ui/double_neg.rs | 2 +- tests/ui/infinite_loops.rs | 2 +- tests/ui/iter_over_hash_type.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/double_neg.rs b/tests/ui/double_neg.rs index da82890443e..3be8c628873 100644 --- a/tests/ui/double_neg.rs +++ b/tests/ui/double_neg.rs @@ -5,6 +5,6 @@ fn main() { -x; -(-x); --x; - //~^ ERROR: `--x` could be misinterpreted as pre-decrement by C programmers, is usuall + //~^ ERROR: `--x` could be misinterpreted as pre-decrement by C programmers, is usually //~| NOTE: `-D clippy::double-neg` implied by `-D warnings` } diff --git a/tests/ui/infinite_loops.rs b/tests/ui/infinite_loops.rs index 52fbbaa8e31..b2d522fa011 100644 --- a/tests/ui/infinite_loops.rs +++ b/tests/ui/infinite_loops.rs @@ -137,7 +137,7 @@ fn can_break_both_inner_and_outer(cond: bool) { } fn break_wrong_loop(cond: bool) { - // 'inner has statement to break 'outer loop, but it was breaked early by a labeled child loop + // 'inner has statement to break 'outer loop, but it was broken out of early by a labeled child loop 'outer: loop { loop { //~^ ERROR: infinite loop detected diff --git a/tests/ui/iter_over_hash_type.rs b/tests/ui/iter_over_hash_type.rs index 7000c8bf96f..65bae1df421 100644 --- a/tests/ui/iter_over_hash_type.rs +++ b/tests/ui/iter_over_hash_type.rs @@ -59,7 +59,7 @@ fn main() { let _ = x; } - // shouldnt fire + // shouldn't fire for x in &vec { let _ = x; } -- cgit 1.4.1-3-g733a5 From 1038927b479fb6c7fe8d91be5d605fb85d15479a Mon Sep 17 00:00:00 2001 From: WeiTheShinobi Date: Thu, 30 May 2024 21:43:40 +0800 Subject: fix: add test case, use a better conditional expression. --- clippy_lints/src/non_canonical_impls.rs | 11 +++++------ tests/ui/auxiliary/proc_macro_derive.rs | 3 +-- tests/ui/non_canonical_clone_impl.fixed | 15 +++++++++++++++ tests/ui/non_canonical_clone_impl.rs | 15 +++++++++++++++ tests/ui/non_canonical_clone_impl.stderr | 8 ++++---- 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index bbefc74e8d2..de6a1a36f3e 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_res_lang_ctor, last_path_segment, path_res, std_or_core}; +use clippy_utils::{is_from_proc_macro, is_res_lang_ctor, last_path_segment, path_res, std_or_core}; use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty::EarlyBinder; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -111,7 +112,7 @@ declare_lint_pass!(NonCanonicalImpls => [NON_CANONICAL_CLONE_IMPL, NON_CANONICAL impl LateLintPass<'_> for NonCanonicalImpls { #[expect(clippy::too_many_lines)] - fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { + fn check_impl_item<'tcx>(&mut self, cx: &LateContext<'tcx>, impl_item: &ImplItem<'tcx>) { let Node::Item(item) = cx.tcx.parent_hir_node(impl_item.hir_id()) else { return; }; @@ -128,9 +129,7 @@ impl LateLintPass<'_> for NonCanonicalImpls { let ExprKind::Block(block, ..) = body.value.kind else { return; }; - if let Some(expr) = block.expr - && expr.span.from_expansion() - { + if in_external_macro(cx.sess(), block.span) || is_from_proc_macro(cx, impl_item) { return; } diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index 36ec31a7873..4c3df472269 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -176,8 +176,7 @@ pub fn non_canonical_clone_derive(_: TokenStream) -> TokenStream { struct NonCanonicalClone; impl Clone for NonCanonicalClone { fn clone(&self) -> Self { - let a = *self; - a + todo!() } } impl Copy for NonCanonicalClone {} diff --git a/tests/ui/non_canonical_clone_impl.fixed b/tests/ui/non_canonical_clone_impl.fixed index 26274fe6574..11616f28825 100644 --- a/tests/ui/non_canonical_clone_impl.fixed +++ b/tests/ui/non_canonical_clone_impl.fixed @@ -3,6 +3,9 @@ #![allow(clippy::assigning_clones)] #![no_main] +extern crate proc_macros; +use proc_macros::with_span; + // lint struct A(u32); @@ -100,3 +103,15 @@ impl Copy for Uwu {} // should skip proc macros, see https://github.com/rust-lang/rust-clippy/issues/12788 #[derive(proc_macro_derive::NonCanonicalClone)] pub struct G; + +with_span!( + span + + #[derive(Copy)] + struct H; + impl Clone for H { + fn clone(&self) -> Self { + todo!() + } + } +); diff --git a/tests/ui/non_canonical_clone_impl.rs b/tests/ui/non_canonical_clone_impl.rs index e2b278ac493..a36c7ed44c2 100644 --- a/tests/ui/non_canonical_clone_impl.rs +++ b/tests/ui/non_canonical_clone_impl.rs @@ -3,6 +3,9 @@ #![allow(clippy::assigning_clones)] #![no_main] +extern crate proc_macros; +use proc_macros::with_span; + // lint struct A(u32); @@ -110,3 +113,15 @@ impl Copy for Uwu {} // should skip proc macros, see https://github.com/rust-lang/rust-clippy/issues/12788 #[derive(proc_macro_derive::NonCanonicalClone)] pub struct G; + +with_span!( + span + + #[derive(Copy)] + struct H; + impl Clone for H { + fn clone(&self) -> Self { + todo!() + } + } +); diff --git a/tests/ui/non_canonical_clone_impl.stderr b/tests/ui/non_canonical_clone_impl.stderr index 80258ee8c77..f7cad58150f 100644 --- a/tests/ui/non_canonical_clone_impl.stderr +++ b/tests/ui/non_canonical_clone_impl.stderr @@ -1,5 +1,5 @@ error: non-canonical implementation of `clone` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:11:29 + --> tests/ui/non_canonical_clone_impl.rs:14:29 | LL | fn clone(&self) -> Self { | _____________________________^ @@ -11,7 +11,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::non_canonical_clone_impl)]` error: unnecessary implementation of `clone_from` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:15:5 + --> tests/ui/non_canonical_clone_impl.rs:18:5 | LL | / fn clone_from(&mut self, source: &Self) { LL | | source.clone(); @@ -20,7 +20,7 @@ LL | | } | |_____^ help: remove it error: non-canonical implementation of `clone` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:82:29 + --> tests/ui/non_canonical_clone_impl.rs:85:29 | LL | fn clone(&self) -> Self { | _____________________________^ @@ -29,7 +29,7 @@ LL | | } | |_____^ help: change this to: `{ *self }` error: unnecessary implementation of `clone_from` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:86:5 + --> tests/ui/non_canonical_clone_impl.rs:89:5 | LL | / fn clone_from(&mut self, source: &Self) { LL | | source.clone(); -- cgit 1.4.1-3-g733a5 From 040edea332a2767aed540b725c38a37167e17fdb Mon Sep 17 00:00:00 2001 From: León Orell Valerian Liehr Date: Mon, 27 May 2024 23:53:46 +0200 Subject: Rename HIR `TypeBinding` to `AssocItemConstraint` and related cleanup --- clippy_lints/src/implied_bounds_in_impls.rs | 54 ++++++++++++++--------------- clippy_lints/src/len_zero.rs | 17 ++++----- clippy_lints/src/manual_async_fn.rs | 10 +++--- clippy_utils/src/ast_utils.rs | 6 ++-- clippy_utils/src/hir_utils.rs | 8 ++--- 5 files changed, 44 insertions(+), 51 deletions(-) diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index dc935ed3d7f..2b389d4f9b1 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::def_id::DefId; use rustc_hir::{ - GenericArg, GenericBound, GenericBounds, ItemKind, PredicateOrigin, TraitBoundModifier, TyKind, TypeBinding, + GenericArg, GenericBound, GenericBounds, ItemKind, PredicateOrigin, TraitBoundModifier, TyKind, AssocItemConstraint, WherePredicate, }; use rustc_hir_analysis::lower_ty; @@ -54,9 +54,9 @@ fn emit_lint( poly_trait: &rustc_hir::PolyTraitRef<'_>, bounds: GenericBounds<'_>, index: usize, - // The bindings that were implied, used for suggestion purposes since removing a bound with associated types - // means we might need to then move it to a different bound - implied_bindings: &[TypeBinding<'_>], + // The constraints that were implied, used for suggestion purposes since removing a bound with + // associated types means we might need to then move it to a different bound. + implied_constraints: &[AssocItemConstraint<'_>], bound: &ImplTraitBound<'_>, ) { let implied_by = snippet(cx, bound.span, ".."); @@ -83,29 +83,29 @@ fn emit_lint( let mut sugg = vec![(implied_span_extended, String::new())]; - // We also might need to include associated type binding that were specified in the implied bound, + // We also might need to include associated item constraints that were specified in the implied bound, // but omitted in the implied-by bound: // `fn f() -> impl Deref + DerefMut` // If we're going to suggest removing `Deref<..>`, we'll need to put `` on `DerefMut` - let omitted_assoc_tys: Vec<_> = implied_bindings + let omitted_constraints: Vec<_> = implied_constraints .iter() - .filter(|binding| !bound.bindings.iter().any(|b| b.ident == binding.ident)) + .filter(|constraint| !bound.constraints.iter().any(|c| c.ident == constraint.ident)) .collect(); - if !omitted_assoc_tys.is_empty() { - // `<>` needs to be added if there aren't yet any generic arguments or bindings - let needs_angle_brackets = bound.args.is_empty() && bound.bindings.is_empty(); - let insert_span = match (bound.args, bound.bindings) { - ([.., arg], [.., binding]) => arg.span().max(binding.span).shrink_to_hi(), + if !omitted_constraints.is_empty() { + // `<>` needs to be added if there aren't yet any generic arguments or constraints + let needs_angle_brackets = bound.args.is_empty() && bound.constraints.is_empty(); + let insert_span = match (bound.args, bound.constraints) { + ([.., arg], [.., constraint]) => arg.span().max(constraint.span).shrink_to_hi(), ([.., arg], []) => arg.span().shrink_to_hi(), - ([], [.., binding]) => binding.span.shrink_to_hi(), + ([], [.., constraint]) => constraint.span.shrink_to_hi(), ([], []) => bound.span.shrink_to_hi(), }; - let mut associated_tys_sugg = if needs_angle_brackets { + let mut constraints_sugg = if needs_angle_brackets { "<".to_owned() } else { - // If angle brackets aren't needed (i.e., there are already generic arguments or bindings), + // If angle brackets aren't needed (i.e., there are already generic arguments or constraints), // we need to add a comma: // `impl A` // ^ if we insert `Assoc=i32` without a comma here, that'd be invalid syntax: @@ -113,16 +113,16 @@ fn emit_lint( ", ".to_owned() }; - for (index, binding) in omitted_assoc_tys.into_iter().enumerate() { + for (index, constraint) in omitted_constraints.into_iter().enumerate() { if index > 0 { - associated_tys_sugg += ", "; + constraints_sugg += ", "; } - associated_tys_sugg += &snippet(cx, binding.span, ".."); + constraints_sugg += &snippet(cx, constraint.span, ".."); } if needs_angle_brackets { - associated_tys_sugg += ">"; + constraints_sugg += ">"; } - sugg.push((insert_span, associated_tys_sugg)); + sugg.push((insert_span, constraints_sugg)); } diag.multipart_suggestion_with_style( @@ -229,8 +229,8 @@ struct ImplTraitBound<'tcx> { trait_def_id: DefId, /// The generic arguments on the `impl Trait` bound args: &'tcx [GenericArg<'tcx>], - /// The associated types on this bound - bindings: &'tcx [TypeBinding<'tcx>], + /// The associated item constraints of this bound + constraints: &'tcx [AssocItemConstraint<'tcx>], } /// Given an `impl Trait` type, gets all the supertraits from each bound ("implied bounds"). @@ -253,7 +253,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds Some(ImplTraitBound { predicates, args: path.args.map_or([].as_slice(), |p| p.args), - bindings: path.args.map_or([].as_slice(), |p| p.bindings), + constraints: path.args.map_or([].as_slice(), |p| p.constraints), trait_def_id, span: bound.span(), }) @@ -310,20 +310,20 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) { if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound && let [.., path] = poly_trait.trait_ref.path.segments && let implied_args = path.args.map_or([].as_slice(), |a| a.args) - && let implied_bindings = path.args.map_or([].as_slice(), |a| a.bindings) + && let implied_constraints = path.args.map_or([].as_slice(), |a| a.constraints) && let Some(def_id) = poly_trait.trait_ref.path.res.opt_def_id() && let Some(bound) = find_bound_in_supertraits(cx, def_id, implied_args, &supertraits) // If the implied bound has a type binding that also exists in the implied-by trait, // then we shouldn't lint. See #11880 for an example. && let assocs = cx.tcx.associated_items(bound.trait_def_id) - && !implied_bindings.iter().any(|binding| { + && !implied_constraints.iter().any(|constraint| { assocs - .filter_by_name_unhygienic(binding.ident.name) + .filter_by_name_unhygienic(constraint.ident.name) .next() .is_some_and(|assoc| assoc.kind == ty::AssocKind::Type) }) { - emit_lint(cx, poly_trait, bounds, index, implied_bindings, bound); + emit_lint(cx, poly_trait, bounds, index, implied_constraints, bound); } } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 97a245b76d4..2091e74665f 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::{ AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind, ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatKind, PathSegment, PrimTy, QPath, - TraitItemRef, TyKind, TypeBindingKind, + TraitItemRef, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; @@ -307,17 +307,12 @@ fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<& && let [GenericBound::Trait(trait_ref, _)] = &opaque.bounds && let Some(segment) = trait_ref.trait_ref.path.segments.last() && let Some(generic_args) = segment.args - && generic_args.bindings.len() == 1 - && let TypeBindingKind::Equality { - term: - rustc_hir::Term::Ty(rustc_hir::Ty { - kind: TyKind::Path(QPath::Resolved(_, path)), - .. - }), - } = &generic_args.bindings[0].kind - && path.segments.len() == 1 + && let [constraint] = generic_args.constraints + && let Some(ty) = constraint.ty() + && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind + && let [segment] = path.segments { - return Some(&path.segments[0]); + return Some(segment); } None diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 4cd5f3b81e5..25c7e5d38b3 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -4,8 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, - FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, - TypeBindingKind, + FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, TraitRef, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -138,10 +137,9 @@ fn future_trait_ref<'tcx>( fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'tcx>> { if let Some(segment) = trait_ref.path.segments.last() && let Some(args) = segment.args - && args.bindings.len() == 1 - && let binding = &args.bindings[0] - && binding.ident.name == sym::Output - && let TypeBindingKind::Equality { term: Term::Ty(output) } = binding.kind + && let [constraint] = args.constraints + && constraint.ident.name == sym::Output + && let Some(output) = constraint.ty() { return Some(output); } diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index d4a5f547211..bbdde3049db 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -108,7 +108,7 @@ pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool { pub fn eq_angle_arg(l: &AngleBracketedArg, r: &AngleBracketedArg) -> bool { match (l, r) { (AngleBracketedArg::Arg(l), AngleBracketedArg::Arg(r)) => eq_generic_arg(l, r), - (AngleBracketedArg::Constraint(l), AngleBracketedArg::Constraint(r)) => eq_assoc_constraint(l, r), + (AngleBracketedArg::Constraint(l), AngleBracketedArg::Constraint(r)) => eq_assoc_item_constraint(l, r), _ => false, } } @@ -802,8 +802,8 @@ fn eq_term(l: &Term, r: &Term) -> bool { } } -pub fn eq_assoc_constraint(l: &AssocConstraint, r: &AssocConstraint) -> bool { - use AssocConstraintKind::*; +pub fn eq_assoc_item_constraint(l: &AssocItemConstraint, r: &AssocItemConstraint) -> bool { + use AssocItemConstraintKind::*; eq_id(l.ident, r.ident) && match (&l.kind, &r.kind) { (Equality { term: l }, Equality { term: r }) => eq_term(l, r), diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 9f285621e0c..36634817fc9 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -9,7 +9,7 @@ use rustc_hir::MatchSource::TryDesugar; use rustc_hir::{ ArrayLen, BinOpKind, BindingMode, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField, PatKind, Path, - PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, + PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, AssocItemConstraint, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::LateContext; @@ -486,7 +486,7 @@ impl HirEqInterExpr<'_, '_, '_> { fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool { if left.parenthesized == right.parenthesized { over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work - && over(left.bindings, right.bindings, |l, r| self.eq_type_binding(l, r)) + && over(left.constraints, right.constraints, |l, r| self.eq_assoc_type_binding(l, r)) } else { false } @@ -518,8 +518,8 @@ impl HirEqInterExpr<'_, '_, '_> { } } - fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool { - left.ident.name == right.ident.name && self.eq_ty(left.ty(), right.ty()) + fn eq_assoc_type_binding(&mut self, left: &AssocItemConstraint<'_>, right: &AssocItemConstraint<'_>) -> bool { + left.ident.name == right.ident.name && self.eq_ty(left.ty().expect("expected assoc type binding"), right.ty().expect("expected assoc type binding")) } fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool { -- cgit 1.4.1-3-g733a5 From 5d0fcfbf56bb53fa70783c3d0d0251a3700b4bd5 Mon Sep 17 00:00:00 2001 From: Jacher Date: Thu, 30 May 2024 17:02:23 +0000 Subject: modify str_to_string to be machine-applicable --- clippy_lints/src/strings.rs | 10 +++++++--- tests/ui/str_to_string.fixed | 9 +++++++++ tests/ui/str_to_string.stderr | 7 ++----- 3 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 tests/ui/str_to_string.fixed diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index f8d36d6b92f..7da661485ab 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -399,13 +399,17 @@ impl<'tcx> LateLintPass<'tcx> for StrToString { && let ty::Ref(_, ty, ..) = ty.kind() && ty.is_str() { - span_lint_and_help( + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability); + + span_lint_and_sugg( cx, STR_TO_STRING, expr.span, "`to_string()` called on a `&str`", - None, - "consider using `.to_owned()`", + "try", + format!("{snippet}.to_owned()"), + applicability, ); } } diff --git a/tests/ui/str_to_string.fixed b/tests/ui/str_to_string.fixed new file mode 100644 index 00000000000..52e40b45a8b --- /dev/null +++ b/tests/ui/str_to_string.fixed @@ -0,0 +1,9 @@ +#![warn(clippy::str_to_string)] + +fn main() { + let hello = "hello world".to_owned(); + //~^ ERROR: `to_string()` called on a `&str` + let msg = &hello[..]; + msg.to_owned(); + //~^ ERROR: `to_string()` called on a `&str` +} diff --git a/tests/ui/str_to_string.stderr b/tests/ui/str_to_string.stderr index 13b73622d69..a761d96cd6b 100644 --- a/tests/ui/str_to_string.stderr +++ b/tests/ui/str_to_string.stderr @@ -2,9 +2,8 @@ error: `to_string()` called on a `&str` --> tests/ui/str_to_string.rs:4:17 | LL | let hello = "hello world".to_string(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"hello world".to_owned()` | - = help: consider using `.to_owned()` = note: `-D clippy::str-to-string` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::str_to_string)]` @@ -12,9 +11,7 @@ error: `to_string()` called on a `&str` --> tests/ui/str_to_string.rs:7:5 | LL | msg.to_string(); - | ^^^^^^^^^^^^^^^ - | - = help: consider using `.to_owned()` + | ^^^^^^^^^^^^^^^ help: try: `msg.to_owned()` error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From 4aa20d2e951d764c0345c5635daa0c9f0841dcd3 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 1 Jun 2024 13:44:13 +0200 Subject: deprecate `maybe_misused_cfg` --- clippy_lints/src/attrs/maybe_misused_cfg.rs | 51 --------------------------- clippy_lints/src/attrs/mod.rs | 35 ------------------- clippy_lints/src/declared_lints.rs | 1 - clippy_lints/src/deprecated_lints.rs | 13 +++++++ clippy_lints/src/lib.deprecated.rs | 4 +++ tests/ui/cfg_features.fixed | 29 ---------------- tests/ui/cfg_features.rs | 29 ---------------- tests/ui/cfg_features.stderr | 53 ----------------------------- tests/ui/deprecated.rs | 1 + tests/ui/deprecated.stderr | 8 ++++- tests/ui/unnecessary_clippy_cfg.rs | 8 ++--- tests/ui/unnecessary_clippy_cfg.stderr | 28 +++++++-------- 12 files changed, 43 insertions(+), 217 deletions(-) delete mode 100644 clippy_lints/src/attrs/maybe_misused_cfg.rs delete mode 100644 tests/ui/cfg_features.fixed delete mode 100644 tests/ui/cfg_features.rs delete mode 100644 tests/ui/cfg_features.stderr diff --git a/clippy_lints/src/attrs/maybe_misused_cfg.rs b/clippy_lints/src/attrs/maybe_misused_cfg.rs deleted file mode 100644 index e6b2e835be8..00000000000 --- a/clippy_lints/src/attrs/maybe_misused_cfg.rs +++ /dev/null @@ -1,51 +0,0 @@ -use super::{Attribute, MAYBE_MISUSED_CFG}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_ast::{MetaItemKind, NestedMetaItem}; -use rustc_errors::Applicability; -use rustc_lint::EarlyContext; -use rustc_span::sym; - -pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { - if attr.has_name(sym::cfg) - && let Some(items) = attr.meta_item_list() - { - check_nested_misused_cfg(cx, &items); - } -} - -fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { - for item in items { - if let NestedMetaItem::MetaItem(meta) = item { - if let Some(ident) = meta.ident() - && ident.name.as_str() == "features" - && let Some(val) = meta.value_str() - { - span_lint_and_sugg( - cx, - MAYBE_MISUSED_CFG, - meta.span, - "'feature' may be misspelled as 'features'", - "did you mean", - format!("feature = \"{val}\""), - Applicability::MaybeIncorrect, - ); - } - if let MetaItemKind::List(list) = &meta.kind { - check_nested_misused_cfg(cx, list); - // If this is not a list, then we check for `cfg(test)`. - } else if let Some(ident) = meta.ident() - && matches!(ident.name.as_str(), "tests" | "Test") - { - span_lint_and_sugg( - cx, - MAYBE_MISUSED_CFG, - meta.span, - format!("'test' may be misspelled as '{}'", ident.name.as_str()), - "did you mean", - "test".to_string(), - Applicability::MaybeIncorrect, - ); - } - } - } -} diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index a24bd5ed44b..764ad497dfe 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -7,7 +7,6 @@ mod deprecated_semver; mod duplicated_attributes; mod empty_line_after; mod inline_always; -mod maybe_misused_cfg; mod mismatched_target_os; mod mixed_attributes_style; mod non_minimal_cfg; @@ -391,38 +390,6 @@ declare_clippy_lint! { "ensure that all `cfg(any())` and `cfg(all())` have more than one condition" } -declare_clippy_lint! { - /// ### What it does - /// Checks for `#[cfg(features = "...")]` and suggests to replace it with - /// `#[cfg(feature = "...")]`. - /// - /// It also checks if `cfg(test)` was misspelled. - /// - /// ### Why is this bad? - /// Misspelling `feature` as `features` or `test` as `tests` can be sometimes hard to spot. It - /// may cause conditional compilation not work quietly. - /// - /// ### Example - /// ```no_run - /// #[cfg(features = "some-feature")] - /// fn conditional() { } - /// #[cfg(tests)] - /// mod tests { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// #[cfg(feature = "some-feature")] - /// fn conditional() { } - /// #[cfg(test)] - /// mod tests { } - /// ``` - #[clippy::version = "1.69.0"] - pub MAYBE_MISUSED_CFG, - suspicious, - "prevent from misusing the wrong attr name" -} - declare_clippy_lint! { /// ### What it does /// Checks for `#[cfg_attr(feature = "cargo-clippy", ...)]` and for @@ -616,7 +583,6 @@ impl_lint_pass!(EarlyAttributes => [ EMPTY_LINE_AFTER_OUTER_ATTR, EMPTY_LINE_AFTER_DOC_COMMENTS, NON_MINIMAL_CFG, - MAYBE_MISUSED_CFG, DEPRECATED_CLIPPY_CFG_ATTR, UNNECESSARY_CLIPPY_CFG, ]); @@ -631,7 +597,6 @@ impl EarlyLintPass for EarlyAttributes { deprecated_cfg_attr::check_clippy(cx, attr); mismatched_target_os::check(cx, attr); non_minimal_cfg::check(cx, attr); - maybe_misused_cfg::check(cx, attr); } extract_msrv_attr!(EarlyContext); diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index df2ef465700..a8d5004c3e2 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -58,7 +58,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::attrs::INLINE_ALWAYS_INFO, - crate::attrs::MAYBE_MISUSED_CFG_INFO, crate::attrs::MISMATCHED_TARGET_OS_INFO, crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO, crate::attrs::NON_MINIMAL_CFG_INFO, diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 9aa5af3190f..4c5d3f9d9ee 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -215,3 +215,16 @@ declare_deprecated_lint! { pub WRONG_PUB_SELF_CONVENTION, "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items" } + +declare_deprecated_lint! { + /// ### What it does + /// Nothing. This lint has been deprecated. + /// + /// ### Deprecation reason + /// This lint has been superseded by rustc's own [`unexpected_cfgs`] lint that is able to detect the `#[cfg(features)]` and `#[cfg(tests)]` typos. + /// + /// [`unexpected_cfgs`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unexpected-cfgs + #[clippy::version = "1.80.0"] + pub MAYBE_MISUSED_CFG, + "this lint has been replaced by `unexpected_cfgs`" +} diff --git a/clippy_lints/src/lib.deprecated.rs b/clippy_lints/src/lib.deprecated.rs index 80bde1b1138..01a23a032aa 100644 --- a/clippy_lints/src/lib.deprecated.rs +++ b/clippy_lints/src/lib.deprecated.rs @@ -67,4 +67,8 @@ "clippy::wrong_pub_self_convention", "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items", ); + store.register_removed( + "clippy::maybe_misused_cfg", + "this lint has been replaced by `unexpected_cfgs`", + ); } diff --git a/tests/ui/cfg_features.fixed b/tests/ui/cfg_features.fixed deleted file mode 100644 index 0fe38f169f9..00000000000 --- a/tests/ui/cfg_features.fixed +++ /dev/null @@ -1,29 +0,0 @@ -#![warn(clippy::maybe_misused_cfg)] - -fn main() { - #[cfg(feature = "not-really-a-feature")] - //~^ ERROR: 'feature' may be misspelled as 'features' - //~| NOTE: `-D clippy::maybe-misused-cfg` implied by `-D warnings` - let _ = 1 + 2; - - #[cfg(all(feature = "right", feature = "wrong"))] - //~^ ERROR: 'feature' may be misspelled as 'features' - let _ = 1 + 2; - - #[cfg(all(feature = "wrong1", any(feature = "right", feature = "wrong2", feature, features)))] - //~^ ERROR: 'feature' may be misspelled as 'features' - //~| ERROR: 'feature' may be misspelled as 'features' - let _ = 1 + 2; - - #[cfg(test)] - //~^ ERROR: 'test' may be misspelled as 'tests' - let _ = 2; - #[cfg(test)] - //~^ ERROR: 'test' may be misspelled as 'Test' - let _ = 2; - - #[cfg(all(test, test))] - //~^ ERROR: 'test' may be misspelled as 'tests' - //~| ERROR: 'test' may be misspelled as 'Test' - let _ = 2; -} diff --git a/tests/ui/cfg_features.rs b/tests/ui/cfg_features.rs deleted file mode 100644 index 9c0db035eac..00000000000 --- a/tests/ui/cfg_features.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![warn(clippy::maybe_misused_cfg)] - -fn main() { - #[cfg(features = "not-really-a-feature")] - //~^ ERROR: 'feature' may be misspelled as 'features' - //~| NOTE: `-D clippy::maybe-misused-cfg` implied by `-D warnings` - let _ = 1 + 2; - - #[cfg(all(feature = "right", features = "wrong"))] - //~^ ERROR: 'feature' may be misspelled as 'features' - let _ = 1 + 2; - - #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] - //~^ ERROR: 'feature' may be misspelled as 'features' - //~| ERROR: 'feature' may be misspelled as 'features' - let _ = 1 + 2; - - #[cfg(tests)] - //~^ ERROR: 'test' may be misspelled as 'tests' - let _ = 2; - #[cfg(Test)] - //~^ ERROR: 'test' may be misspelled as 'Test' - let _ = 2; - - #[cfg(all(tests, Test))] - //~^ ERROR: 'test' may be misspelled as 'tests' - //~| ERROR: 'test' may be misspelled as 'Test' - let _ = 2; -} diff --git a/tests/ui/cfg_features.stderr b/tests/ui/cfg_features.stderr deleted file mode 100644 index d576271f1a2..00000000000 --- a/tests/ui/cfg_features.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error: 'feature' may be misspelled as 'features' - --> tests/ui/cfg_features.rs:4:11 - | -LL | #[cfg(features = "not-really-a-feature")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "not-really-a-feature"` - | - = note: `-D clippy::maybe-misused-cfg` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::maybe_misused_cfg)]` - -error: 'feature' may be misspelled as 'features' - --> tests/ui/cfg_features.rs:9:34 - | -LL | #[cfg(all(feature = "right", features = "wrong"))] - | ^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "wrong"` - -error: 'feature' may be misspelled as 'features' - --> tests/ui/cfg_features.rs:13:15 - | -LL | #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] - | ^^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "wrong1"` - -error: 'feature' may be misspelled as 'features' - --> tests/ui/cfg_features.rs:13:59 - | -LL | #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] - | ^^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "wrong2"` - -error: 'test' may be misspelled as 'tests' - --> tests/ui/cfg_features.rs:18:11 - | -LL | #[cfg(tests)] - | ^^^^^ help: did you mean: `test` - -error: 'test' may be misspelled as 'Test' - --> tests/ui/cfg_features.rs:21:11 - | -LL | #[cfg(Test)] - | ^^^^ help: did you mean: `test` - -error: 'test' may be misspelled as 'tests' - --> tests/ui/cfg_features.rs:25:15 - | -LL | #[cfg(all(tests, Test))] - | ^^^^^ help: did you mean: `test` - -error: 'test' may be misspelled as 'Test' - --> tests/ui/cfg_features.rs:25:22 - | -LL | #[cfg(all(tests, Test))] - | ^^^^ help: did you mean: `test` - -error: aborting due to 8 previous errors - diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index 07270bd7636..178bd2f3b66 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -18,5 +18,6 @@ #![warn(clippy::filter_map)] #![warn(clippy::pub_enum_variant_names)] #![warn(clippy::wrong_pub_self_convention)] +#![warn(clippy::maybe_misused_cfg)] fn main() {} diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index a9cf04bea52..39a2278d8a6 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -97,5 +97,11 @@ error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid LL | #![warn(clippy::wrong_pub_self_convention)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 16 previous errors +error: lint `clippy::maybe_misused_cfg` has been removed: this lint has been replaced by `unexpected_cfgs` + --> tests/ui/deprecated.rs:21:9 + | +LL | #![warn(clippy::maybe_misused_cfg)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 17 previous errors diff --git a/tests/ui/unnecessary_clippy_cfg.rs b/tests/ui/unnecessary_clippy_cfg.rs index ff960520f5e..9915f8b843e 100644 --- a/tests/ui/unnecessary_clippy_cfg.rs +++ b/tests/ui/unnecessary_clippy_cfg.rs @@ -5,18 +5,18 @@ //~^ ERROR: no need to put clippy lints behind a `clippy` cfg #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg -#![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +#![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg -#![cfg_attr(clippy, deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +#![cfg_attr(clippy, deny(clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg #[cfg_attr(clippy, deny(clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg -#[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +#[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg -#[cfg_attr(clippy, deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +#[cfg_attr(clippy, deny(clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg pub struct Bar; diff --git a/tests/ui/unnecessary_clippy_cfg.stderr b/tests/ui/unnecessary_clippy_cfg.stderr index 3d58c9eb5da..16a86165295 100644 --- a/tests/ui/unnecessary_clippy_cfg.stderr +++ b/tests/ui/unnecessary_clippy_cfg.stderr @@ -18,16 +18,16 @@ LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] error: no need to put clippy lints behind a `clippy` cfg --> tests/ui/unnecessary_clippy_cfg.rs:17:36 | -LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] - | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: write instead: `#[deny(clippy::non_minimal_cfg,clippy::maybe_misused_cfg)]` + = note: write instead: `#[deny(clippy::non_minimal_cfg)]` error: no need to put clippy lints behind a `clippy` cfg --> tests/ui/unnecessary_clippy_cfg.rs:19:1 | -LL | #[cfg_attr(clippy, deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#[deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg)]` +LL | #[cfg_attr(clippy, deny(clippy::non_minimal_cfg))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#[deny(clippy::non_minimal_cfg)]` error: no need to put clippy lints behind a `clippy` cfg --> tests/ui/unnecessary_clippy_cfg.rs:4:1 @@ -46,21 +46,21 @@ LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] error: no need to put clippy lints behind a `clippy` cfg --> tests/ui/unnecessary_clippy_cfg.rs:8:37 | -LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] - | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: write instead: `#![deny(clippy::non_minimal_cfg,clippy::maybe_misused_cfg)]` + = note: write instead: `#![deny(clippy::non_minimal_cfg)]` error: no need to put clippy lints behind a `clippy` cfg --> tests/ui/unnecessary_clippy_cfg.rs:10:1 | -LL | #![cfg_attr(clippy, deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#![deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg)]` +LL | #![cfg_attr(clippy, deny(clippy::non_minimal_cfg))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#![deny(clippy::non_minimal_cfg)]` error: duplicated attribute --> tests/ui/unnecessary_clippy_cfg.rs:8:26 | -LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] | ^^^^^^^^^ | note: first defined here @@ -71,7 +71,7 @@ LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] help: remove this attribute --> tests/ui/unnecessary_clippy_cfg.rs:8:26 | -LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] | ^^^^^^^^^ = note: `-D clippy::duplicated-attributes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]` @@ -79,7 +79,7 @@ LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_ error: duplicated attribute --> tests/ui/unnecessary_clippy_cfg.rs:17:25 | -LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] | ^^^^^^^^^ | note: first defined here @@ -90,7 +90,7 @@ LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] help: remove this attribute --> tests/ui/unnecessary_clippy_cfg.rs:17:25 | -LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] | ^^^^^^^^^ error: aborting due to 10 previous errors -- cgit 1.4.1-3-g733a5 From 2334264463eee8aab8c4ebd642f80131d60603b8 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 27 Apr 2024 13:58:37 -0400 Subject: Deduplicate supertrait_def_ids code --- clippy_lints/src/len_zero.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 2091e74665f..57e0a7aa2c7 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -253,7 +253,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items // fill the set with current and super traits fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) { if set.insert(traitt) { - for supertrait in rustc_trait_selection::traits::supertrait_def_ids(cx.tcx, traitt) { + for supertrait in cx.tcx.supertrait_def_ids(traitt) { fill_trait_set(supertrait, set, cx); } } -- cgit 1.4.1-3-g733a5 From f950961c4270e9954e9c087417b53ab25b9ab48d Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 1 Jun 2024 14:11:07 +0200 Subject: deprecate `mismatched_target_os` --- clippy_lints/src/attrs/mismatched_target_os.rs | 90 ------------ clippy_lints/src/attrs/mod.rs | 36 ----- clippy_lints/src/declared_lints.rs | 1 - clippy_lints/src/deprecated_lints.rs | 13 ++ clippy_lints/src/lib.deprecated.rs | 4 + tests/ui/deprecated.rs | 1 + tests/ui/deprecated.stderr | 8 +- tests/ui/mismatched_target_os_non_unix.fixed | 25 ---- tests/ui/mismatched_target_os_non_unix.rs | 25 ---- tests/ui/mismatched_target_os_non_unix.stderr | 37 ----- tests/ui/mismatched_target_os_unix.fixed | 60 -------- tests/ui/mismatched_target_os_unix.rs | 60 -------- tests/ui/mismatched_target_os_unix.stderr | 184 ------------------------- 13 files changed, 25 insertions(+), 519 deletions(-) delete mode 100644 clippy_lints/src/attrs/mismatched_target_os.rs delete mode 100644 tests/ui/mismatched_target_os_non_unix.fixed delete mode 100644 tests/ui/mismatched_target_os_non_unix.rs delete mode 100644 tests/ui/mismatched_target_os_non_unix.stderr delete mode 100644 tests/ui/mismatched_target_os_unix.fixed delete mode 100644 tests/ui/mismatched_target_os_unix.rs delete mode 100644 tests/ui/mismatched_target_os_unix.stderr diff --git a/clippy_lints/src/attrs/mismatched_target_os.rs b/clippy_lints/src/attrs/mismatched_target_os.rs deleted file mode 100644 index b1cc0a763c5..00000000000 --- a/clippy_lints/src/attrs/mismatched_target_os.rs +++ /dev/null @@ -1,90 +0,0 @@ -use super::{Attribute, MISMATCHED_TARGET_OS}; -use clippy_utils::diagnostics::span_lint_and_then; -use rustc_ast::{MetaItemKind, NestedMetaItem}; -use rustc_errors::Applicability; -use rustc_lint::EarlyContext; -use rustc_span::{sym, Span}; - -static UNIX_SYSTEMS: &[&str] = &[ - "android", - "dragonfly", - "emscripten", - "freebsd", - "fuchsia", - "haiku", - "illumos", - "ios", - "l4re", - "linux", - "macos", - "netbsd", - "openbsd", - "redox", - "solaris", - "vxworks", -]; - -// NOTE: windows is excluded from the list because it's also a valid target family. -static NON_UNIX_SYSTEMS: &[&str] = &["hermit", "none", "wasi"]; - -pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { - fn find_os(name: &str) -> Option<&'static str> { - UNIX_SYSTEMS - .iter() - .chain(NON_UNIX_SYSTEMS.iter()) - .find(|&&os| os == name) - .copied() - } - - fn is_unix(name: &str) -> bool { - UNIX_SYSTEMS.iter().any(|&os| os == name) - } - - fn find_mismatched_target_os(items: &[NestedMetaItem]) -> Vec<(&str, Span)> { - let mut mismatched = Vec::new(); - - for item in items { - if let NestedMetaItem::MetaItem(meta) = item { - match &meta.kind { - MetaItemKind::List(list) => { - mismatched.extend(find_mismatched_target_os(list)); - }, - MetaItemKind::Word => { - if let Some(ident) = meta.ident() - && let Some(os) = find_os(ident.name.as_str()) - { - mismatched.push((os, ident.span)); - } - }, - MetaItemKind::NameValue(..) => {}, - } - } - } - - mismatched - } - - if attr.has_name(sym::cfg) - && let Some(list) = attr.meta_item_list() - && let mismatched = find_mismatched_target_os(&list) - && !mismatched.is_empty() - { - let mess = "operating system used in target family position"; - - span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, mess, |diag| { - // Avoid showing the unix suggestion multiple times in case - // we have more than one mismatch for unix-like systems - let mut unix_suggested = false; - - for (os, span) in mismatched { - let sugg = format!("target_os = \"{os}\""); - diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect); - - if !unix_suggested && is_unix(os) { - diag.help("did you mean `unix`?"); - unix_suggested = true; - } - } - }); - } -} diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 764ad497dfe..83c828e8e22 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -7,7 +7,6 @@ mod deprecated_semver; mod duplicated_attributes; mod empty_line_after; mod inline_always; -mod mismatched_target_os; mod mixed_attributes_style; mod non_minimal_cfg; mod should_panic_without_expect; @@ -269,39 +268,6 @@ declare_clippy_lint! { "usage of `cfg_attr(rustfmt)` instead of tool attributes" } -declare_clippy_lint! { - /// ### What it does - /// Checks for cfg attributes having operating systems used in target family position. - /// - /// ### Why is this bad? - /// The configuration option will not be recognised and the related item will not be included - /// by the conditional compilation engine. - /// - /// ### Example - /// ```no_run - /// #[cfg(linux)] - /// fn conditional() { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// # mod hidden { - /// #[cfg(target_os = "linux")] - /// fn conditional() { } - /// # } - /// - /// // or - /// - /// #[cfg(unix)] - /// fn conditional() { } - /// ``` - /// Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details. - #[clippy::version = "1.45.0"] - pub MISMATCHED_TARGET_OS, - correctness, - "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`" -} - declare_clippy_lint! { /// ### What it does /// Checks for attributes that allow lints without a reason. @@ -579,7 +545,6 @@ pub struct EarlyAttributes { impl_lint_pass!(EarlyAttributes => [ DEPRECATED_CFG_ATTR, - MISMATCHED_TARGET_OS, EMPTY_LINE_AFTER_OUTER_ATTR, EMPTY_LINE_AFTER_DOC_COMMENTS, NON_MINIMAL_CFG, @@ -595,7 +560,6 @@ impl EarlyLintPass for EarlyAttributes { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { deprecated_cfg_attr::check(cx, attr, &self.msrv); deprecated_cfg_attr::check_clippy(cx, attr); - mismatched_target_os::check(cx, attr); non_minimal_cfg::check(cx, attr); } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index a8d5004c3e2..9aa0c0c7289 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -58,7 +58,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::attrs::INLINE_ALWAYS_INFO, - crate::attrs::MISMATCHED_TARGET_OS_INFO, crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO, crate::attrs::NON_MINIMAL_CFG_INFO, crate::attrs::SHOULD_PANIC_WITHOUT_EXPECT_INFO, diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 4c5d3f9d9ee..a0900f46f6a 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -228,3 +228,16 @@ declare_deprecated_lint! { pub MAYBE_MISUSED_CFG, "this lint has been replaced by `unexpected_cfgs`" } + +declare_deprecated_lint! { + /// ### What it does + /// Nothing. This lint has been deprecated. + /// + /// ### Deprecation reason + /// This lint has been superseded by rustc's own [`unexpected_cfgs`] lint that is able to detect invalid `#[cfg(linux)]` attributes. + /// + /// [`unexpected_cfgs`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unexpected-cfgs + #[clippy::version = "1.80.0"] + pub MISMATCHED_TARGET_OS, + "this lint has been replaced by `unexpected_cfgs`" +} diff --git a/clippy_lints/src/lib.deprecated.rs b/clippy_lints/src/lib.deprecated.rs index 01a23a032aa..0d21261822d 100644 --- a/clippy_lints/src/lib.deprecated.rs +++ b/clippy_lints/src/lib.deprecated.rs @@ -71,4 +71,8 @@ "clippy::maybe_misused_cfg", "this lint has been replaced by `unexpected_cfgs`", ); + store.register_removed( + "clippy::mismatched_target_os", + "this lint has been replaced by `unexpected_cfgs`", + ); } diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index 178bd2f3b66..d3c34fb3716 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -19,5 +19,6 @@ #![warn(clippy::pub_enum_variant_names)] #![warn(clippy::wrong_pub_self_convention)] #![warn(clippy::maybe_misused_cfg)] +#![warn(clippy::mismatched_target_os)] fn main() {} diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index 39a2278d8a6..49b90c70c06 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -103,5 +103,11 @@ error: lint `clippy::maybe_misused_cfg` has been removed: this lint has been rep LL | #![warn(clippy::maybe_misused_cfg)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 17 previous errors +error: lint `clippy::mismatched_target_os` has been removed: this lint has been replaced by `unexpected_cfgs` + --> tests/ui/deprecated.rs:22:9 + | +LL | #![warn(clippy::mismatched_target_os)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 18 previous errors diff --git a/tests/ui/mismatched_target_os_non_unix.fixed b/tests/ui/mismatched_target_os_non_unix.fixed deleted file mode 100644 index de02b2bee31..00000000000 --- a/tests/ui/mismatched_target_os_non_unix.fixed +++ /dev/null @@ -1,25 +0,0 @@ -#![warn(clippy::mismatched_target_os)] -#![allow(unused)] - -#[cfg(target_os = "hermit")] -fn hermit() {} - -#[cfg(target_os = "wasi")] -fn wasi() {} - -#[cfg(target_os = "none")] -fn none() {} - -// list with conditions -#[cfg(all(not(windows), target_os = "wasi"))] -fn list() {} - -// windows is a valid target family, should be ignored -#[cfg(windows)] -fn windows() {} - -// correct use, should be ignored -#[cfg(target_os = "hermit")] -fn correct() {} - -fn main() {} diff --git a/tests/ui/mismatched_target_os_non_unix.rs b/tests/ui/mismatched_target_os_non_unix.rs deleted file mode 100644 index a960518751b..00000000000 --- a/tests/ui/mismatched_target_os_non_unix.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![warn(clippy::mismatched_target_os)] -#![allow(unused)] - -#[cfg(hermit)] -fn hermit() {} - -#[cfg(wasi)] -fn wasi() {} - -#[cfg(none)] -fn none() {} - -// list with conditions -#[cfg(all(not(windows), wasi))] -fn list() {} - -// windows is a valid target family, should be ignored -#[cfg(windows)] -fn windows() {} - -// correct use, should be ignored -#[cfg(target_os = "hermit")] -fn correct() {} - -fn main() {} diff --git a/tests/ui/mismatched_target_os_non_unix.stderr b/tests/ui/mismatched_target_os_non_unix.stderr deleted file mode 100644 index 7f7a4e9d6f6..00000000000 --- a/tests/ui/mismatched_target_os_non_unix.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error: operating system used in target family position - --> tests/ui/mismatched_target_os_non_unix.rs:4:1 - | -LL | #[cfg(hermit)] - | ^^^^^^------^^ - | | - | help: try: `target_os = "hermit"` - | - = note: `-D clippy::mismatched-target-os` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::mismatched_target_os)]` - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_non_unix.rs:7:1 - | -LL | #[cfg(wasi)] - | ^^^^^^----^^ - | | - | help: try: `target_os = "wasi"` - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_non_unix.rs:10:1 - | -LL | #[cfg(none)] - | ^^^^^^----^^ - | | - | help: try: `target_os = "none"` - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_non_unix.rs:14:1 - | -LL | #[cfg(all(not(windows), wasi))] - | ^^^^^^^^^^^^^^^^^^^^^^^^----^^^ - | | - | help: try: `target_os = "wasi"` - -error: aborting due to 4 previous errors - diff --git a/tests/ui/mismatched_target_os_unix.fixed b/tests/ui/mismatched_target_os_unix.fixed deleted file mode 100644 index b945c4d9619..00000000000 --- a/tests/ui/mismatched_target_os_unix.fixed +++ /dev/null @@ -1,60 +0,0 @@ -#![warn(clippy::mismatched_target_os)] -#![allow(unused)] - -#[cfg(target_os = "linux")] -fn linux() {} - -#[cfg(target_os = "freebsd")] -fn freebsd() {} - -#[cfg(target_os = "dragonfly")] -fn dragonfly() {} - -#[cfg(target_os = "openbsd")] -fn openbsd() {} - -#[cfg(target_os = "netbsd")] -fn netbsd() {} - -#[cfg(target_os = "macos")] -fn macos() {} - -#[cfg(target_os = "ios")] -fn ios() {} - -#[cfg(target_os = "android")] -fn android() {} - -#[cfg(target_os = "emscripten")] -fn emscripten() {} - -#[cfg(target_os = "fuchsia")] -fn fuchsia() {} - -#[cfg(target_os = "haiku")] -fn haiku() {} - -#[cfg(target_os = "illumos")] -fn illumos() {} - -#[cfg(target_os = "l4re")] -fn l4re() {} - -#[cfg(target_os = "redox")] -fn redox() {} - -#[cfg(target_os = "solaris")] -fn solaris() {} - -#[cfg(target_os = "vxworks")] -fn vxworks() {} - -// list with conditions -#[cfg(all(not(any(target_os = "solaris", target_os = "linux")), target_os = "freebsd"))] -fn list() {} - -// correct use, should be ignored -#[cfg(target_os = "freebsd")] -fn correct() {} - -fn main() {} diff --git a/tests/ui/mismatched_target_os_unix.rs b/tests/ui/mismatched_target_os_unix.rs deleted file mode 100644 index 34307facd65..00000000000 --- a/tests/ui/mismatched_target_os_unix.rs +++ /dev/null @@ -1,60 +0,0 @@ -#![warn(clippy::mismatched_target_os)] -#![allow(unused)] - -#[cfg(linux)] -fn linux() {} - -#[cfg(freebsd)] -fn freebsd() {} - -#[cfg(dragonfly)] -fn dragonfly() {} - -#[cfg(openbsd)] -fn openbsd() {} - -#[cfg(netbsd)] -fn netbsd() {} - -#[cfg(macos)] -fn macos() {} - -#[cfg(ios)] -fn ios() {} - -#[cfg(android)] -fn android() {} - -#[cfg(emscripten)] -fn emscripten() {} - -#[cfg(fuchsia)] -fn fuchsia() {} - -#[cfg(haiku)] -fn haiku() {} - -#[cfg(illumos)] -fn illumos() {} - -#[cfg(l4re)] -fn l4re() {} - -#[cfg(redox)] -fn redox() {} - -#[cfg(solaris)] -fn solaris() {} - -#[cfg(vxworks)] -fn vxworks() {} - -// list with conditions -#[cfg(all(not(any(solaris, linux)), freebsd))] -fn list() {} - -// correct use, should be ignored -#[cfg(target_os = "freebsd")] -fn correct() {} - -fn main() {} diff --git a/tests/ui/mismatched_target_os_unix.stderr b/tests/ui/mismatched_target_os_unix.stderr deleted file mode 100644 index 3071bad1324..00000000000 --- a/tests/ui/mismatched_target_os_unix.stderr +++ /dev/null @@ -1,184 +0,0 @@ -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:4:1 - | -LL | #[cfg(linux)] - | ^^^^^^-----^^ - | | - | help: try: `target_os = "linux"` - | - = help: did you mean `unix`? - = note: `-D clippy::mismatched-target-os` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::mismatched_target_os)]` - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:7:1 - | -LL | #[cfg(freebsd)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "freebsd"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:10:1 - | -LL | #[cfg(dragonfly)] - | ^^^^^^---------^^ - | | - | help: try: `target_os = "dragonfly"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:13:1 - | -LL | #[cfg(openbsd)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "openbsd"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:16:1 - | -LL | #[cfg(netbsd)] - | ^^^^^^------^^ - | | - | help: try: `target_os = "netbsd"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:19:1 - | -LL | #[cfg(macos)] - | ^^^^^^-----^^ - | | - | help: try: `target_os = "macos"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:22:1 - | -LL | #[cfg(ios)] - | ^^^^^^---^^ - | | - | help: try: `target_os = "ios"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:25:1 - | -LL | #[cfg(android)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "android"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:28:1 - | -LL | #[cfg(emscripten)] - | ^^^^^^----------^^ - | | - | help: try: `target_os = "emscripten"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:31:1 - | -LL | #[cfg(fuchsia)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "fuchsia"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:34:1 - | -LL | #[cfg(haiku)] - | ^^^^^^-----^^ - | | - | help: try: `target_os = "haiku"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:37:1 - | -LL | #[cfg(illumos)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "illumos"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:40:1 - | -LL | #[cfg(l4re)] - | ^^^^^^----^^ - | | - | help: try: `target_os = "l4re"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:43:1 - | -LL | #[cfg(redox)] - | ^^^^^^-----^^ - | | - | help: try: `target_os = "redox"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:46:1 - | -LL | #[cfg(solaris)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "solaris"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:49:1 - | -LL | #[cfg(vxworks)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "vxworks"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:53:1 - | -LL | #[cfg(all(not(any(solaris, linux)), freebsd))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: did you mean `unix`? -help: try - | -LL | #[cfg(all(not(any(target_os = "solaris", linux)), freebsd))] - | ~~~~~~~~~~~~~~~~~~~~~ -help: try - | -LL | #[cfg(all(not(any(solaris, target_os = "linux")), freebsd))] - | ~~~~~~~~~~~~~~~~~~~ -help: try - | -LL | #[cfg(all(not(any(solaris, linux)), target_os = "freebsd"))] - | ~~~~~~~~~~~~~~~~~~~~~ - -error: aborting due to 17 previous errors - -- cgit 1.4.1-3-g733a5 From 5a44877a394569261cd53b23003113272349cf68 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 31 May 2024 14:13:46 -0400 Subject: Uplift TypeRelation and Relate --- clippy_lints/src/eta_reduction.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index b58018ca035..48c4c4206fe 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -10,7 +10,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, Ty, - TypeVisitableExt, TypeckResults, + TypeVisitableExt, TypeckResults, TyCtxt, }; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; @@ -240,7 +240,7 @@ fn check_inputs( }) } -fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<'tcx>, call_sig: FnSig<'_>) -> bool { +fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs>, call_sig: FnSig<'_>) -> bool { call_sig.safety == Safety::Safe && !has_late_bound_to_non_late_bound_regions( cx.tcx.signature_unclosure(closure.sig(), Safety::Safe).skip_binder(), -- cgit 1.4.1-3-g733a5 From 25d40c9f6b09b4decd17c564c037e1f8de9859b2 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 1 Jun 2024 20:10:48 +0200 Subject: handle parent const effects correctly in type_certainty --- clippy_utils/src/ty/type_certainty/mod.rs | 14 ++++++++++++-- tests/ui/or_fun_call.fixed | 7 +++++++ tests/ui/or_fun_call.rs | 7 +++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs index 80219303450..cba61c841ef 100644 --- a/clippy_utils/src/ty/type_certainty/mod.rs +++ b/clippy_utils/src/ty/type_certainty/mod.rs @@ -206,8 +206,18 @@ fn path_segment_certainty( // Checking `res_generics_def_id(..)` before calling `generics_of` avoids an ICE. if cx.tcx.res_generics_def_id(path_segment.res).is_some() { let generics = cx.tcx.generics_of(def_id); - let count = generics.own_params.len() - usize::from(generics.host_effect_index.is_some()); - let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && count == 0 { + + let own_count = generics.own_params.len() + - usize::from(generics.host_effect_index.is_some_and(|index| { + // Check that the host index actually belongs to this resolution. + // E.g. for `Add::add`, host_effect_index is `Some(2)`, but it's part of the parent `Add` + // trait's generics. + // Add params: [Self#0, Rhs#1, host#2] parent_count=0, count=3 + // Add::add params: [] parent_count=3, count=3 + // (3..3).contains(&host_effect_index) => false + (generics.parent_count..generics.count()).contains(&index) + })); + let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && own_count == 0 { Certainty::Certain(None) } else { Certainty::Uncertain diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index e7ba54864ab..7657ef470c5 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -311,4 +311,11 @@ mod lazy { } } +fn host_effect() { + // #12877 - make sure we don't ICE in type_certainty + use std::ops::Add; + + Add::::add(1, 1).add(i32::MIN); +} + fn main() {} diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 196632133d5..97cf496d3ac 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -311,4 +311,11 @@ mod lazy { } } +fn host_effect() { + // #12877 - make sure we don't ICE in type_certainty + use std::ops::Add; + + Add::::add(1, 1).add(i32::MIN); +} + fn main() {} -- cgit 1.4.1-3-g733a5 From e94779a396619b63b99dd6494a5a940c59518d8e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 1 Jun 2024 14:51:31 -0400 Subject: Opt-in diagnostics reporting to avoid doing extra work in the new solver --- clippy_lints/src/future_not_send.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 192fb611c2d..cb1d0de1edf 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -79,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); let infcx = cx.tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let cause = traits::ObligationCause::misc(span, fn_def_id); ocx.register_bound(cause, cx.param_env, ret_ty, send_trait); let send_errors = ocx.select_all_or_error(); -- cgit 1.4.1-3-g733a5 From 708ef7955d4c326e990e5b435523c131a98c14d7 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 3 Jun 2024 21:31:33 +0200 Subject: only run flop lints on inherent method calls --- clippy_lints/src/floating_point_arithmetic.rs | 5 +++-- clippy_utils/src/lib.rs | 9 +++++++++ tests/ui/floating_point_log.fixed | 15 +++++++++++++++ tests/ui/floating_point_log.rs | 15 +++++++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 46d47e217b0..68bdf88d0a7 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -2,7 +2,8 @@ use clippy_utils::consts::Constant::{Int, F32, F64}; use clippy_utils::consts::{constant, constant_simple, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{ - eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate, numeric_literal, peel_blocks, sugg, + eq_expr_value, get_parent_expr, higher, in_constant, is_inherent_method_call, is_no_std_crate, numeric_literal, + peel_blocks, sugg, }; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; @@ -759,7 +760,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind { let recv_ty = cx.typeck_results().expr_ty(receiver); - if recv_ty.is_floating_point() && !is_no_std_crate(cx) { + if recv_ty.is_floating_point() && !is_no_std_crate(cx) && is_inherent_method_call(cx, expr) { match path.ident.name.as_str() { "ln" => check_ln1p(cx, expr, receiver), "log" => check_log_base(cx, expr, receiver, args), diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index b10830b24e1..6d6c4ffbe5d 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -321,6 +321,15 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) .map_or(false, |trt_id| match_def_path(cx, trt_id, path)) } +/// Checks if the given method call expression calls an inherent method. +pub fn is_inherent_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { + cx.tcx.trait_of_item(method_id).is_none() + } else { + false + } +} + /// Checks if a method is defined in an impl of a diagnostic item pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool { if let Some(impl_did) = cx.tcx.impl_of_method(def_id) { diff --git a/tests/ui/floating_point_log.fixed b/tests/ui/floating_point_log.fixed index 01f0fc5c671..15cc47eef0d 100644 --- a/tests/ui/floating_point_log.fixed +++ b/tests/ui/floating_point_log.fixed @@ -55,4 +55,19 @@ fn check_ln1p() { let _ = (1.0 + x - 2.0).ln(); } +fn issue12881() { + pub trait MyLog { + fn log(&self) -> Self; + } + + impl MyLog for f32 { + fn log(&self) -> Self { + 4. + } + } + + let x = 2.0; + x.log(); +} + fn main() {} diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index 197e3e1ff90..1241af82859 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -55,4 +55,19 @@ fn check_ln1p() { let _ = (1.0 + x - 2.0).ln(); } +fn issue12881() { + pub trait MyLog { + fn log(&self) -> Self; + } + + impl MyLog for f32 { + fn log(&self) -> Self { + 4. + } + } + + let x = 2.0; + x.log(); +} + fn main() {} -- cgit 1.4.1-3-g733a5 From 9173c58e68e49defe25aa09c1614400c0ab139ca Mon Sep 17 00:00:00 2001 From: Renato Lochetti Date: Mon, 3 Jun 2024 20:46:05 +0100 Subject: Using Clippy as a proper noun when refering to the unique entity Clippy --- README.md | 4 ++-- book/src/configuration.md | 2 +- book/src/development/basics.md | 2 +- book/src/development/defining_lints.md | 4 ++-- book/src/development/proposals/syntax-tree-patterns.md | 12 ++++++------ clippy_dummy/PUBLISH.md | 2 +- clippy_dummy/crates-readme.md | 4 ++-- lintcheck/README.md | 4 ++-- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index fa18447090c..ec76a6dfb08 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ You can add options to your code to `allow`/`warn`/`deny` Clippy lints: Note: `allow` means to suppress the lint for your code. With `warn` the lint will only emit a warning, while with `deny` the lint will emit an error, when -triggering for your code. An error causes clippy to exit with an error code, so +triggering for your code. An error causes Clippy to exit with an error code, so is useful in scripts like CI/CD. If you do not want to include your lint levels in your code, you can globally @@ -238,7 +238,7 @@ define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable. ### Specifying the minimum supported Rust version Projects that intend to support old versions of Rust can disable lints pertaining to newer features by -specifying the minimum supported Rust version (MSRV) in the clippy configuration file. +specifying the minimum supported Rust version (MSRV) in the Clippy configuration file. ```toml msrv = "1.30.0" diff --git a/book/src/configuration.md b/book/src/configuration.md index ea549e4df4a..b1305443189 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -99,7 +99,7 @@ For more details and options, refer to the Cargo documentation. ### Specifying the minimum supported Rust version Projects that intend to support old versions of Rust can disable lints pertaining to newer features by specifying the -minimum supported Rust version (MSRV) in the clippy configuration file. +minimum supported Rust version (MSRV) in the Clippy configuration file. ```toml msrv = "1.30.0" diff --git a/book/src/development/basics.md b/book/src/development/basics.md index f4c109ff119..166b6aab9fb 100644 --- a/book/src/development/basics.md +++ b/book/src/development/basics.md @@ -107,7 +107,7 @@ More about [intellij] command usage and reasons. ## lintcheck -`cargo lintcheck` will build and run clippy on a fixed set of crates and +`cargo lintcheck` will build and run Clippy on a fixed set of crates and generate a log of the results. You can `git diff` the updated log against its previous version and see what impact your lint made on a small set of crates. If you add a new lint, please audit the resulting warnings and make sure there diff --git a/book/src/development/defining_lints.md b/book/src/development/defining_lints.md index 806ed0845f0..ceabb255e2d 100644 --- a/book/src/development/defining_lints.md +++ b/book/src/development/defining_lints.md @@ -163,11 +163,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // example code where clippy issues a warning + /// // example code where Clippy issues a warning /// ``` /// Use instead: /// ```rust - /// // example code which does not raise clippy warning + /// // example code which does not raise Clippy warning /// ``` #[clippy::version = "1.70.0"] // <- In which version was this implemented, keep it up to date! pub LINT_NAME, // <- The lint name IN_ALL_CAPS diff --git a/book/src/development/proposals/syntax-tree-patterns.md b/book/src/development/proposals/syntax-tree-patterns.md index 285488cec55..92fbf733a8f 100644 --- a/book/src/development/proposals/syntax-tree-patterns.md +++ b/book/src/development/proposals/syntax-tree-patterns.md @@ -428,7 +428,7 @@ selection of possible matches is produced by the pattern syntax. In the second stage, the named subpattern references can be used to do additional tests like asserting that a node hasn't been created as part of a macro expansion. -## Implementing clippy lints using patterns +## Implementing Clippy lints using patterns As a "real-world" example, I re-implemented the `collapsible_if` lint using patterns. The code can be found @@ -572,7 +572,7 @@ The pattern syntax and the *PatternTree* are independent of specific syntax tree implementations (rust ast / hir, syn, ...). When looking at the different pattern examples in the previous sections, it can be seen that the patterns don't contain any information specific to a certain syntax tree implementation. -In contrast, clippy lints currently match against ast / hir syntax tree nodes +In contrast, Clippy lints currently match against ast / hir syntax tree nodes and therefore directly depend on their implementation. The connection between the *PatternTree* and specific syntax tree @@ -690,7 +690,7 @@ change, only the `IsMatch` trait implementations need to be adapted and existing lints can remain unchanged. This also means that if the `IsMatch` trait implementations were integrated into the compiler, updating the `IsMatch` implementations would be required for the compiler to compile successfully. This -could reduce the number of times clippy breaks because of changes in the +could reduce the number of times Clippy breaks because of changes in the compiler. Another advantage of the pattern's independence is that converting an `EarlyLintPass` lint into a `LatePassLint` wouldn't require rewriting the whole pattern matching code. In fact, the pattern might work just fine without any @@ -777,7 +777,7 @@ complexity to solve a relatively minor problem. The issue of users not knowing about the *PatternTree* structure could be solved by a tool that, given a rust program, generates a pattern that matches only this -program (similar to the clippy author lint). +program (similar to the Clippy author lint). For some simple cases (like the first example above), it might be possible to successfully mix Rust and pattern syntax. This space could be further explored @@ -789,7 +789,7 @@ The pattern syntax is heavily inspired by regular expressions (repetitions, alternatives, sequences, ...). From what I've seen until now, other linters also implement lints that directly -work on syntax tree data structures, just like clippy does currently. I would +work on syntax tree data structures, just like Clippy does currently. I would therefore consider the pattern syntax to be *new*, but please correct me if I'm wrong. @@ -982,5 +982,5 @@ pattern!{ } ``` -In the future, clippy could use this system to also provide lints for custom +In the future, Clippy could use this system to also provide lints for custom syntaxes like those found in macros. diff --git a/clippy_dummy/PUBLISH.md b/clippy_dummy/PUBLISH.md index 8e420ec959a..f0021f1594f 100644 --- a/clippy_dummy/PUBLISH.md +++ b/clippy_dummy/PUBLISH.md @@ -1,5 +1,5 @@ This is a dummy crate to publish to crates.io. It primarily exists to ensure -that folks trying to install clippy from crates.io get redirected to the +that folks trying to install Clippy from crates.io get redirected to the `rustup` technique. Before publishing, be sure to rename `clippy_dummy` to `clippy` in `Cargo.toml`, diff --git a/clippy_dummy/crates-readme.md b/clippy_dummy/crates-readme.md index 0decae8b910..a8ec0a1c36c 100644 --- a/clippy_dummy/crates-readme.md +++ b/clippy_dummy/crates-readme.md @@ -1,9 +1,9 @@ -Installing clippy via crates.io is deprecated. Please use the following: +Installing Clippy via crates.io is deprecated. Please use the following: ```terminal rustup component add clippy ``` -on a Rust version 1.29 or later. You may need to run `rustup self update` if it complains about a missing clippy binary. +on a Rust version 1.29 or later. You may need to run `rustup self update` if it complains about a missing Clippy binary. See [the homepage](https://github.com/rust-lang/rust-clippy/#clippy) for more information diff --git a/lintcheck/README.md b/lintcheck/README.md index 37cc0453809..61b581ba0fa 100644 --- a/lintcheck/README.md +++ b/lintcheck/README.md @@ -1,6 +1,6 @@ ## `cargo lintcheck` -Runs clippy on a fixed set of crates read from +Runs Clippy on a fixed set of crates read from `lintcheck/lintcheck_crates.toml` and saves logs of the lint warnings into the repo. We can then check the diff and spot new or disappearing warnings. @@ -84,7 +84,7 @@ This lets us spot bad suggestions or false positives automatically in some cases > Note: Fix mode implies `--all-targets`, so it can fix as much code as it can. -Please note that the target dir should be cleaned afterwards since clippy will modify +Please note that the target dir should be cleaned afterwards since Clippy will modify the downloaded sources which can lead to unexpected results when running lintcheck again afterwards. ### Recursive mode -- cgit 1.4.1-3-g733a5 From 9f4a2dd1475638fda91f5cf54650b55b320575fe Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 29 May 2024 22:23:49 -0400 Subject: Align Term methods with GenericArg methods --- clippy_lints/src/methods/iter_on_single_or_empty_collections.rs | 2 +- clippy_lints/src/needless_borrows_for_generic_args.rs | 4 ++-- clippy_lints/src/unit_return_expecting_ord.rs | 4 ++-- clippy_utils/src/ty.rs | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index f4397212cf6..7f6b666e434 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -42,7 +42,7 @@ fn is_arg_ty_unified_in_fn<'tcx>( cx.tcx.predicates_of(fn_id).predicates.iter().any(|(clause, _)| { clause .as_projection_clause() - .and_then(|p| p.map_bound(|p| p.term.ty()).transpose()) + .and_then(|p| p.map_bound(|p| p.term.as_type()).transpose()) .is_some_and(|ty| ty.skip_binder() == arg_ty_in_args) }) || fn_sig .inputs() diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index 5b5e1c23424..4f99eaa40c2 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -311,7 +311,7 @@ fn is_mixed_projection_predicate<'tcx>( ) -> bool { let generics = cx.tcx.generics_of(callee_def_id); // The predicate requires the projected type to equal a type parameter from the parent context. - if let Some(term_ty) = projection_predicate.term.ty() + if let Some(term_ty) = projection_predicate.term.as_type() && let ty::Param(term_param_ty) = term_ty.kind() && (term_param_ty.index as usize) < generics.parent_count { @@ -370,7 +370,7 @@ fn replace_types<'tcx>( if replaced.insert(param_ty.index) { for projection_predicate in projection_predicates { if projection_predicate.projection_term.self_ty() == param_ty.to_ty(cx.tcx) - && let Some(term_ty) = projection_predicate.term.ty() + && let Some(term_ty) = projection_predicate.term.as_type() && let ty::Param(term_param_ty) = term_ty.kind() { let projection = projection_predicate diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index f0d1458a59b..a8cc2f97963 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -100,12 +100,12 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve { if ord_preds .iter() - .any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty()) + .any(|ord| Some(ord.self_ty()) == return_ty_pred.term.as_type()) { args_to_check.push((i, "Ord".to_string())); } else if partial_ord_preds .iter() - .any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) + .any(|pord| pord.self_ty() == return_ty_pred.term.expect_type()) { args_to_check.push((i, "PartialOrd".to_string())); } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 3414b5ef680..f0dac6f5d9c 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -750,7 +750,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option None, @@ -798,7 +798,7 @@ fn sig_from_bounds<'tcx>( // Multiple different fn trait impls. Is this even allowed? return None; } - output = Some(pred.kind().rebind(p.term.ty().unwrap())); + output = Some(pred.kind().rebind(p.term.expect_type())); }, _ => (), } @@ -836,7 +836,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option // Multiple different fn trait impls. Is this even allowed? return None; } - output = pred.kind().rebind(p.term.ty()).transpose(); + output = pred.kind().rebind(p.term.as_type()).transpose(); }, _ => (), } -- cgit 1.4.1-3-g733a5 From 537ce5c8c6d4f592461ff883b95b61a14a4932ae Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 23 May 2024 10:01:05 -0300 Subject: Handle safety keyword for extern block inner items --- clippy_utils/src/ast_utils.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index bbdde3049db..14f9ef8966d 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -451,13 +451,15 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { ty: lt, mutability: lm, expr: le, + safety: ls, }), Static(box StaticForeignItem { ty: rt, mutability: rm, expr: re, + safety: rs, }), - ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re) && ls == rs, ( Fn(box ast::Fn { defaultness: ld, -- cgit 1.4.1-3-g733a5 From bd0f90824274d20bcace9d0149f1ffb0450e23cc Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 7 May 2024 14:43:23 +0200 Subject: Add safe/unsafe to static inside extern blocks --- clippy_utils/src/ast_utils.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 14f9ef8966d..c70f5c2df84 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -308,13 +308,15 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ty: lt, mutability: lm, expr: le, + safety: ls, }), Static(box StaticItem { ty: rt, mutability: rm, expr: re, + safety: rs, }), - ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + ) => lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Const(box ConstItem { defaultness: ld, -- cgit 1.4.1-3-g733a5 From 158b65889cb5e5be2b367c1acb349c966e70543f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 3 Jun 2024 21:57:47 +0200 Subject: Fix false positive for `needless_character_iteration` lint --- clippy_lints/src/methods/mod.rs | 3 ++- .../src/methods/needless_character_iteration.rs | 26 +++++++++++++++++----- tests/ui/needless_character_iteration.fixed | 6 +++++ tests/ui/needless_character_iteration.rs | 14 ++++++++---- tests/ui/needless_character_iteration.stderr | 8 +++---- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1572f6fb601..6a535c11a98 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4485,7 +4485,7 @@ impl Methods { }, ("all", [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); - needless_character_iteration::check(cx, expr, recv, arg); + needless_character_iteration::check(cx, expr, recv, arg, true); if let Some(("cloned", recv2, [], _, _)) = method_call(recv) { iter_overeager_cloned::check( cx, @@ -4506,6 +4506,7 @@ impl Methods { }, ("any", [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); + needless_character_iteration::check(cx, expr, recv, arg, false); match method_call(recv) { Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( cx, diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs index f4467af4de8..e3d78207715 100644 --- a/clippy_lints/src/methods/needless_character_iteration.rs +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -24,10 +24,14 @@ fn handle_expr( span: Span, before_chars: Span, revert: bool, + is_all: bool, ) { match expr.kind { ExprKind::MethodCall(method, receiver, [], _) => { - if method.ident.name.as_str() == "is_ascii" + // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is + // `is_ascii`, then only `.all()` should warn. + if revert != is_all + && method.ident.name.as_str() == "is_ascii" && path_to_local_id(receiver, first_param) && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() && *char_arg_ty.kind() == ty::Char @@ -55,12 +59,23 @@ fn handle_expr( && let Some(last_chain_binding_id) = get_last_chain_binding_hir_id(first_param, block.stmts) { - handle_expr(cx, block_expr, last_chain_binding_id, span, before_chars, revert); + handle_expr( + cx, + block_expr, + last_chain_binding_id, + span, + before_chars, + revert, + is_all, + ); } }, - ExprKind::Unary(UnOp::Not, expr) => handle_expr(cx, expr, first_param, span, before_chars, !revert), + ExprKind::Unary(UnOp::Not, expr) => handle_expr(cx, expr, first_param, span, before_chars, !revert, is_all), ExprKind::Call(fn_path, [arg]) => { - if let ExprKind::Path(path) = fn_path.kind + // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is + // `is_ascii`, then only `.all()` should warn. + if revert != is_all + && let ExprKind::Path(path) = fn_path.kind && let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id() && match_def_path(cx, fn_def_id, &["core", "char", "methods", "", "is_ascii"]) && path_to_local_id(peels_expr_ref(arg), first_param) @@ -81,7 +96,7 @@ fn handle_expr( } } -pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>, is_all: bool) { if let ExprKind::Closure(&Closure { body, .. }) = closure_arg.kind && let body = cx.tcx.hir().body(body) && let Some(first_param) = body.params.first() @@ -103,6 +118,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, recv.span.with_hi(call_expr.span.hi()), recv.span.with_hi(expr_start.hi()), false, + is_all, ); } } diff --git a/tests/ui/needless_character_iteration.fixed b/tests/ui/needless_character_iteration.fixed index 5a5da592987..f0bf84a41d7 100644 --- a/tests/ui/needless_character_iteration.fixed +++ b/tests/ui/needless_character_iteration.fixed @@ -48,4 +48,10 @@ fn main() { // Should not lint! "foo".chars().map(|c| c).all(|c| !char::is_ascii(&c)); + + // Should not lint! + "foo".chars().all(|c| !c.is_ascii()); + + // Should not lint! + "foo".chars().any(|c| c.is_ascii()); } diff --git a/tests/ui/needless_character_iteration.rs b/tests/ui/needless_character_iteration.rs index f6320ff22b7..2805d2438b4 100644 --- a/tests/ui/needless_character_iteration.rs +++ b/tests/ui/needless_character_iteration.rs @@ -17,17 +17,17 @@ fn magic(_: char) {} fn main() { "foo".chars().all(|c| c.is_ascii()); //~^ ERROR: checking if a string is ascii using iterators - "foo".chars().all(|c| !c.is_ascii()); + "foo".chars().any(|c| !c.is_ascii()); //~^ ERROR: checking if a string is ascii using iterators "foo".chars().all(|c| char::is_ascii(&c)); //~^ ERROR: checking if a string is ascii using iterators - "foo".chars().all(|c| !char::is_ascii(&c)); + "foo".chars().any(|c| !char::is_ascii(&c)); //~^ ERROR: checking if a string is ascii using iterators let s = String::new(); s.chars().all(|c| c.is_ascii()); //~^ ERROR: checking if a string is ascii using iterators - "foo".to_string().chars().all(|c| !c.is_ascii()); + "foo".to_string().chars().any(|c| !c.is_ascii()); //~^ ERROR: checking if a string is ascii using iterators "foo".chars().all(|c| { @@ -35,7 +35,7 @@ fn main() { let x = c; x.is_ascii() }); - "foo".chars().all(|c| { + "foo".chars().any(|c| { //~^ ERROR: checking if a string is ascii using iterators let x = c; !x.is_ascii() @@ -56,4 +56,10 @@ fn main() { // Should not lint! "foo".chars().map(|c| c).all(|c| !char::is_ascii(&c)); + + // Should not lint! + "foo".chars().all(|c| !c.is_ascii()); + + // Should not lint! + "foo".chars().any(|c| c.is_ascii()); } diff --git a/tests/ui/needless_character_iteration.stderr b/tests/ui/needless_character_iteration.stderr index 05055f75aa7..7966033555f 100644 --- a/tests/ui/needless_character_iteration.stderr +++ b/tests/ui/needless_character_iteration.stderr @@ -10,7 +10,7 @@ LL | "foo".chars().all(|c| c.is_ascii()); error: checking if a string is ascii using iterators --> tests/ui/needless_character_iteration.rs:20:5 | -LL | "foo".chars().all(|c| !c.is_ascii()); +LL | "foo".chars().any(|c| !c.is_ascii()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()` error: checking if a string is ascii using iterators @@ -22,7 +22,7 @@ LL | "foo".chars().all(|c| char::is_ascii(&c)); error: checking if a string is ascii using iterators --> tests/ui/needless_character_iteration.rs:24:5 | -LL | "foo".chars().all(|c| !char::is_ascii(&c)); +LL | "foo".chars().any(|c| !char::is_ascii(&c)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()` error: checking if a string is ascii using iterators @@ -34,7 +34,7 @@ LL | s.chars().all(|c| c.is_ascii()); error: checking if a string is ascii using iterators --> tests/ui/needless_character_iteration.rs:30:5 | -LL | "foo".to_string().chars().all(|c| !c.is_ascii()); +LL | "foo".to_string().chars().any(|c| !c.is_ascii()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".to_string().is_ascii()` error: checking if a string is ascii using iterators @@ -50,7 +50,7 @@ LL | | }); error: checking if a string is ascii using iterators --> tests/ui/needless_character_iteration.rs:38:5 | -LL | / "foo".chars().all(|c| { +LL | / "foo".chars().any(|c| { LL | | LL | | let x = c; LL | | !x.is_ascii() -- cgit 1.4.1-3-g733a5 From e8d02fe1cb20a21e0bee2f80f1e16945eb3b9437 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 May 2024 15:43:18 +1000 Subject: Make top-level `rustc_parse` functions fallible. Currently we have an awkward mix of fallible and infallible functions: ``` new_parser_from_source_str maybe_new_parser_from_source_str new_parser_from_file (maybe_new_parser_from_file) // missing (new_parser_from_source_file) // missing maybe_new_parser_from_source_file source_str_to_stream maybe_source_file_to_stream ``` We could add the two missing functions, but instead this commit removes of all the infallible ones and renames the fallible ones leaving us with these which are all fallible: ``` new_parser_from_source_str new_parser_from_file new_parser_from_source_file source_str_to_stream source_file_to_stream ``` This requires making `unwrap_or_emit_fatal` public so callers of formerly infallible functions can still work. This does make some of the call sites slightly more verbose, but I think it's worth it for the simpler API. Also, there are two `catch_unwind` calls and one `catch_fatal_errors` call in this diff that become removable thanks this change. (I will do that in a follow-up PR.) --- clippy_lints/src/doc/needless_doctest_main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/doc/needless_doctest_main.rs b/clippy_lints/src/doc/needless_doctest_main.rs index 651f2ebaee6..c3e3c0431e6 100644 --- a/clippy_lints/src/doc/needless_doctest_main.rs +++ b/clippy_lints/src/doc/needless_doctest_main.rs @@ -8,7 +8,7 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::HumanEmitter; use rustc_errors::{Diag, DiagCtxt}; use rustc_lint::LateContext; -use rustc_parse::maybe_new_parser_from_source_str; +use rustc_parse::new_parser_from_source_str; use rustc_parse::parser::ForceCollect; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; @@ -50,7 +50,7 @@ pub fn check( let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let psess = ParseSess::with_dcx(dcx, sm); - let mut parser = match maybe_new_parser_from_source_str(&psess, filename, code) { + let mut parser = match new_parser_from_source_str(&psess, filename, code) { Ok(p) => p, Err(errs) => { errs.into_iter().for_each(Diag::cancel); -- cgit 1.4.1-3-g733a5 From d47ab9f9c9b52167e8abf68d3a1d8722c4c395c2 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Wed, 5 Jun 2024 13:51:29 +0200 Subject: Update version attribute for 1.79 lints --- clippy_lints/src/attrs/mod.rs | 2 +- clippy_lints/src/integer_division_remainder_used.rs | 2 +- clippy_lints/src/legacy_numeric_constants.rs | 2 +- clippy_lints/src/manual_unwrap_or_default.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/transmute/mod.rs | 2 +- clippy_lints/src/zero_repeat_side_effects.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 83c828e8e22..e4c98a32fd6 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -463,7 +463,7 @@ declare_clippy_lint! { /// #[allow(dead_code)] /// fn foo() {} /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.79.0"] pub DUPLICATED_ATTRIBUTES, suspicious, "duplicated attribute" diff --git a/clippy_lints/src/integer_division_remainder_used.rs b/clippy_lints/src/integer_division_remainder_used.rs index cf598d5045e..a1215491b48 100644 --- a/clippy_lints/src/integer_division_remainder_used.rs +++ b/clippy_lints/src/integer_division_remainder_used.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ```no_run /// let my_div = 10 >> 1; /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.79.0"] pub INTEGER_DIVISION_REMAINDER_USED, restriction, "use of disallowed default division and remainder operations" diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index 00124dcdd91..eadfeb6e341 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// ```rust /// let eps = f32::EPSILON; /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.79.0"] pub LEGACY_NUMERIC_CONSTANTS, style, "checks for usage of legacy std numeric constants and methods" diff --git a/clippy_lints/src/manual_unwrap_or_default.rs b/clippy_lints/src/manual_unwrap_or_default.rs index 84fb183e3f7..70ec6478a25 100644 --- a/clippy_lints/src/manual_unwrap_or_default.rs +++ b/clippy_lints/src/manual_unwrap_or_default.rs @@ -43,7 +43,7 @@ declare_clippy_lint! { /// let x: Option> = Some(Vec::new()); /// let y: Vec = x.unwrap_or_default(); /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.79.0"] pub MANUAL_UNWRAP_OR_DEFAULT, suspicious, "check if a `match` or `if let` can be simplified with `unwrap_or_default`" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1572f6fb601..8ef68262571 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4085,7 +4085,7 @@ declare_clippy_lint! { /// ```no_run /// println!("the string is empty"); /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.79.0"] pub CONST_IS_EMPTY, suspicious, "is_empty() called on strings known at compile time" diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 598032ccdeb..aa329ec3366 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -546,7 +546,7 @@ declare_clippy_lint! { /// let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); /// # } /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.79.0"] pub MISSING_TRANSMUTE_ANNOTATIONS, suspicious, "warns if a transmute call doesn't have all generics specified" diff --git a/clippy_lints/src/zero_repeat_side_effects.rs b/clippy_lints/src/zero_repeat_side_effects.rs index 143fecdd237..1450975835a 100644 --- a/clippy_lints/src/zero_repeat_side_effects.rs +++ b/clippy_lints/src/zero_repeat_side_effects.rs @@ -36,7 +36,7 @@ declare_clippy_lint! { /// side_effect(); /// let a: [i32; 0] = []; /// ``` - #[clippy::version = "1.75.0"] + #[clippy::version = "1.79.0"] pub ZERO_REPEAT_SIDE_EFFECTS, suspicious, "usage of zero-sized initializations of arrays or vecs causing side effects" -- cgit 1.4.1-3-g733a5 From 466acfa6505f54386320036c204d7179b853516a Mon Sep 17 00:00:00 2001 From: xFrednet Date: Tue, 4 Jun 2024 15:51:44 +0200 Subject: Changelog for Clippy 1.79 :mortar_board: --- CHANGELOG.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0f511742fa..d09e0e55ddb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,73 @@ document. ## Unreleased / Beta / In Rust Nightly -[93f0a9a9...master](https://github.com/rust-lang/rust-clippy/compare/93f0a9a9...master) +[ca3b3937...master](https://github.com/rust-lang/rust-clippy/compare/ca3b3937...master) + +## Rust 1.79 + +Current stable, released 2024-06-13 + +[View all 102 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-03-08T11%3A13%3A58Z..2024-04-18T15%3A50%3A50Z+base%3Amaster) + +### New Lints + +* Added [`legacy_numeric_constants`] to + [#12312](https://github.com/rust-lang/rust-clippy/pull/12312) +* Added [`missing_transmute_annotations`] to + [#12239](https://github.com/rust-lang/rust-clippy/pull/12239) +* Added [`integer_division_remainder_used`] to `restriction` + [#12451](https://github.com/rust-lang/rust-clippy/pull/12451) +* Added [`duplicated_attributes`] to `suspicious` + [#12378](https://github.com/rust-lang/rust-clippy/pull/12378) +* Added [`manual_unwrap_or_default`] to `suspicious` + [#12440](https://github.com/rust-lang/rust-clippy/pull/12440) +* Added [`zero_repeat_side_effects`] to `suspicious` + [#12449](https://github.com/rust-lang/rust-clippy/pull/12449) +* Added [`const_is_empty`] to `suspicious` + [#12310](https://github.com/rust-lang/rust-clippy/pull/12310) + +### Moves and Deprecations + +* Moved [`box_default`] to `style` (From `perf`) + [#12601](https://github.com/rust-lang/rust-clippy/pull/12601) +* Moved [`manual_clamp`] to `complexity` (From `nursery` now warn-by-default) + [#12543](https://github.com/rust-lang/rust-clippy/pull/12543) +* Moved [`mixed_attributes_style`] to `style` (From `suspicious`) + [#12572](https://github.com/rust-lang/rust-clippy/pull/12572) +* Moved [`readonly_write_lock`] to `perf` (From `nursery` now warn-by-default) + [#12479](https://github.com/rust-lang/rust-clippy/pull/12479) + +### Enhancements + +* [`module_name_repetition`]: Added the [`allowed-prefixes`] configuration to allow common prefixes. + [#12573](https://github.com/rust-lang/rust-clippy/pull/12573) +* [`cast_sign_loss`], [`cast_possible_truncation`], [`cast_lossless`]: Are now allowed in macros + [#12631](https://github.com/rust-lang/rust-clippy/pull/12631) +* [`manual_clamp`]: Now only lints on constant min and max values + [#12543](https://github.com/rust-lang/rust-clippy/pull/12543) +* [`assigning_clones`]: Now considers the [`msrv`] configuration + [#12511](https://github.com/rust-lang/rust-clippy/pull/12511) +* [`needless_return`], [`useless_let_if_seq`], [`mut_mut`]: [`read_zero_byte_vec`], [`unused_io_amount`], + [`unused_peekable`]: Now respects `#[allow]` attributes on the affected statement instead + [#12446](https://github.com/rust-lang/rust-clippy/pull/12446) + +### False Positive Fixes + +* [`cast_lossless`]: No longer lints when casting to `u128` + [#12496](https://github.com/rust-lang/rust-clippy/pull/12496) +* [`std_instead_of_core`] No longer lints on modules that are only in `std` + [#12447](https://github.com/rust-lang/rust-clippy/pull/12447) + +### ICE Fixes + +* [`ptr_as_ptr`]: No longer crashes when the result of a function is casted + [#12617](https://github.com/rust-lang/rust-clippy/pull/12617) +* [`needless_return`]: No longer crashes on non-ascii characters + [#12493](https://github.com/rust-lang/rust-clippy/pull/12493) ## Rust 1.78 -Current stable, released 2024-05-02 +Released 2024-05-02 [View all 112 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-01-26T05%3A46%3A23Z..2024-03-07T16%3A25%3A52Z+base%3Amaster) -- cgit 1.4.1-3-g733a5 From a0e407c7c2454a869cf1eb5870fae13dcb823c54 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Wed, 5 Jun 2024 16:26:51 +0200 Subject: Address PR feedback <3 --- CHANGELOG.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d09e0e55ddb..5b3f29de483 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,9 +16,9 @@ Current stable, released 2024-06-13 ### New Lints -* Added [`legacy_numeric_constants`] to +* Added [`legacy_numeric_constants`] to `style` [#12312](https://github.com/rust-lang/rust-clippy/pull/12312) -* Added [`missing_transmute_annotations`] to +* Added [`missing_transmute_annotations`] to `suspicious` [#12239](https://github.com/rust-lang/rust-clippy/pull/12239) * Added [`integer_division_remainder_used`] to `restriction` [#12451](https://github.com/rust-lang/rust-clippy/pull/12451) @@ -37,14 +37,12 @@ Current stable, released 2024-06-13 [#12601](https://github.com/rust-lang/rust-clippy/pull/12601) * Moved [`manual_clamp`] to `complexity` (From `nursery` now warn-by-default) [#12543](https://github.com/rust-lang/rust-clippy/pull/12543) -* Moved [`mixed_attributes_style`] to `style` (From `suspicious`) - [#12572](https://github.com/rust-lang/rust-clippy/pull/12572) * Moved [`readonly_write_lock`] to `perf` (From `nursery` now warn-by-default) [#12479](https://github.com/rust-lang/rust-clippy/pull/12479) ### Enhancements -* [`module_name_repetition`]: Added the [`allowed-prefixes`] configuration to allow common prefixes. +* [`module_name_repetitions`]: Added the [`allowed-prefixes`] configuration to allow common prefixes. [#12573](https://github.com/rust-lang/rust-clippy/pull/12573) * [`cast_sign_loss`], [`cast_possible_truncation`], [`cast_lossless`]: Are now allowed in macros [#12631](https://github.com/rust-lang/rust-clippy/pull/12631) @@ -52,7 +50,7 @@ Current stable, released 2024-06-13 [#12543](https://github.com/rust-lang/rust-clippy/pull/12543) * [`assigning_clones`]: Now considers the [`msrv`] configuration [#12511](https://github.com/rust-lang/rust-clippy/pull/12511) -* [`needless_return`], [`useless_let_if_seq`], [`mut_mut`]: [`read_zero_byte_vec`], [`unused_io_amount`], +* [`needless_return`], [`useless_let_if_seq`], [`mut_mut`], [`read_zero_byte_vec`], [`unused_io_amount`], [`unused_peekable`]: Now respects `#[allow]` attributes on the affected statement instead [#12446](https://github.com/rust-lang/rust-clippy/pull/12446) @@ -65,8 +63,6 @@ Current stable, released 2024-06-13 ### ICE Fixes -* [`ptr_as_ptr`]: No longer crashes when the result of a function is casted - [#12617](https://github.com/rust-lang/rust-clippy/pull/12617) * [`needless_return`]: No longer crashes on non-ascii characters [#12493](https://github.com/rust-lang/rust-clippy/pull/12493) -- cgit 1.4.1-3-g733a5 From 35e2027a35572af11b7d7965d0adf8807ab4b16e Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Wed, 5 Jun 2024 14:11:56 -0400 Subject: Fix grammer for the Safety documentation check The original message ("unsafe function's docs miss `# Safety` section") reads quite awkwardly. I've changed it to "unsafe function's docs are missing a `# Safety` section" to have it read better. Signed-off-by: Paul R. Tagliamonte --- clippy_lints/src/doc/missing_headers.rs | 2 +- tests/ui-toml/private-doc-errors/doc_lints.rs | 2 +- tests/ui-toml/private-doc-errors/doc_lints.stderr | 2 +- tests/ui/doc_unsafe.stderr | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs index 010fab803d9..e3d74840726 100644 --- a/clippy_lints/src/doc/missing_headers.rs +++ b/clippy_lints/src/doc/missing_headers.rs @@ -37,7 +37,7 @@ pub fn check( cx, MISSING_SAFETY_DOC, span, - "unsafe function's docs miss `# Safety` section", + "unsafe function's docs are missing a `# Safety` section", ), (true, Safety::Safe) => span_lint( cx, diff --git a/tests/ui-toml/private-doc-errors/doc_lints.rs b/tests/ui-toml/private-doc-errors/doc_lints.rs index ae4c3f84c29..79c8751468d 100644 --- a/tests/ui-toml/private-doc-errors/doc_lints.rs +++ b/tests/ui-toml/private-doc-errors/doc_lints.rs @@ -47,7 +47,7 @@ pub mod __macro { pub struct T; impl T { pub unsafe fn f() {} - //~^ ERROR: unsafe function's docs miss `# Safety` section + //~^ ERROR: unsafe function's docs are missing a `# Safety` section } } diff --git a/tests/ui-toml/private-doc-errors/doc_lints.stderr b/tests/ui-toml/private-doc-errors/doc_lints.stderr index 65ec1a7bebb..a8ee09b9df7 100644 --- a/tests/ui-toml/private-doc-errors/doc_lints.stderr +++ b/tests/ui-toml/private-doc-errors/doc_lints.stderr @@ -51,7 +51,7 @@ note: the lint level is defined here LL | clippy::missing_panics_doc | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: unsafe function's docs miss `# Safety` section +error: unsafe function's docs are missing a `# Safety` section --> tests/ui-toml/private-doc-errors/doc_lints.rs:49:9 | LL | pub unsafe fn f() {} diff --git a/tests/ui/doc_unsafe.stderr b/tests/ui/doc_unsafe.stderr index 4fcbe716951..929afbceb87 100644 --- a/tests/ui/doc_unsafe.stderr +++ b/tests/ui/doc_unsafe.stderr @@ -1,4 +1,4 @@ -error: unsafe function's docs miss `# Safety` section +error: unsafe function's docs are missing a `# Safety` section --> tests/ui/doc_unsafe.rs:9:1 | LL | pub unsafe fn destroy_the_planet() { @@ -7,13 +7,13 @@ LL | pub unsafe fn destroy_the_planet() { = note: `-D clippy::missing-safety-doc` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_safety_doc)]` -error: unsafe function's docs miss `# Safety` section +error: unsafe function's docs are missing a `# Safety` section --> tests/ui/doc_unsafe.rs:32:5 | LL | pub unsafe fn republished() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: unsafe function's docs miss `# Safety` section +error: unsafe function's docs are missing a `# Safety` section --> tests/ui/doc_unsafe.rs:40:5 | LL | unsafe fn woefully_underdocumented(self); @@ -25,13 +25,13 @@ error: docs for unsafe trait missing `# Safety` section LL | pub unsafe trait UnsafeTrait { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: unsafe function's docs miss `# Safety` section +error: unsafe function's docs are missing a `# Safety` section --> tests/ui/doc_unsafe.rs:76:5 | LL | pub unsafe fn more_undocumented_unsafe() -> Self { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: unsafe function's docs miss `# Safety` section +error: unsafe function's docs are missing a `# Safety` section --> tests/ui/doc_unsafe.rs:92:9 | LL | pub unsafe fn whee() { -- cgit 1.4.1-3-g733a5 From 38de6e1f3a48fc7a18448a3117f2db72c5fb356e Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 4 Jun 2024 07:01:58 +0100 Subject: Misc fixes to cranelift/clippy/miri --- clippy_lints/src/large_const_arrays.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 2 +- clippy_lints/src/matches/overlapping_arms.rs | 4 ++-- clippy_lints/src/zero_repeat_side_effects.rs | 2 +- clippy_utils/src/lib.rs | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index b561054b582..77d05020c82 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { && generics.params.is_empty() && !generics.has_where_clause_predicates && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Array(element_type, cst) = ty.kind() - && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() + && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 208d1bb6e68..f0f3f53647b 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { if let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind && !self.is_from_vec_macro(cx, expr.span) && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() - && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() + && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && !cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| { diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs index 8199366d175..45b375dbe3d 100644 --- a/clippy_lints/src/matches/overlapping_arms.rs +++ b/clippy_lints/src/matches/overlapping_arms.rs @@ -37,14 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) Some(lhs) => constant(cx, cx.typeck_results(), lhs)?, None => { let min_val_const = ty.numeric_min_val(cx.tcx)?; - mir_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))? + mir_to_const(cx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))? }, }; let rhs_const = match rhs { Some(rhs) => constant(cx, cx.typeck_results(), rhs)?, None => { let max_val_const = ty.numeric_max_val(cx.tcx)?; - mir_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))? + mir_to_const(cx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))? }, }; let lhs_val = lhs_const.int_value(cx, ty)?; diff --git a/clippy_lints/src/zero_repeat_side_effects.rs b/clippy_lints/src/zero_repeat_side_effects.rs index 143fecdd237..848b49130dc 100644 --- a/clippy_lints/src/zero_repeat_side_effects.rs +++ b/clippy_lints/src/zero_repeat_side_effects.rs @@ -55,7 +55,7 @@ impl LateLintPass<'_> for ZeroRepeatSideEffects { inner_check(cx, expr, inner_expr, true); } else if let ExprKind::Repeat(inner_expr, _) = expr.kind && let ty::Array(_, cst) = cx.typeck_results().expr_ty(expr).kind() - && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() + && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) && element_count == 0 { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index b10830b24e1..1147dce6215 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1534,7 +1534,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti if let rustc_ty::Adt(_, subst) = ty.kind() && let bnd_ty = subst.type_at(0) && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx) - && let Some(min_const) = mir_to_const(cx, Const::from_ty_const(min_val, cx.tcx)) + && let Some(min_const) = mir_to_const(cx, Const::from_ty_const(min_val, bnd_ty, cx.tcx)) && let Some(start_const) = constant(cx, cx.typeck_results(), start) { start_const == min_const @@ -1547,7 +1547,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti if let rustc_ty::Adt(_, subst) = ty.kind() && let bnd_ty = subst.type_at(0) && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) - && let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, cx.tcx)) + && let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, bnd_ty, cx.tcx)) && let Some(end_const) = constant(cx, cx.typeck_results(), end) { end_const == max_const -- cgit 1.4.1-3-g733a5 From 6d19ac36b904155ca0f3f89e6a6361d56a46551d Mon Sep 17 00:00:00 2001 From: Veera Date: Wed, 5 Jun 2024 19:11:40 -0400 Subject: Update Tests --- tests/ui/associated-type-bounds/no-gat-position.rs | 1 + .../associated-type-bounds/no-gat-position.stderr | 5 ++ tests/ui/associated-types/associated-types-eq-2.rs | 2 - .../associated-types/associated-types-eq-2.stderr | 62 ++++---------- .../rtn-in-impl-signature.stderr | 5 ++ .../parser-error-recovery/issue-89013-no-kw.rs | 3 +- .../parser-error-recovery/issue-89013-no-kw.stderr | 22 +---- .../parser-error-recovery/issue-89013.rs | 1 - .../parser-error-recovery/issue-89013.stderr | 22 +---- ...k-params-declared-in-wrong-spot-issue-113073.rs | 33 ++++++++ ...rams-declared-in-wrong-spot-issue-113073.stderr | 96 ++++++++++++++++++++++ 11 files changed, 161 insertions(+), 91 deletions(-) create mode 100644 tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.rs create mode 100644 tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.stderr diff --git a/tests/ui/associated-type-bounds/no-gat-position.rs b/tests/ui/associated-type-bounds/no-gat-position.rs index cb62c882468..249812ebbff 100644 --- a/tests/ui/associated-type-bounds/no-gat-position.rs +++ b/tests/ui/associated-type-bounds/no-gat-position.rs @@ -5,6 +5,7 @@ pub trait Iter { fn next<'a>(&'a mut self) -> Option>; //~^ ERROR associated item constraints are not allowed here + //~| HELP consider removing this associated item binding } impl Iter for () { diff --git a/tests/ui/associated-type-bounds/no-gat-position.stderr b/tests/ui/associated-type-bounds/no-gat-position.stderr index e167ac1fda4..b8e466b8d84 100644 --- a/tests/ui/associated-type-bounds/no-gat-position.stderr +++ b/tests/ui/associated-type-bounds/no-gat-position.stderr @@ -3,6 +3,11 @@ error[E0229]: associated item constraints are not allowed here | LL | fn next<'a>(&'a mut self) -> Option>; | ^^^^^^^^^ associated item constraint not allowed here + | +help: consider removing this associated item binding + | +LL | fn next<'a>(&'a mut self) -> Option>; + | ~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/associated-types-eq-2.rs b/tests/ui/associated-types/associated-types-eq-2.rs index f0a7d1e46b1..88eb2981061 100644 --- a/tests/ui/associated-types/associated-types-eq-2.rs +++ b/tests/ui/associated-types/associated-types-eq-2.rs @@ -76,7 +76,6 @@ trait Tr3 { impl Tr3 for Bar { } @@ -92,7 +91,6 @@ impl Tr3 for Qux { // matches the const param ident but the constraint is a type arg impl Tr3 for Bar { //~^ ERROR associated item constraints are not allowed here -//~| ERROR trait takes 3 generic arguments but 0 generic arguments were supplied } // Test for when equality constraint's ident diff --git a/tests/ui/associated-types/associated-types-eq-2.stderr b/tests/ui/associated-types/associated-types-eq-2.stderr index 53e4e59128e..69b1b533450 100644 --- a/tests/ui/associated-types/associated-types-eq-2.stderr +++ b/tests/ui/associated-types/associated-types-eq-2.stderr @@ -5,7 +5,6 @@ LL | impl Tr3 for Bar { | |____^ | @@ -14,7 +13,7 @@ LL | | = 42, T2 = Qux, T3 = usize> for Bar { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated const equality is incomplete - --> $DIR/associated-types-eq-2.rs:85:10 + --> $DIR/associated-types-eq-2.rs:84:10 | LL | impl Tr3 for Qux { | ^^^^^^ @@ -24,7 +23,7 @@ LL | impl Tr3 for Qux { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated const equality is incomplete - --> $DIR/associated-types-eq-2.rs:100:14 + --> $DIR/associated-types-eq-2.rs:98:14 | LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { | ^^^^^^^ @@ -34,7 +33,7 @@ LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated const equality is incomplete - --> $DIR/associated-types-eq-2.rs:108:10 + --> $DIR/associated-types-eq-2.rs:106:10 | LL | impl Tr3 for Bar { | ^^^^^^ @@ -190,22 +189,6 @@ help: to use `GenericTerm` as a generic argument specify it directly LL | impl Tr2> for Bar { | ~~~~~~~~~~~~~~~~ -error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied - --> $DIR/associated-types-eq-2.rs:76:6 - | -LL | impl Tr3 $DIR/associated-types-eq-2.rs:69:7 - | -LL | trait Tr3 { - | ^^^ ------------ -- -- -help: add missing generic arguments - | -LL | impl Tr3 $DIR/associated-types-eq-2.rs:76:10 | @@ -213,7 +196,6 @@ LL | impl Tr3 for Bar { | |____^ associated item constraint not allowed here | @@ -223,7 +205,7 @@ LL | impl Tr3<42, T2 = Qux, T3 = usize> for Bar { | ~~ error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied - --> $DIR/associated-types-eq-2.rs:85:6 + --> $DIR/associated-types-eq-2.rs:84:6 | LL | impl Tr3 for Qux { | ^^^ expected 3 generic arguments @@ -239,7 +221,7 @@ LL | impl Tr3 for Qux { | ++++++++++ error[E0229]: associated item constraints are not allowed here - --> $DIR/associated-types-eq-2.rs:85:10 + --> $DIR/associated-types-eq-2.rs:84:10 | LL | impl Tr3 for Qux { | ^^^^^^ associated item constraint not allowed here @@ -249,24 +231,8 @@ help: consider removing this associated item binding LL | impl Tr3 for Qux { | ~~~~~~~ -error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied - --> $DIR/associated-types-eq-2.rs:93:6 - | -LL | impl Tr3 for Bar { - | ^^^ expected 3 generic arguments - | -note: trait defined here, with 3 generic parameters: `N`, `T2`, `T3` - --> $DIR/associated-types-eq-2.rs:69:7 - | -LL | trait Tr3 { - | ^^^ ------------ -- -- -help: add missing generic arguments - | -LL | impl Tr3 for Bar { - | ++++++++++ - error[E0229]: associated item constraints are not allowed here - --> $DIR/associated-types-eq-2.rs:93:10 + --> $DIR/associated-types-eq-2.rs:92:10 | LL | impl Tr3 for Bar { | ^^^^^^^ associated item constraint not allowed here @@ -277,7 +243,7 @@ LL | impl Tr3 for Bar { | ~~~~~~~~ error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied - --> $DIR/associated-types-eq-2.rs:100:6 + --> $DIR/associated-types-eq-2.rs:98:6 | LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { | ^^^ -- supplied 1 generic argument @@ -295,7 +261,7 @@ LL | impl Tr3<42, T2, T3, T2 = 42, T3 = usize> for Bar { | ++++++++ error[E0229]: associated item constraints are not allowed here - --> $DIR/associated-types-eq-2.rs:100:14 + --> $DIR/associated-types-eq-2.rs:98:14 | LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { | ^^^^^^^ associated item constraint not allowed here @@ -306,7 +272,7 @@ LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { | ~~~~~~~~~ error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied - --> $DIR/associated-types-eq-2.rs:108:6 + --> $DIR/associated-types-eq-2.rs:106:6 | LL | impl Tr3 for Bar { | ^^^ expected 3 generic arguments @@ -322,7 +288,7 @@ LL | impl Tr3 for Bar { | ++++++++++ error[E0229]: associated item constraints are not allowed here - --> $DIR/associated-types-eq-2.rs:108:10 + --> $DIR/associated-types-eq-2.rs:106:10 | LL | impl Tr3 for Bar { | ^^^^^^ associated item constraint not allowed here @@ -333,13 +299,13 @@ LL | impl Tr3 for Bar { | ~~~~~~~ error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/associated-types-eq-2.rs:119:13 + --> $DIR/associated-types-eq-2.rs:117:13 | LL | impl<'a, T> St<'a , T = Qux> { | ^^ expected 1 generic argument | note: struct defined here, with 1 generic parameter: `T` - --> $DIR/associated-types-eq-2.rs:117:8 + --> $DIR/associated-types-eq-2.rs:115:8 | LL | struct St<'a, T> { v: &'a T } | ^^ - @@ -349,7 +315,7 @@ LL | impl<'a, T> St<'a, T , T = Qux> { | +++ error[E0229]: associated item constraints are not allowed here - --> $DIR/associated-types-eq-2.rs:119:21 + --> $DIR/associated-types-eq-2.rs:117:21 | LL | impl<'a, T> St<'a , T = Qux> { | ^^^^^^^ associated item constraint not allowed here @@ -359,7 +325,7 @@ help: to use `Qux` as a generic argument specify it directly LL | impl<'a, T> St<'a , Qux> { | ~~~ -error: aborting due to 27 previous errors +error: aborting due to 25 previous errors Some errors have detailed explanations: E0046, E0107, E0229, E0658. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr index b07c5735dff..b0c89b05925 100644 --- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr @@ -12,6 +12,11 @@ error[E0229]: associated item constraints are not allowed here | LL | impl Super1<'_, bar(): Send> for () {} | ^^^^^^^^^^^ associated item constraint not allowed here + | +help: consider removing this associated item binding + | +LL | impl Super1<'_, bar(): Send> for () {} + | ~~~~~~~~~~~~~ error[E0046]: not all trait items implemented, missing: `bar` --> $DIR/rtn-in-impl-signature.rs:10:1 diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs index fbf1553c182..c15482f92dc 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs @@ -7,8 +7,7 @@ struct Bar; const T: usize = 42; impl Foo for Bar { -//~^ ERROR trait takes 1 generic argument but 0 generic arguments were supplied -//~| ERROR associated item constraints are not allowed here +//~^ ERROR associated item constraints are not allowed here //~| ERROR associated const equality is incomplete fn do_x(&self) -> [u8; 3] { [0u8; 3] diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr index a132859b412..78cddcc234c 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr @@ -8,22 +8,6 @@ LL | impl Foo for Bar { = help: add `#![feature(associated_const_equality)]` 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 1 generic argument but 0 generic arguments were supplied - --> $DIR/issue-89013-no-kw.rs:9:6 - | -LL | impl Foo for Bar { - | ^^^ expected 1 generic argument - | -note: trait defined here, with 1 generic parameter: `N` - --> $DIR/issue-89013-no-kw.rs:1:7 - | -LL | trait Foo { - | ^^^ -------------- -help: add missing generic argument - | -LL | impl Foo for Bar { - | ++ - error[E0229]: associated item constraints are not allowed here --> $DIR/issue-89013-no-kw.rs:9:10 | @@ -35,7 +19,7 @@ help: to use `3` as a generic argument specify it directly LL | impl Foo<3> for Bar { | ~ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0107, E0229, E0658. -For more information about an error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0229, E0658. +For more information about an error, try `rustc --explain E0229`. diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013.rs b/tests/ui/const-generics/parser-error-recovery/issue-89013.rs index c9c7ff3a170..6302f7f2ad5 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013.rs +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013.rs @@ -8,7 +8,6 @@ const T: usize = 42; impl Foo for Bar { //~^ ERROR expected lifetime, type, or constant, found keyword `const` -//~| ERROR trait takes 1 generic //~| ERROR associated item constraints are not allowed here //~| ERROR associated const equality is incomplete fn do_x(&self) -> [u8; 3] { diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr b/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr index 2fdd1208565..387eb226e70 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr @@ -20,22 +20,6 @@ LL | impl Foo for Bar { = help: add `#![feature(associated_const_equality)]` 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 1 generic argument but 0 generic arguments were supplied - --> $DIR/issue-89013.rs:9:6 - | -LL | impl Foo for Bar { - | ^^^ expected 1 generic argument - | -note: trait defined here, with 1 generic parameter: `N` - --> $DIR/issue-89013.rs:1:7 - | -LL | trait Foo { - | ^^^ -------------- -help: add missing generic argument - | -LL | impl Foo for Bar { - | ++ - error[E0229]: associated item constraints are not allowed here --> $DIR/issue-89013.rs:9:10 | @@ -47,7 +31,7 @@ help: to use `3` as a generic argument specify it directly LL | impl Foo<3> for Bar { | ~ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0107, E0229, E0658. -For more information about an error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0229, E0658. +For more information about an error, try `rustc --explain E0229`. diff --git a/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.rs b/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.rs new file mode 100644 index 00000000000..3a5b60e5763 --- /dev/null +++ b/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.rs @@ -0,0 +1,33 @@ +trait Foo {} + +impl Foo for String {} +//~^ ERROR associated item constraints are not allowed here +//~| HELP declare the type parameter right after the `impl` keyword + +impl Foo for u8 {} +//~^ ERROR associated item constraints are not allowed here +//~| HELP declare the type parameter right after the `impl` keyword +//~| ERROR use of undeclared lifetime name `'a` +//~| HELP consider introducing lifetime `'a` here + +impl Foo for u16 {} +//~^ ERROR associated item constraints are not allowed here +//~| HELP declare the type parameter right after the `impl` keyword + +impl<'a> Foo for u32 {} +//~^ ERROR associated item constraints are not allowed here +//~| HELP declare the type parameter right after the `impl` keyword + +trait Bar {} + +impl Bar for String {} +//~^ ERROR associated item constraints are not allowed here +//~| HELP declare the type parameter right after the `impl` keyword + +impl Bar for u8 {} +//~^ ERROR trait takes 2 generic arguments but 1 generic argument was supplied +//~| HELP add missing generic argument +//~| ERROR associated item constraints are not allowed here +//~| HELP declare the type parameter right after the `impl` keyword + +fn main() {} diff --git a/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.stderr b/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.stderr new file mode 100644 index 00000000000..dfc6761e17e --- /dev/null +++ b/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.stderr @@ -0,0 +1,96 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:7:13 + | +LL | impl Foo for u8 {} + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + +error[E0229]: associated item constraints are not allowed here + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:3:10 + | +LL | impl Foo for String {} + | ^^^^^^^^^^ associated item constraint not allowed here + | +help: declare the type parameter right after the `impl` keyword + | +LL | impl Foo for String {} + | ++++++++++++ ~ + +error[E0229]: associated item constraints are not allowed here + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:7:10 + | +LL | impl Foo for u8 {} + | ^^^^^^^^^^^^^^^ associated item constraint not allowed here + | +help: declare the type parameter right after the `impl` keyword + | +LL | impl<'a, T: 'a + Default> Foo for u8 {} + | +++++++++++++++++++++ ~ + +error[E0229]: associated item constraints are not allowed here + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:13:13 + | +LL | impl Foo for u16 {} + | ^^^^^^^^^^ associated item constraint not allowed here + | +help: declare the type parameter right after the `impl` keyword + | +LL | impl Foo for u16 {} + | ++++++++++++ ~ + +error[E0229]: associated item constraints are not allowed here + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:17:14 + | +LL | impl<'a> Foo for u32 {} + | ^^^^^^^^^^^^^^^ associated item constraint not allowed here + | +help: declare the type parameter right after the `impl` keyword + | +LL | impl<'a, 'a, T: 'a + Default> Foo for u32 {} + | +++++++++++++++++++++ ~ + +error[E0229]: associated item constraints are not allowed here + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:23:10 + | +LL | impl Bar for String {} + | ^^^^^^^^^^ associated item constraint not allowed here + | +help: declare the type parameter right after the `impl` keyword + | +LL | impl Bar for String {} + | ++++++++++++ ~ + +error[E0107]: trait takes 2 generic arguments but 1 generic argument was supplied + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:27:9 + | +LL | impl Bar for u8 {} + | ^^^ - supplied 1 generic argument + | | + | expected 2 generic arguments + | +note: trait defined here, with 2 generic parameters: `T`, `K` + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:21:7 + | +LL | trait Bar {} + | ^^^ - - +help: add missing generic argument + | +LL | impl Bar for u8 {} + | +++ + +error[E0229]: associated item constraints are not allowed here + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:27:16 + | +LL | impl Bar for u8 {} + | ^^^^^^^^^^ associated item constraint not allowed here + | +help: declare the type parameter right after the `impl` keyword + | +LL | impl Bar for u8 {} + | ++++++++++++ ~ + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0107, E0229, E0261. +For more information about an error, try `rustc --explain E0107`. -- cgit 1.4.1-3-g733a5 From c245cde61cbe914dcf5c46a072a2b3cd0c694f0b Mon Sep 17 00:00:00 2001 From: Rémy Rakic Date: Thu, 6 Jun 2024 09:45:50 +0000 Subject: Revert "Rollup merge of #124976 - petrochenkov:usedcrates, r=oli-obk" This reverts commit eda4a35f365535af72118118a3597edf5a13c12d, reversing changes made to eb6b35b5bcb3c2a594cb29cd478aeb2893f49d30. --- clippy_utils/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 1147dce6215..2f6bf920967 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -647,7 +647,7 @@ fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec, path: &[&str]) -> Vec { fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> impl Iterator + '_ { - tcx.crates_including_speculative(()) + tcx.crates(()) .iter() .copied() .filter(move |&num| tcx.crate_name(num) == name) -- cgit 1.4.1-3-g733a5 From 1e23449678e4c986b609ed7a82ae6497e7b6ddd1 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 25 May 2024 18:15:14 +0200 Subject: Move `is_receiver_of_method_call` to `clippy_utils` for reuse --- clippy_lints/src/methods/search_is_some.rs | 12 +----------- clippy_utils/src/lib.rs | 11 +++++++++++ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index f5f1e94bbf4..3b2dd285b8c 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::deref_closure_args; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{get_parent_expr, is_trait_method, strip_pat_refs}; +use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs}; use hir::ExprKind; use rustc_errors::Applicability; use rustc_hir as hir; @@ -156,13 +156,3 @@ pub(super) fn check<'tcx>( } } } - -fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - if let Some(parent_expr) = get_parent_expr(cx, expr) - && let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind - && receiver.hir_id == expr.hir_id - { - return true; - } - false -} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 6d6c4ffbe5d..6b00e793eaa 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3401,3 +3401,14 @@ pub fn binary_expr_needs_parentheses(expr: &Expr<'_>) -> bool { contains_block(expr, false) } + +/// Returns true if the specified expression is in a receiver position. +pub fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(parent_expr) = get_parent_expr(cx, expr) + && let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind + && receiver.hir_id == expr.hir_id + { + return true; + } + false +} -- cgit 1.4.1-3-g733a5 From 35b2aa99f3357a69d09f247ed5aff64cdd7765b1 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 25 May 2024 18:08:14 +0200 Subject: Add required parentheses around method receiver --- clippy_lints/src/needless_bool.rs | 13 ++++++++++--- tests/ui/needless_bool/fixable.fixed | 12 ++++++++++++ tests/ui/needless_bool/fixable.rs | 12 ++++++++++++ tests/ui/needless_bool/fixable.stderr | 20 +++++++++++++++++++- 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index e1866eaa18a..9cb4fa41c73 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -6,8 +6,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{ - higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, peel_blocks, peel_blocks_with_stmt, - span_extract_comment, SpanlessEq, + get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, is_receiver_of_method_call, + peel_blocks, peel_blocks_with_stmt, span_extract_comment, SpanlessEq, }; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -154,7 +154,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { snip = snip.blockify(); } - if condition_needs_parentheses(cond) && is_parent_stmt(cx, e.hir_id) { + if (condition_needs_parentheses(cond) && is_parent_stmt(cx, e.hir_id)) + || is_receiver_of_method_call(cx, e) + || is_as_argument(cx, e) + { snip = snip.maybe_par(); } @@ -442,3 +445,7 @@ fn fetch_assign<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, bool) None } } + +fn is_as_argument(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { + matches!(get_parent_expr(cx, e).map(|e| e.kind), Some(ExprKind::Cast(_, _))) +} diff --git a/tests/ui/needless_bool/fixable.fixed b/tests/ui/needless_bool/fixable.fixed index 3059de8f89c..ec63c4fd6a2 100644 --- a/tests/ui/needless_bool/fixable.fixed +++ b/tests/ui/needless_bool/fixable.fixed @@ -131,3 +131,15 @@ fn needless_bool_condition() -> bool { foo() } + +fn issue12846() { + let a = true; + let b = false; + + // parentheses are needed here + let _x = (a && b).then(|| todo!()); + let _x = (a && b) as u8; + + // parentheses are not needed here + let _x = a.then(|| todo!()); +} diff --git a/tests/ui/needless_bool/fixable.rs b/tests/ui/needless_bool/fixable.rs index b2cbe86e223..8694aa71590 100644 --- a/tests/ui/needless_bool/fixable.rs +++ b/tests/ui/needless_bool/fixable.rs @@ -191,3 +191,15 @@ fn needless_bool_condition() -> bool { foo() } + +fn issue12846() { + let a = true; + let b = false; + + // parentheses are needed here + let _x = if a && b { true } else { false }.then(|| todo!()); + let _x = if a && b { true } else { false } as u8; + + // parentheses are not needed here + let _x = if a { true } else { false }.then(|| todo!()); +} diff --git a/tests/ui/needless_bool/fixable.stderr b/tests/ui/needless_bool/fixable.stderr index 9746e931f50..99b5b998344 100644 --- a/tests/ui/needless_bool/fixable.stderr +++ b/tests/ui/needless_bool/fixable.stderr @@ -191,5 +191,23 @@ error: this if-then-else expression returns a bool literal LL | if unsafe { no(4) } & 1 != 0 { true } else { false } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` -error: aborting due to 21 previous errors +error: this if-then-else expression returns a bool literal + --> tests/ui/needless_bool/fixable.rs:200:14 + | +LL | let _x = if a && b { true } else { false }.then(|| todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(a && b)` + +error: this if-then-else expression returns a bool literal + --> tests/ui/needless_bool/fixable.rs:201:14 + | +LL | let _x = if a && b { true } else { false } as u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(a && b)` + +error: this if-then-else expression returns a bool literal + --> tests/ui/needless_bool/fixable.rs:204:14 + | +LL | let _x = if a { true } else { false }.then(|| todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `a` + +error: aborting due to 24 previous errors -- cgit 1.4.1-3-g733a5 From 5b63ab113118a97997c6bb2b553a54687b1b67d2 Mon Sep 17 00:00:00 2001 From: Renato Lochetti Date: Thu, 6 Jun 2024 21:33:37 +0100 Subject: Lint `manual_unwrap_or_default` for Result as well --- clippy_lints/src/manual_unwrap_or_default.rs | 11 ++++++++++- tests/ui/manual_unwrap_or_default.fixed | 6 ++++++ tests/ui/manual_unwrap_or_default.rs | 15 +++++++++++++++ tests/ui/manual_unwrap_or_default.stderr | 25 +++++++++++++++++++++++-- 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/manual_unwrap_or_default.rs b/clippy_lints/src/manual_unwrap_or_default.rs index 84fb183e3f7..8bcc0acb7da 100644 --- a/clippy_lints/src/manual_unwrap_or_default.rs +++ b/clippy_lints/src/manual_unwrap_or_default.rs @@ -57,7 +57,8 @@ fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option { // Since it comes from a pattern binding, we need to get the parent to actually match // against it. && let Some(def_id) = cx.tcx.opt_parent(def_id) - && cx.tcx.lang_items().get(LangItem::OptionSome) == Some(def_id) + && (cx.tcx.lang_items().get(LangItem::OptionSome) == Some(def_id) + || cx.tcx.lang_items().get(LangItem::ResultOk) == Some(def_id)) { let mut bindings = Vec::new(); pat.each_binding(|_, id, _, _| bindings.push(id)); @@ -80,6 +81,14 @@ fn get_none<'tcx>(cx: &LateContext<'tcx>, arm: &Arm<'tcx>) -> Option<&'tcx Expr< && cx.tcx.lang_items().get(LangItem::OptionNone) == Some(def_id) { Some(arm.body) + } else if let PatKind::TupleStruct(QPath::Resolved(_, path), _, _)= arm.pat.kind + && let Some(def_id) = path.res.opt_def_id() + // Since it comes from a pattern binding, we need to get the parent to actually match + // against it. + && let Some(def_id) = cx.tcx.opt_parent(def_id) + && cx.tcx.lang_items().get(LangItem::ResultErr) == Some(def_id) + { + Some(arm.body) } else if let PatKind::Wild = arm.pat.kind { // We consider that the `Some` check will filter it out if it's not right. Some(arm.body) diff --git a/tests/ui/manual_unwrap_or_default.fixed b/tests/ui/manual_unwrap_or_default.fixed index d6e736ba9cc..663de1a5f06 100644 --- a/tests/ui/manual_unwrap_or_default.fixed +++ b/tests/ui/manual_unwrap_or_default.fixed @@ -26,6 +26,12 @@ fn main() { Some(x) => x, None => &[], }; + + let x: Result = Ok(String::new()); + x.unwrap_or_default(); + + let x: Result = Ok(String::new()); + x.unwrap_or_default(); } // Issue #12531 diff --git a/tests/ui/manual_unwrap_or_default.rs b/tests/ui/manual_unwrap_or_default.rs index 462d5d90ee7..75ffe09be9d 100644 --- a/tests/ui/manual_unwrap_or_default.rs +++ b/tests/ui/manual_unwrap_or_default.rs @@ -47,6 +47,21 @@ fn main() { Some(x) => x, None => &[], }; + + let x: Result = Ok(String::new()); + match x { + //~^ ERROR: match can be simplified with `.unwrap_or_default()` + Ok(v) => v, + Err(_) => String::new(), + }; + + let x: Result = Ok(String::new()); + if let Ok(v) = x { + //~^ ERROR: if let can be simplified with `.unwrap_or_default()` + v + } else { + String::new() + }; } // Issue #12531 diff --git a/tests/ui/manual_unwrap_or_default.stderr b/tests/ui/manual_unwrap_or_default.stderr index 3f1da444301..9e3b1be5cb9 100644 --- a/tests/ui/manual_unwrap_or_default.stderr +++ b/tests/ui/manual_unwrap_or_default.stderr @@ -53,7 +53,28 @@ LL | | }; | |_____^ help: replace it with: `x.unwrap_or_default()` error: match can be simplified with `.unwrap_or_default()` - --> tests/ui/manual_unwrap_or_default.rs:56:20 + --> tests/ui/manual_unwrap_or_default.rs:52:5 + | +LL | / match x { +LL | | +LL | | Ok(v) => v, +LL | | Err(_) => String::new(), +LL | | }; + | |_____^ help: replace it with: `x.unwrap_or_default()` + +error: if let can be simplified with `.unwrap_or_default()` + --> tests/ui/manual_unwrap_or_default.rs:59:5 + | +LL | / if let Ok(v) = x { +LL | | +LL | | v +LL | | } else { +LL | | String::new() +LL | | }; + | |_____^ help: replace it with: `x.unwrap_or_default()` + +error: match can be simplified with `.unwrap_or_default()` + --> tests/ui/manual_unwrap_or_default.rs:71:20 | LL | Some(_) => match *b { | ____________________^ @@ -62,5 +83,5 @@ LL | | _ => 0, LL | | }, | |_________^ help: replace it with: `(*b).unwrap_or_default()` -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors -- cgit 1.4.1-3-g733a5 From 5ea5f6351e29ebbac17d1d45d87322bec8793b83 Mon Sep 17 00:00:00 2001 From: Rémy Rakic Date: Thu, 6 Jun 2024 20:39:54 +0000 Subject: Revert "Rollup merge of #124099 - voidc:disallow-ambiguous-expr-attrs, r=davidtwco" This reverts commit 57dad1d75e562ff73051c1c43b07eaf65c7dbd74, reversing changes made to 36316df9fe6c3e246153fe6e78967643cf08c148. --- tests/ui/cfg_attr_rustfmt.fixed | 6 +++--- tests/ui/cfg_attr_rustfmt.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ui/cfg_attr_rustfmt.fixed b/tests/ui/cfg_attr_rustfmt.fixed index 84dac431169..05d5b3d10ea 100644 --- a/tests/ui/cfg_attr_rustfmt.fixed +++ b/tests/ui/cfg_attr_rustfmt.fixed @@ -16,7 +16,7 @@ fn foo( fn skip_on_statements() { #[rustfmt::skip] - { 5+3; } + 5+3; } #[rustfmt::skip] @@ -33,11 +33,11 @@ mod foo { #[clippy::msrv = "1.29"] fn msrv_1_29() { #[cfg_attr(rustfmt, rustfmt::skip)] - { 1+29; } + 1+29; } #[clippy::msrv = "1.30"] fn msrv_1_30() { #[rustfmt::skip] - { 1+30; } + 1+30; } diff --git a/tests/ui/cfg_attr_rustfmt.rs b/tests/ui/cfg_attr_rustfmt.rs index 4ab5c70e13b..bc29e20210e 100644 --- a/tests/ui/cfg_attr_rustfmt.rs +++ b/tests/ui/cfg_attr_rustfmt.rs @@ -16,7 +16,7 @@ fn foo( fn skip_on_statements() { #[cfg_attr(rustfmt, rustfmt::skip)] - { 5+3; } + 5+3; } #[cfg_attr(rustfmt, rustfmt_skip)] @@ -33,11 +33,11 @@ mod foo { #[clippy::msrv = "1.29"] fn msrv_1_29() { #[cfg_attr(rustfmt, rustfmt::skip)] - { 1+29; } + 1+29; } #[clippy::msrv = "1.30"] fn msrv_1_30() { #[cfg_attr(rustfmt, rustfmt::skip)] - { 1+30; } + 1+30; } -- cgit 1.4.1-3-g733a5 From 478d44487e4c69888b29a1bddbcedc7872fbef28 Mon Sep 17 00:00:00 2001 From: Renato Lochetti Date: Thu, 6 Jun 2024 21:44:06 +0100 Subject: Allow manual_unwrap_or_default at useless_conversion_try tests --- tests/ui/useless_conversion_try.rs | 6 +++++- tests/ui/useless_conversion_try.stderr | 18 +++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/tests/ui/useless_conversion_try.rs b/tests/ui/useless_conversion_try.rs index 803d3b39f37..23edeae12b8 100644 --- a/tests/ui/useless_conversion_try.rs +++ b/tests/ui/useless_conversion_try.rs @@ -1,5 +1,9 @@ #![deny(clippy::useless_conversion)] -#![allow(clippy::needless_if, clippy::unnecessary_fallible_conversions)] +#![allow( + clippy::needless_if, + clippy::unnecessary_fallible_conversions, + clippy::manual_unwrap_or_default +)] fn test_generic(val: T) -> T { let _ = T::try_from(val).unwrap(); diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr index 11fb8f38ea5..30a43629dbd 100644 --- a/tests/ui/useless_conversion_try.stderr +++ b/tests/ui/useless_conversion_try.stderr @@ -1,5 +1,5 @@ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion_try.rs:5:13 + --> tests/ui/useless_conversion_try.rs:9:13 | LL | let _ = T::try_from(val).unwrap(); | ^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion_try.rs:7:5 + --> tests/ui/useless_conversion_try.rs:11:5 | LL | val.try_into().unwrap() | ^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | val.try_into().unwrap() = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:30:21 + --> tests/ui/useless_conversion_try.rs:34:21 | LL | let _: String = "foo".to_string().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | let _: String = "foo".to_string().try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:32:21 + --> tests/ui/useless_conversion_try.rs:36:21 | LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); = help: consider removing `TryFrom::try_from()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:34:13 + --> tests/ui/useless_conversion_try.rs:38:13 | LL | let _ = String::try_from("foo".to_string()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | let _ = String::try_from("foo".to_string()).unwrap(); = help: consider removing `String::try_from()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:36:13 + --> tests/ui/useless_conversion_try.rs:40:13 | LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); = help: consider removing `String::try_from()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:38:21 + --> tests/ui/useless_conversion_try.rs:42:21 | LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:40:21 + --> tests/ui/useless_conversion_try.rs:44:21 | LL | let _: String = String::new().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | let _: String = String::new().try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:42:27 + --> tests/ui/useless_conversion_try.rs:46:27 | LL | let _: String = match String::from("_").try_into() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 246d4fe79120976d484a4a57359ee951aedb4ce9 Mon Sep 17 00:00:00 2001 From: Slanterns Date: Fri, 7 Jun 2024 08:37:05 +0800 Subject: bless `std_instead_of_core` --- tests/ui/std_instead_of_core.fixed | 4 ++-- tests/ui/std_instead_of_core.rs | 2 +- tests/ui/std_instead_of_core.stderr | 8 +++++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/ui/std_instead_of_core.fixed b/tests/ui/std_instead_of_core.fixed index ec4ae2ea13c..6ede7bfcd9f 100644 --- a/tests/ui/std_instead_of_core.fixed +++ b/tests/ui/std_instead_of_core.fixed @@ -45,8 +45,8 @@ fn std_instead_of_core() { let _ = std::env!("PATH"); - // do not lint until `error_in_core` is stable - use std::error::Error; + use core::error::Error; + //~^ ERROR: used import from `std` instead of `core` // lint items re-exported from private modules, `core::iter::traits::iterator::Iterator` use core::iter::Iterator; diff --git a/tests/ui/std_instead_of_core.rs b/tests/ui/std_instead_of_core.rs index c12c459c7eb..e22b4f61f3e 100644 --- a/tests/ui/std_instead_of_core.rs +++ b/tests/ui/std_instead_of_core.rs @@ -45,8 +45,8 @@ fn std_instead_of_core() { let _ = std::env!("PATH"); - // do not lint until `error_in_core` is stable use std::error::Error; + //~^ ERROR: used import from `std` instead of `core` // lint items re-exported from private modules, `core::iter::traits::iterator::Iterator` use std::iter::Iterator; diff --git a/tests/ui/std_instead_of_core.stderr b/tests/ui/std_instead_of_core.stderr index 8f920511cc5..22cb9db7050 100644 --- a/tests/ui/std_instead_of_core.stderr +++ b/tests/ui/std_instead_of_core.stderr @@ -49,6 +49,12 @@ error: used import from `std` instead of `core` LL | let cell_absolute = ::std::cell::Cell::new(8u32); | ^^^ help: consider importing the item from `core`: `core` +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core.rs:48:9 + | +LL | use std::error::Error; + | ^^^ help: consider importing the item from `core`: `core` + error: used import from `std` instead of `core` --> tests/ui/std_instead_of_core.rs:52:9 | @@ -79,5 +85,5 @@ LL | use alloc::slice::from_ref; = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::alloc_instead_of_core)]` -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors -- cgit 1.4.1-3-g733a5 From abd011638dffe2586a382b4e89823bf2b84b5a4d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 3 Jun 2024 09:11:58 +0000 Subject: Revert "Create const block DefIds in typeck instead of ast lowering" This reverts commit ddc5f9b6c1f21da5d4596bf7980185a00984ac42. --- clippy_utils/src/consts.rs | 6 +++--- clippy_utils/src/hir_utils.rs | 6 +++--- tests/ui/arithmetic_side_effects.stderr | 32 ++++---------------------------- 3 files changed, 10 insertions(+), 34 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index cd88ccd87cf..5c9cad2b45d 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -6,7 +6,7 @@ use crate::{clip, is_direct_expn_of, sext, unsext}; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; +use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir::interpret::{alloc_range, Scalar}; @@ -412,7 +412,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// Simple constant folding: Insert an expression, get a constant or none. pub fn expr(&mut self, e: &Expr<'_>) -> Option> { match e.kind { - ExprKind::ConstBlock(e) | ExprKind::DropTemps(e) => self.expr(e), + ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr(e), ExprKind::Path(ref qpath) => { self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| { let result = mir_to_const(this.lcx, result)?; @@ -490,7 +490,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// leaves the local crate. pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option { match e.kind { - ExprKind::ConstBlock(e) | ExprKind::DropTemps(e) => self.expr_is_empty(e), + ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr_is_empty(e), ExprKind::Path(ref qpath) => { if !self .typeck_results diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index c649c179468..36634817fc9 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -295,7 +295,7 @@ impl HirEqInterExpr<'_, '_, '_> { self.eq_expr(lx, rx) && self.eq_ty(lt, rt) }, (&ExprKind::Closure(_l), &ExprKind::Closure(_r)) => false, - (&ExprKind::ConstBlock(lb), &ExprKind::ConstBlock(rb)) => self.eq_expr(lb, rb), + (&ExprKind::ConstBlock(lb), &ExprKind::ConstBlock(rb)) => self.eq_body(lb.body, rb.body), (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => { both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name) }, @@ -769,8 +769,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { // closures inherit TypeckResults self.hash_expr(self.cx.tcx.hir().body(body).value); }, - ExprKind::ConstBlock(l_id) => { - self.hash_expr(l_id); + ExprKind::ConstBlock(ref l_id) => { + self.hash_body(l_id.body); }, ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { self.hash_expr(e); diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index df14ff396f6..8039c0bfa24 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -1,35 +1,11 @@ -error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:188:36 - | -LL | let _ = const { let mut n = 1; n += 1; n }; - | ^^^^^^ - | - = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` - -error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:191:40 - | -LL | let _ = const { let mut n = 1; n = n + 1; n }; - | ^^^^^ - -error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:194:40 - | -LL | let _ = const { let mut n = 1; n = 1 + n; n }; - | ^^^^^ - -error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:200:59 - | -LL | let _ = const { let mut n = 1; n = -1; n = -(-1); n = -n; n }; - | ^^ - error: arithmetic operation that can potentially result in unexpected side-effects --> tests/ui/arithmetic_side_effects.rs:304:5 | LL | _n += 1; | ^^^^^^^ + | + = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` error: arithmetic operation that can potentially result in unexpected side-effects --> tests/ui/arithmetic_side_effects.rs:305:5 @@ -751,5 +727,5 @@ error: arithmetic operation that can potentially result in unexpected side-effec LL | one.sub_assign(1); | ^^^^^^^^^^^^^^^^^ -error: aborting due to 125 previous errors +error: aborting due to 121 previous errors -- cgit 1.4.1-3-g733a5 From b21ee38fa91b8a917e7cde983806c77a9b0c5c99 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 15 May 2024 17:30:11 +0000 Subject: Don't lint blocks in closures for blocks_in_conditions --- clippy_lints/src/blocks_in_conditions.rs | 32 +--------- tests/ui/blocks_in_conditions.fixed | 13 ++++ tests/ui/blocks_in_conditions.rs | 13 ++++ tests/ui/blocks_in_conditions_closure.rs | 89 ---------------------------- tests/ui/blocks_in_conditions_closure.stderr | 39 ------------ 5 files changed, 28 insertions(+), 158 deletions(-) delete mode 100644 tests/ui/blocks_in_conditions_closure.rs delete mode 100644 tests/ui/blocks_in_conditions_closure.stderr diff --git a/clippy_lints/src/blocks_in_conditions.rs b/clippy_lints/src/blocks_in_conditions.rs index 869ed332b9c..eb05dc96cde 100644 --- a/clippy_lints/src/blocks_in_conditions.rs +++ b/clippy_lints/src/blocks_in_conditions.rs @@ -1,15 +1,11 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_block_with_applicability; -use clippy_utils::ty::implements_trait; -use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; -use clippy_utils::{get_parent_expr, higher, is_from_proc_macro}; -use core::ops::ControlFlow; +use clippy_utils::{higher, is_from_proc_macro}; use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -124,30 +120,6 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInConditions { ); } } - } else { - let _: Option = for_each_expr_without_closures(cond, |e| { - if let ExprKind::Closure(closure) = e.kind { - // do not lint if the closure is called using an iterator (see #1141) - if let Some(parent) = get_parent_expr(cx, e) - && let ExprKind::MethodCall(_, self_arg, _, _) = &parent.kind - && let caller = cx.typeck_results().expr_ty(self_arg) - && let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator) - && implements_trait(cx, caller, iter_id, &[]) - { - return ControlFlow::Continue(Descend::No); - } - - let body = cx.tcx.hir().body(closure.body); - let ex = &body.value; - if let ExprKind::Block(block, _) = ex.kind { - if !body.value.span.from_expansion() && !block.stmts.is_empty() { - span_lint(cx, BLOCKS_IN_CONDITIONS, ex.span, complex_block_message.clone()); - return ControlFlow::Continue(Descend::No); - } - } - } - ControlFlow::Continue(Descend::Yes) - }); } } } diff --git a/tests/ui/blocks_in_conditions.fixed b/tests/ui/blocks_in_conditions.fixed index a2da5f9c5fb..af8e65270d0 100644 --- a/tests/ui/blocks_in_conditions.fixed +++ b/tests/ui/blocks_in_conditions.fixed @@ -117,4 +117,17 @@ mod issue_12016 { } } +fn in_closure() { + let v = vec![1, 2, 3]; + if v.into_iter() + .filter(|x| { + let y = x + 1; + y > 3 + }) + .any(|x| x == 5) + { + println!("contains 4!"); + } +} + fn main() {} diff --git a/tests/ui/blocks_in_conditions.rs b/tests/ui/blocks_in_conditions.rs index 608ca4cf267..6adae951a29 100644 --- a/tests/ui/blocks_in_conditions.rs +++ b/tests/ui/blocks_in_conditions.rs @@ -117,4 +117,17 @@ mod issue_12016 { } } +fn in_closure() { + let v = vec![1, 2, 3]; + if v.into_iter() + .filter(|x| { + let y = x + 1; + y > 3 + }) + .any(|x| x == 5) + { + println!("contains 4!"); + } +} + fn main() {} diff --git a/tests/ui/blocks_in_conditions_closure.rs b/tests/ui/blocks_in_conditions_closure.rs deleted file mode 100644 index db31e4ae1a9..00000000000 --- a/tests/ui/blocks_in_conditions_closure.rs +++ /dev/null @@ -1,89 +0,0 @@ -#![warn(clippy::blocks_in_conditions)] -#![allow( - unused, - clippy::let_and_return, - clippy::needless_if, - clippy::unnecessary_literal_unwrap -)] - -fn predicate bool, T>(pfn: F, val: T) -> bool { - pfn(val) -} - -fn pred_test() { - let v = 3; - let sky = "blue"; - // This is a sneaky case, where the block isn't directly in the condition, - // but is actually inside a closure that the condition is using. - // The same principle applies -- add some extra expressions to make sure - // linter isn't confused by them. - if v == 3 - && sky == "blue" - && predicate( - |x| { - //~^ ERROR: in an `if` condition, avoid complex blocks or closures with blocks - //~| NOTE: `-D clippy::blocks-in-conditions` implied by `-D warnings` - let target = 3; - x == target - }, - v, - ) - {} - - if predicate( - |x| { - //~^ ERROR: in an `if` condition, avoid complex blocks or closures with blocks; in - let target = 3; - x == target - }, - v, - ) {} -} - -fn closure_without_block() { - if predicate(|x| x == 3, 6) {} -} - -fn macro_in_closure() { - let option = Some(true); - - if option.unwrap_or_else(|| unimplemented!()) { - unimplemented!() - } -} - -fn closure(_: impl FnMut()) -> bool { - true -} - -fn function_with_empty_closure() { - if closure(|| {}) {} -} - -// issue #11814 -fn match_with_pred() { - let v = 3; - match Some(predicate( - |x| { - //~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks - let target = 3; - x == target - }, - v, - )) { - Some(true) => 1, - Some(false) => 2, - None => 3, - }; -} - -#[rustfmt::skip] -fn main() { - let mut range = 0..10; - range.all(|i| {i < 10} ); - - let v = vec![1, 2, 3]; - if v.into_iter().any(|x| {x == 4}) { - println!("contains 4!"); - } -} diff --git a/tests/ui/blocks_in_conditions_closure.stderr b/tests/ui/blocks_in_conditions_closure.stderr deleted file mode 100644 index 2faae680ec0..00000000000 --- a/tests/ui/blocks_in_conditions_closure.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions_closure.rs:23:17 - | -LL | |x| { - | _________________^ -LL | | -LL | | -LL | | let target = 3; -LL | | x == target -LL | | }, - | |_____________^ - | - = note: `-D clippy::blocks-in-conditions` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::blocks_in_conditions)]` - -error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions_closure.rs:34:13 - | -LL | |x| { - | _____________^ -LL | | -LL | | let target = 3; -LL | | x == target -LL | | }, - | |_________^ - -error: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions_closure.rs:67:13 - | -LL | |x| { - | _____________^ -LL | | -LL | | let target = 3; -LL | | x == target -LL | | }, - | |_________^ - -error: aborting due to 3 previous errors - -- cgit 1.4.1-3-g733a5 From 65af5d7b22ecd29a5aad8b6849659c9eaf62a96a Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 7 Jun 2024 12:00:08 +0000 Subject: Remove `lazy_static` mention --- clippy_lints/src/non_copy_const.rs | 32 ++++++++++------ tests/ui/crashes/ice-9445.rs | 2 - tests/ui/crashes/ice-9445.stderr | 7 ++-- tests/ui/crashes/mut_mut_macro.rs | 33 ----------------- .../ui/declare_interior_mutable_const/enums.stderr | 43 ++++++++++------------ .../declare_interior_mutable_const/others.stderr | 27 +++++++------- .../declare_interior_mutable_const/traits.stderr | 26 ++++++------- 7 files changed, 69 insertions(+), 101 deletions(-) delete mode 100644 tests/ui/crashes/mut_mut_macro.rs diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 76d9cee18aa..464c658b2b4 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -7,7 +7,7 @@ use std::ptr; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::in_constant; use clippy_utils::macros::macro_backtrace; -use clippy_utils::ty::InteriorMut; +use clippy_utils::ty::{implements_trait, InteriorMut}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ @@ -18,7 +18,7 @@ use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, InnerSpan, Span, DUMMY_SP}; +use rustc_span::{sym, Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; // FIXME: this is a correctness problem but there's no suitable @@ -127,19 +127,19 @@ declare_clippy_lint! { } #[derive(Copy, Clone)] -enum Source { - Item { item: Span }, +enum Source<'tcx> { + Item { item: Span, ty: Ty<'tcx> }, Assoc { item: Span }, Expr { expr: Span }, } -impl Source { +impl Source<'_> { #[must_use] fn lint(&self) -> (&'static Lint, &'static str, Span) { match self { - Self::Item { item } | Self::Assoc { item, .. } => ( + Self::Item { item, .. } | Self::Assoc { item, .. } => ( DECLARE_INTERIOR_MUTABLE_CONST, - "a `const` item should never be interior mutable", + "a `const` item should not be interior mutable", *item, ), Self::Expr { expr } => ( @@ -151,16 +151,24 @@ impl Source { } } -fn lint(cx: &LateContext<'_>, source: Source) { +fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) { let (lint, msg, span) = source.lint(); span_lint_and_then(cx, lint, span, msg, |diag| { if span.from_expansion() { return; // Don't give suggestions into macros. } match source { - Source::Item { .. } => { - let const_kw_span = span.from_inner(InnerSpan::new(0, 5)); - diag.span_label(const_kw_span, "make this a static item (maybe with lazy_static)"); + Source::Item { ty, .. } => { + let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else { + return; + }; + if implements_trait(cx, ty, sync_trait, &[]) { + diag.help("consider making this a static item"); + } else { + diag.help( + "consider making this `Sync` so that it can go in a static item or using a `thread_local`", + ); + } }, Source::Assoc { .. } => (), Source::Expr { .. } => { @@ -311,7 +319,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { && self.interior_mut.is_interior_mut_ty(cx, ty) && Self::is_value_unfrozen_poly(cx, body_id, ty) { - lint(cx, Source::Item { item: it.span }); + lint(cx, Source::Item { item: it.span, ty }); } } } diff --git a/tests/ui/crashes/ice-9445.rs b/tests/ui/crashes/ice-9445.rs index b6afbd33c79..c67b22f6f8c 100644 --- a/tests/ui/crashes/ice-9445.rs +++ b/tests/ui/crashes/ice-9445.rs @@ -1,5 +1,3 @@ const UNINIT: core::mem::MaybeUninit> = core::mem::MaybeUninit::uninit(); -//~^ ERROR: a `const` item should never be interior mutable -//~| NOTE: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` fn main() {} diff --git a/tests/ui/crashes/ice-9445.stderr b/tests/ui/crashes/ice-9445.stderr index d6957e9549d..76689cd6f5c 100644 --- a/tests/ui/crashes/ice-9445.stderr +++ b/tests/ui/crashes/ice-9445.stderr @@ -1,11 +1,10 @@ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/crashes/ice-9445.rs:1:1 | LL | const UNINIT: core::mem::MaybeUninit> = core::mem::MaybeUninit::uninit(); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` diff --git a/tests/ui/crashes/mut_mut_macro.rs b/tests/ui/crashes/mut_mut_macro.rs deleted file mode 100644 index 92821b6ecbb..00000000000 --- a/tests/ui/crashes/mut_mut_macro.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![deny(clippy::mut_mut, clippy::zero_ptr)] -#![allow(dead_code)] - -// FIXME: compiletest + extern crates doesn't work together. To make this test work, it would need -// the following three lines and the lazy_static crate. -// -// #[macro_use] -// extern crate lazy_static; -// use std::collections::HashMap; - -/// ensure that we don't suggest `is_null` inside constants -/// FIXME: once const fn is stable, suggest these functions again in constants - -const BAA: *const i32 = 0 as *const i32; -static mut BAR: *const i32 = BAA; -static mut FOO: *const i32 = 0 as *const i32; - -#[allow(unused_variables, unused_mut)] -fn main() { - /* - lazy_static! { - static ref MUT_MAP : HashMap = { - let mut m = HashMap::new(); - m.insert(0, "zero"); - m - }; - static ref MUT_COUNT : usize = MUT_MAP.len(); - } - assert_eq!(*MUT_COUNT, 1); - */ - // FIXME: don't lint in array length, requires `check_body` - //let _ = [""; (42.0 < f32::NAN) as usize]; -} diff --git a/tests/ui/declare_interior_mutable_const/enums.stderr b/tests/ui/declare_interior_mutable_const/enums.stderr index 6c0dce6b5ea..22329172c3a 100644 --- a/tests/ui/declare_interior_mutable_const/enums.stderr +++ b/tests/ui/declare_interior_mutable_const/enums.stderr @@ -1,87 +1,84 @@ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:12:1 | LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:23:1 | LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:45:1 | -LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { - | ^---- - | | - | _make this a static item (maybe with lazy_static) - | | +LL | / const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { LL | | LL | | outer: NestedOuter::NestedInner(NestedInner { LL | | inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), LL | | }), LL | | }; | |__^ + | + = help: consider making this a static item -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:60:5 | LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:61:5 | LL | const TO_BE_FROZEN_VARIANT: OptionalCell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:64:5 | LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:90:5 | LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:102:5 | LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:105:5 | LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:111:5 | LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:118:5 | LL | / const UNFROZEN_VARIANT: BothOfCellAndGeneric = LL | | BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); | |____________________________________________________________________^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:120:5 | LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr index 9dba0c95221..1f2b9561ce5 100644 --- a/tests/ui/declare_interior_mutable_const/others.stderr +++ b/tests/ui/declare_interior_mutable_const/others.stderr @@ -1,31 +1,30 @@ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/others.rs:9:1 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: consider making this a static item = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/others.rs:10:1 | LL | const CELL: Cell = Cell::new(6); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/others.rs:11:1 | LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider making this a static item -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/others.rs:16:9 | LL | const $name: $ty = $e; @@ -36,7 +35,7 @@ LL | declare_const!(_ONCE: Once = Once::new()); | = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/others.rs:44:13 | LL | const _BAZ: Cell = Cell::new(0); diff --git a/tests/ui/declare_interior_mutable_const/traits.stderr b/tests/ui/declare_interior_mutable_const/traits.stderr index 1d1e9e2002f..4a793d985e5 100644 --- a/tests/ui/declare_interior_mutable_const/traits.stderr +++ b/tests/ui/declare_interior_mutable_const/traits.stderr @@ -1,4 +1,4 @@ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:16:5 | LL | const ATOMIC: AtomicUsize; @@ -7,7 +7,7 @@ LL | const ATOMIC: AtomicUsize; = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:9:9 | LL | const $name: $ty = $e; @@ -18,67 +18,67 @@ LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); | = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:44:5 | LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:69:5 | LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:70:5 | LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:89:5 | LL | const BOUNDED: T::ToBeBounded; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:117:5 | LL | const SELF: Self = AtomicUsize::new(17); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:118:5 | LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:124:5 | LL | const DIRECT: Cell; | ^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:125:5 | LL | const INDIRECT: Cell<*const T>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:129:5 | LL | const DIRECT: Cell = Cell::new(T::DEFAULT); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:141:5 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:147:5 | LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); -- cgit 1.4.1-3-g733a5 From 1781333ec75b9222446405aa0ab960f2fea004bb Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Sat, 8 Jun 2024 00:06:20 +0800 Subject: [`match_same_arms`]: add a test case with lifetimes --- tests/ui/match_same_arms2.fixed | 17 +++++++++++++++++ tests/ui/match_same_arms2.rs | 18 ++++++++++++++++++ tests/ui/match_same_arms2.stderr | 18 +++++++++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/tests/ui/match_same_arms2.fixed b/tests/ui/match_same_arms2.fixed index fba0cf33b3c..09e960ddd6a 100644 --- a/tests/ui/match_same_arms2.fixed +++ b/tests/ui/match_same_arms2.fixed @@ -239,3 +239,20 @@ fn main() { _ => false, }; } + +// issue #8919, fixed on https://github.com/rust-lang/rust/pull/97312 +mod with_lifetime { + enum MaybeStaticStr<'a> { + Static(&'static str), + Borrowed(&'a str), + } + + impl<'a> MaybeStaticStr<'a> { + fn get(&self) -> &'a str { + match *self { + MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s, + //~^ ERROR: this match arm has an identical body to another arm + } + } + } +} diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index 8a4e3b325bb..cc7425135cc 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -262,3 +262,21 @@ fn main() { _ => false, }; } + +// issue #8919, fixed on https://github.com/rust-lang/rust/pull/97312 +mod with_lifetime { + enum MaybeStaticStr<'a> { + Static(&'static str), + Borrowed(&'a str), + } + + impl<'a> MaybeStaticStr<'a> { + fn get(&self) -> &'a str { + match *self { + MaybeStaticStr::Static(s) => s, + MaybeStaticStr::Borrowed(s) => s, + //~^ ERROR: this match arm has an identical body to another arm + } + } + } +} diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr index 3d15176ccf9..a5d137c658b 100644 --- a/tests/ui/match_same_arms2.stderr +++ b/tests/ui/match_same_arms2.stderr @@ -221,5 +221,21 @@ help: and remove this obsolete arm LL - 0 => cfg!(not_enable), | -error: aborting due to 13 previous errors +error: this match arm has an identical body to another arm + --> tests/ui/match_same_arms2.rs:277:17 + | +LL | MaybeStaticStr::Borrowed(s) => s, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: and remove this obsolete arm + | +LL - MaybeStaticStr::Static(s) => s, + | + +error: aborting due to 14 previous errors -- cgit 1.4.1-3-g733a5 From 1f125a67163115c03e58c4da2b6f9dae68a52c4a Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Fri, 7 Jun 2024 20:20:51 +0200 Subject: add HermitOS support of vectored read/write operations In general, the I/O interface of hermit-abi is more POSIX-like interface. Consequently, platform abstraction layer for HermitOS has slightly adjusted and some inaccuracies remove. --- Cargo.lock | 10 +++- library/std/Cargo.toml | 2 +- library/std/src/sys/pal/hermit/fd.rs | 39 ++++++++++++++- library/std/src/sys/pal/hermit/fs.rs | 45 ++++++++---------- library/std/src/sys/pal/hermit/futex.rs | 2 +- library/std/src/sys/pal/hermit/io.rs | 82 ++++++++++++++++++++++++++++++++ library/std/src/sys/pal/hermit/mod.rs | 1 - library/std/src/sys/pal/hermit/net.rs | 13 +++-- library/std/src/sys/pal/hermit/os.rs | 2 +- library/std/src/sys/pal/hermit/stdio.rs | 67 +++++++++----------------- library/std/src/sys/pal/hermit/thread.rs | 2 +- library/std/src/sys/pal/hermit/time.rs | 18 +++---- 12 files changed, 189 insertions(+), 94 deletions(-) create mode 100644 library/std/src/sys/pal/hermit/io.rs diff --git a/Cargo.lock b/Cargo.lock index 54b1bf593e0..762648e862e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1694,6 +1694,12 @@ name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -2636,7 +2642,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] @@ -5363,7 +5369,7 @@ dependencies = [ "dlmalloc", "fortanix-sgx-abi", "hashbrown", - "hermit-abi", + "hermit-abi 0.4.0", "libc", "miniz_oxide", "object 0.36.0", diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 68bba5c2be1..32479cd2836 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -50,7 +50,7 @@ dlmalloc = { version = "0.2.4", features = ['rustc-dep-of-std'] } fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'], public = true } [target.'cfg(target_os = "hermit")'.dependencies] -hermit-abi = { version = "0.3.9", features = ['rustc-dep-of-std'], public = true } +hermit-abi = { version = "0.4.0", features = ['rustc-dep-of-std'], public = true } [target.'cfg(target_os = "wasi")'.dependencies] wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false } diff --git a/library/std/src/sys/pal/hermit/fd.rs b/library/std/src/sys/pal/hermit/fd.rs index d7dab08cfbd..3c52b85de23 100644 --- a/library/std/src/sys/pal/hermit/fd.rs +++ b/library/std/src/sys/pal/hermit/fd.rs @@ -1,7 +1,8 @@ #![unstable(reason = "not public", issue = "none", feature = "fd")] use super::hermit_abi; -use crate::io::{self, Read}; +use crate::cmp; +use crate::io::{self, IoSlice, IoSliceMut, Read}; use crate::os::hermit::io::{FromRawFd, OwnedFd, RawFd}; use crate::sys::cvt; use crate::sys::unsupported; @@ -9,6 +10,10 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::os::hermit::io::*; +const fn max_iov() -> usize { + hermit_abi::IOV_MAX +} + #[derive(Debug)] pub struct FileDesc { fd: OwnedFd, @@ -21,6 +26,22 @@ impl FileDesc { Ok(result as usize) } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let ret = cvt(unsafe { + hermit_abi::readv( + self.as_raw_fd(), + bufs.as_mut_ptr() as *mut hermit_abi::iovec as *const hermit_abi::iovec, + cmp::min(bufs.len(), max_iov()), + ) + })?; + Ok(ret as usize) + } + + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { let mut me = self; (&mut me).read_to_end(buf) @@ -32,6 +53,22 @@ impl FileDesc { Ok(result as usize) } + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + let ret = cvt(unsafe { + hermit_abi::writev( + self.as_raw_fd(), + bufs.as_ptr() as *const hermit_abi::iovec, + cmp::min(bufs.len(), max_iov()), + ) + })?; + Ok(ret as usize) + } + + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn duplicate(&self) -> io::Result { self.duplicate_path(&[]) } diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs index a4a16e6e86b..a98a1006ef4 100644 --- a/library/std/src/sys/pal/hermit/fs.rs +++ b/library/std/src/sys/pal/hermit/fs.rs @@ -1,7 +1,7 @@ use super::fd::FileDesc; use super::hermit_abi::{ self, dirent64, stat as stat_struct, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, - O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, + O_DIRECTORY, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, }; use crate::ffi::{CStr, OsStr, OsString}; use crate::fmt; @@ -62,7 +62,7 @@ pub struct DirEntry { /// 64-bit inode number ino: u64, /// File type - type_: u32, + type_: u8, /// name of the entry name: OsString, } @@ -90,7 +90,7 @@ pub struct FilePermissions { #[derive(Copy, Clone, Eq, Debug)] pub struct FileType { - mode: u32, + mode: u8, } impl PartialEq for FileType { @@ -112,31 +112,23 @@ pub struct DirBuilder { impl FileAttr { pub fn modified(&self) -> io::Result { - Ok(SystemTime::new( - self.stat_val.st_mtime.try_into().unwrap(), - self.stat_val.st_mtime_nsec.try_into().unwrap(), - )) + Ok(SystemTime::new(self.stat_val.st_mtim.tv_sec, self.stat_val.st_mtim.tv_nsec)) } pub fn accessed(&self) -> io::Result { - Ok(SystemTime::new( - self.stat_val.st_atime.try_into().unwrap(), - self.stat_val.st_atime_nsec.try_into().unwrap(), - )) + Ok(SystemTime::new(self.stat_val.st_atim.tv_sec, self.stat_val.st_atim.tv_nsec)) } pub fn created(&self) -> io::Result { - Ok(SystemTime::new( - self.stat_val.st_ctime.try_into().unwrap(), - self.stat_val.st_ctime_nsec.try_into().unwrap(), - )) + Ok(SystemTime::new(self.stat_val.st_ctim.tv_sec, self.stat_val.st_ctim.tv_nsec)) } pub fn size(&self) -> u64 { self.stat_val.st_size as u64 } + pub fn perm(&self) -> FilePermissions { - FilePermissions { mode: (self.stat_val.st_mode) } + FilePermissions { mode: self.stat_val.st_mode } } pub fn file_type(&self) -> FileType { @@ -220,7 +212,7 @@ impl Iterator for ReadDir { let entry = DirEntry { root: self.inner.root.clone(), ino: dir.d_ino, - type_: dir.d_type as u32, + type_: dir.d_type, name: OsString::from_vec(name_bytes.to_vec()), }; @@ -251,7 +243,7 @@ impl DirEntry { } pub fn file_type(&self) -> io::Result { - Ok(FileType { mode: self.type_ as u32 }) + Ok(FileType { mode: self.type_ }) } #[allow(dead_code)] @@ -385,12 +377,12 @@ impl File { } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - crate::io::default_read_vectored(|buf| self.read(buf), bufs) + self.0.read_vectored(bufs) } #[inline] pub fn is_read_vectored(&self) -> bool { - false + self.0.is_read_vectored() } pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { @@ -402,12 +394,12 @@ impl File { } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - crate::io::default_write_vectored(|buf| self.write(buf), bufs) + self.0.write_vectored(bufs) } #[inline] pub fn is_write_vectored(&self) -> bool { - false + self.0.is_write_vectored() } #[inline] @@ -439,13 +431,13 @@ impl DirBuilder { pub fn mkdir(&self, path: &Path) -> io::Result<()> { run_path_with_cstr(path, &|path| { - cvt(unsafe { hermit_abi::mkdir(path.as_ptr(), self.mode) }).map(|_| ()) + cvt(unsafe { hermit_abi::mkdir(path.as_ptr(), self.mode.into()) }).map(|_| ()) }) } #[allow(dead_code)] pub fn set_mode(&mut self, mode: u32) { - self.mode = mode as u32; + self.mode = mode; } } @@ -501,8 +493,9 @@ impl FromRawFd for File { } pub fn readdir(path: &Path) -> io::Result { - let fd_raw = - run_path_with_cstr(path, &|path| cvt(unsafe { hermit_abi::opendir(path.as_ptr()) }))?; + let fd_raw = run_path_with_cstr(path, &|path| { + cvt(unsafe { hermit_abi::open(path.as_ptr(), O_RDONLY | O_DIRECTORY, 0) }) + })?; let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) }; let root = path.to_path_buf(); diff --git a/library/std/src/sys/pal/hermit/futex.rs b/library/std/src/sys/pal/hermit/futex.rs index 571b2885658..b2d74d1311b 100644 --- a/library/std/src/sys/pal/hermit/futex.rs +++ b/library/std/src/sys/pal/hermit/futex.rs @@ -10,7 +10,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) - let timespec = timeout.and_then(|dur| { Some(hermit_abi::timespec { tv_sec: dur.as_secs().try_into().ok()?, - tv_nsec: dur.subsec_nanos().into(), + tv_nsec: dur.subsec_nanos().try_into().ok()?, }) }); diff --git a/library/std/src/sys/pal/hermit/io.rs b/library/std/src/sys/pal/hermit/io.rs new file mode 100644 index 00000000000..9de7b53e53c --- /dev/null +++ b/library/std/src/sys/pal/hermit/io.rs @@ -0,0 +1,82 @@ +use crate::marker::PhantomData; +use crate::os::hermit::io::{AsFd, AsRawFd}; +use crate::slice; + +use hermit_abi::{c_void, iovec}; + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct IoSlice<'a> { + vec: iovec, + _p: PhantomData<&'a [u8]>, +} + +impl<'a> IoSlice<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice { + vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSlice beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} + +#[repr(transparent)] +pub struct IoSliceMut<'a> { + vec: iovec, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoSliceMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut { + vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSliceMut beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} + +pub fn is_terminal(fd: &impl AsFd) -> bool { + let fd = fd.as_fd(); + hermit_abi::isatty(fd.as_raw_fd()) +} diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index a64323a3a29..eca7351d54c 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -23,7 +23,6 @@ pub mod env; pub mod fd; pub mod fs; pub mod futex; -#[path = "../unsupported/io.rs"] pub mod io; pub mod net; pub mod os; diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs index 00dbca86a4b..6016d50eba0 100644 --- a/library/std/src/sys/pal/hermit/net.rs +++ b/library/std/src/sys/pal/hermit/net.rs @@ -175,12 +175,12 @@ impl Socket { } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - crate::io::default_read_vectored(|b| self.read(b), bufs) + self.0.read_vectored(bufs) } #[inline] pub fn is_read_vectored(&self) -> bool { - false + self.0.is_read_vectored() } fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> { @@ -209,16 +209,15 @@ impl Socket { } pub fn write(&self, buf: &[u8]) -> io::Result { - let sz = cvt(unsafe { netc::write(self.0.as_raw_fd(), buf.as_ptr(), buf.len()) })?; - Ok(sz.try_into().unwrap()) + self.0.write(buf) } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - crate::io::default_write_vectored(|b| self.write(b), bufs) + self.0.write_vectored(bufs) } pub fn is_write_vectored(&self) -> bool { - false + self.0.is_write_vectored() } pub fn set_timeout(&self, dur: Option, kind: i32) -> io::Result<()> { @@ -265,7 +264,7 @@ impl Socket { Shutdown::Read => netc::SHUT_RD, Shutdown::Both => netc::SHUT_RDWR, }; - cvt(unsafe { netc::shutdown_socket(self.as_raw_fd(), how) })?; + cvt(unsafe { netc::shutdown(self.as_raw_fd(), how) })?; Ok(()) } diff --git a/library/std/src/sys/pal/hermit/os.rs b/library/std/src/sys/pal/hermit/os.rs index 91247d30462..a7a73c756f2 100644 --- a/library/std/src/sys/pal/hermit/os.rs +++ b/library/std/src/sys/pal/hermit/os.rs @@ -198,5 +198,5 @@ pub fn exit(code: i32) -> ! { } pub fn getpid() -> u32 { - unsafe { hermit_abi::getpid() } + unsafe { hermit_abi::getpid() as u32 } } diff --git a/library/std/src/sys/pal/hermit/stdio.rs b/library/std/src/sys/pal/hermit/stdio.rs index 777c57b391c..3ea00f5cc5e 100644 --- a/library/std/src/sys/pal/hermit/stdio.rs +++ b/library/std/src/sys/pal/hermit/stdio.rs @@ -1,6 +1,9 @@ use super::hermit_abi; use crate::io; use crate::io::{IoSlice, IoSliceMut}; +use crate::mem::ManuallyDrop; +use crate::os::hermit::io::FromRawFd; +use crate::sys::fd::FileDesc; pub struct Stdin; pub struct Stdout; @@ -13,12 +16,14 @@ impl Stdin { } impl io::Read for Stdin { - fn read(&mut self, data: &mut [u8]) -> io::Result { - self.read_vectored(&mut [IoSliceMut::new(data)]) + fn read(&mut self, buf: &mut [u8]) -> io::Result { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDIN_FILENO)).read(buf) } } - fn read_vectored(&mut self, _data: &mut [IoSliceMut<'_>]) -> io::Result { - Ok(0) + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + unsafe { + ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDIN_FILENO)).read_vectored(bufs) + } } #[inline] @@ -34,27 +39,13 @@ impl Stdout { } impl io::Write for Stdout { - fn write(&mut self, data: &[u8]) -> io::Result { - let len; - - unsafe { len = hermit_abi::write(1, data.as_ptr() as *const u8, data.len()) } - - if len < 0 { - Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print")) - } else { - Ok(len as usize) - } + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDOUT_FILENO)).write(buf) } } - fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result { - let len; - - unsafe { len = hermit_abi::write(1, data.as_ptr() as *const u8, data.len()) } - - if len < 0 { - Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print")) - } else { - Ok(len as usize) + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + unsafe { + ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDOUT_FILENO)).write_vectored(bufs) } } @@ -75,27 +66,13 @@ impl Stderr { } impl io::Write for Stderr { - fn write(&mut self, data: &[u8]) -> io::Result { - let len; - - unsafe { len = hermit_abi::write(2, data.as_ptr() as *const u8, data.len()) } - - if len < 0 { - Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print")) - } else { - Ok(len as usize) - } + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDERR_FILENO)).write(buf) } } - fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result { - let len; - - unsafe { len = hermit_abi::write(2, data.as_ptr() as *const u8, data.len()) } - - if len < 0 { - Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print")) - } else { - Ok(len as usize) + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + unsafe { + ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDERR_FILENO)).write_vectored(bufs) } } @@ -109,10 +86,10 @@ impl io::Write for Stderr { } } -pub const STDIN_BUF_SIZE: usize = 0; +pub const STDIN_BUF_SIZE: usize = 128; -pub fn is_ebadf(_err: &io::Error) -> bool { - true +pub fn is_ebadf(err: &io::Error) -> bool { + err.raw_os_error() == Some(hermit_abi::EBADF) } pub fn panic_output() -> Option { diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs index b336dcd6860..07a843a597e 100644 --- a/library/std/src/sys/pal/hermit/thread.rs +++ b/library/std/src/sys/pal/hermit/thread.rs @@ -98,5 +98,5 @@ impl Thread { } pub fn available_parallelism() -> io::Result> { - unsafe { Ok(NonZero::new_unchecked(hermit_abi::get_processor_count())) } + unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) } } diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index 2bf24462fa8..e0cb7c2aa98 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -1,11 +1,13 @@ #![allow(dead_code)] -use super::hermit_abi::{self, timespec, CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC}; +use super::hermit_abi::{self, timespec, CLOCK_MONOTONIC, CLOCK_REALTIME}; use crate::cmp::Ordering; use crate::ops::{Add, AddAssign, Sub, SubAssign}; use crate::time::Duration; use core::hash::{Hash, Hasher}; +const NSEC_PER_SEC: i32 = 1_000_000_000; + #[derive(Copy, Clone, Debug)] struct Timespec { t: timespec, @@ -16,8 +18,8 @@ impl Timespec { Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } } } - const fn new(tv_sec: i64, tv_nsec: i64) -> Timespec { - assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64); + const fn new(tv_sec: i64, tv_nsec: i32) -> Timespec { + assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC); // SAFETY: The assert above checks tv_nsec is within the valid range Timespec { t: timespec { tv_sec: tv_sec, tv_nsec: tv_nsec } } } @@ -32,7 +34,7 @@ impl Timespec { } else { Duration::new( (self.t.tv_sec - 1 - other.t.tv_sec) as u64, - self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32, + (self.t.tv_nsec + NSEC_PER_SEC - other.t.tv_nsec) as u32, ) }) } else { @@ -48,9 +50,9 @@ impl Timespec { // Nano calculations can't overflow because nanos are <1B which fit // in a u32. - let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; - if nsec >= NSEC_PER_SEC as u32 { - nsec -= NSEC_PER_SEC as u32; + let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap(); + if nsec >= NSEC_PER_SEC.try_into().unwrap() { + nsec -= u32::try_from(NSEC_PER_SEC).unwrap(); secs = secs.checked_add(1)?; } Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } }) @@ -200,7 +202,7 @@ pub struct SystemTime(Timespec); pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero()); impl SystemTime { - pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime { + pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime { SystemTime(Timespec::new(tv_sec, tv_nsec)) } -- cgit 1.4.1-3-g733a5 From 6fdf295664acc28ebb018e1d7b97b9e9e1e8f0ea Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Tue, 16 Apr 2024 20:25:35 +0200 Subject: let `qualify_min_const_fn` deal with drop checks --- clippy_lints/src/missing_const_for_fn.rs | 15 +-------------- tests/ui/missing_const_for_fn/could_be_const.rs | 18 ++++++++++++++++++ tests/ui/missing_const_for_fn/could_be_const.stderr | 18 +++++++++++++++++- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 9ba19e0a865..fe636f27a0f 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,7 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint; use clippy_utils::qualify_min_const_fn::is_min_const_fn; -use clippy_utils::ty::has_drop; use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method}; use rustc_hir as hir; use rustc_hir::def_id::CRATE_DEF_ID; @@ -121,10 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { } }, FnKind::Method(_, sig, ..) => { - if trait_ref_of_method(cx, def_id).is_some() - || already_const(sig.header) - || method_accepts_droppable(cx, def_id) - { + if trait_ref_of_method(cx, def_id).is_some() || already_const(sig.header) { return; } }, @@ -162,15 +158,6 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { extract_msrv_attr!(LateContext); } -/// Returns true if any of the method parameters is a type that implements `Drop`. The method -/// can't be made const then, because `drop` can't be const-evaluated. -fn method_accepts_droppable(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { - let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); - - // If any of the params are droppable, return true - sig.inputs().iter().any(|&ty| has_drop(cx, ty)) -} - // We don't have to lint on something that's already `const` #[must_use] fn already_const(header: hir::FnHeader) -> bool { diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index 06dbbeb31c0..8e0ede478b5 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -141,3 +141,21 @@ mod msrv { let _ = unsafe { bar.val }; } } + +mod issue12677 { + pub struct Wrapper { + pub strings: Vec, + } + + impl Wrapper { + #[must_use] + pub fn new(strings: Vec) -> Self { + Self { strings } + } + + #[must_use] + pub fn empty() -> Self { + Self { strings: Vec::new() } + } + } +} diff --git a/tests/ui/missing_const_for_fn/could_be_const.stderr b/tests/ui/missing_const_for_fn/could_be_const.stderr index b2cade30563..84ad6357b7b 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -130,5 +130,21 @@ LL | | let _ = unsafe { bar.val }; LL | | } | |_____^ -error: aborting due to 14 previous errors +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:152:9 + | +LL | / pub fn new(strings: Vec) -> Self { +LL | | Self { strings } +LL | | } + | |_________^ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:157:9 + | +LL | / pub fn empty() -> Self { +LL | | Self { strings: Vec::new() } +LL | | } + | |_________^ + +error: aborting due to 16 previous errors -- cgit 1.4.1-3-g733a5 From 973f318514cec40bd388f9e6f1acacc9e2bed436 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Tue, 16 Apr 2024 21:27:34 +0200 Subject: qualify_min_const_fn: ignore cleanup bbs --- clippy_utils/src/qualify_min_const_fn.rs | 10 +++++++--- tests/ui/missing_const_for_fn/could_be_const.rs | 12 ++++++++++++ tests/ui/missing_const_for_fn/could_be_const.stderr | 11 ++++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 81e94725a70..42b10f69c0c 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -40,9 +40,13 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) )?; for bb in &*body.basic_blocks { - check_terminator(tcx, body, bb.terminator(), msrv)?; - for stmt in &bb.statements { - check_statement(tcx, body, def_id, stmt, msrv)?; + // Cleanup blocks are ignored entirely by const eval, so we can too: + // https://github.com/rust-lang/rust/blob/1dea922ea6e74f99a0e97de5cdb8174e4dea0444/compiler/rustc_const_eval/src/transform/check_consts/check.rs#L382 + if !bb.is_cleanup { + check_terminator(tcx, body, bb.terminator(), msrv)?; + for stmt in &bb.statements { + check_statement(tcx, body, def_id, stmt, msrv)?; + } } } Ok(()) diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index 8e0ede478b5..58e639cc7fd 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -158,4 +158,16 @@ mod issue12677 { Self { strings: Vec::new() } } } + + pub struct Other { + pub text: String, + pub vec: Vec, + } + + impl Other { + pub fn new(text: String) -> Self { + let vec = Vec::new(); + Self { text, vec } + } + } } diff --git a/tests/ui/missing_const_for_fn/could_be_const.stderr b/tests/ui/missing_const_for_fn/could_be_const.stderr index 84ad6357b7b..1c61c3e8713 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -146,5 +146,14 @@ LL | | Self { strings: Vec::new() } LL | | } | |_________^ -error: aborting due to 16 previous errors +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:168:9 + | +LL | / pub fn new(text: String) -> Self { +LL | | let vec = Vec::new(); +LL | | Self { text, vec } +LL | | } + | |_________^ + +error: aborting due to 17 previous errors -- cgit 1.4.1-3-g733a5 From c3d3a3f30164644d64c09812c863415f28604e80 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Fri, 7 Jun 2024 21:54:33 +0200 Subject: remove unnecessary const error handling in `missing_const_for_fn` --- clippy_lints/src/missing_const_for_fn.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index fe636f27a0f..4592324809f 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -147,11 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { let mir = cx.tcx.optimized_mir(def_id); - if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, &self.msrv) { - if cx.tcx.is_const_fn_raw(def_id.to_def_id()) { - cx.tcx.dcx().span_err(span, err); - } - } else { + if let Ok(()) = is_min_const_fn(cx.tcx, mir, &self.msrv) { span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`"); } } -- cgit 1.4.1-3-g733a5 From 75e1d72093262ad955262b7cefea05a3d412de7c Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 8 Jun 2024 01:19:05 -0400 Subject: Normalize type aliases when checking significant drops. --- clippy_lints/src/significant_drop_tightening.rs | 50 +++++++++---------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 038eb92d652..979d6dc77ae 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{indent_of, snippet}; use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, Visitor}; @@ -12,6 +12,7 @@ use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, DUMMY_SP}; use std::borrow::Cow; +use std::collections::hash_map::Entry; declare_clippy_lint! { /// ### What it does @@ -57,7 +58,6 @@ impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]); pub struct SignificantDropTightening<'tcx> { apas: FxIndexMap, /// Auxiliary structure used to avoid having to verify the same type multiple times. - seen_types: FxHashSet>, type_cache: FxHashMap, bool>, } @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { self.apas.clear(); let initial_dummy_stmt = dummy_stmt_expr(body.value); let mut ap = AuxParams::new(&mut self.apas, &initial_dummy_stmt); - StmtsChecker::new(&mut ap, cx, &mut self.seen_types, &mut self.type_cache).visit_body(body); + StmtsChecker::new(&mut ap, cx, &mut self.type_cache).visit_body(body); for apa in ap.apas.values() { if apa.counter <= 1 || !apa.has_expensive_expr_after_last_attr { continue; @@ -142,28 +142,25 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { /// Checks the existence of the `#[has_significant_drop]` attribute. struct AttrChecker<'cx, 'others, 'tcx> { cx: &'cx LateContext<'tcx>, - seen_types: &'others mut FxHashSet>, type_cache: &'others mut FxHashMap, bool>, } impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { - pub(crate) fn new( - cx: &'cx LateContext<'tcx>, - seen_types: &'others mut FxHashSet>, - type_cache: &'others mut FxHashMap, bool>, - ) -> Self { - seen_types.clear(); - Self { - cx, - seen_types, - type_cache, - } + pub(crate) fn new(cx: &'cx LateContext<'tcx>, type_cache: &'others mut FxHashMap, bool>) -> Self { + Self { cx, type_cache } } fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { - // The borrow checker prevents us from using something fancier like or_insert_with. - if let Some(ty) = self.type_cache.get(&ty) { - return *ty; + let ty = self + .cx + .tcx + .try_normalize_erasing_regions(self.cx.param_env, ty) + .unwrap_or(ty); + match self.type_cache.entry(ty) { + Entry::Occupied(e) => return *e.get(), + Entry::Vacant(e) => { + e.insert(false); + }, } let value = self.has_sig_drop_attr_uncached(ty); self.type_cache.insert(ty, value); @@ -185,7 +182,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { rustc_middle::ty::Adt(a, b) => { for f in a.all_fields() { let ty = f.ty(self.cx.tcx, b); - if !self.has_seen_ty(ty) && self.has_sig_drop_attr(ty) { + if self.has_sig_drop_attr(ty) { return true; } } @@ -205,16 +202,11 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { _ => false, } } - - fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool { - !self.seen_types.insert(ty) - } } struct StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx> { ap: &'ap mut AuxParams<'others, 'stmt, 'tcx>, cx: &'lc LateContext<'tcx>, - seen_types: &'others mut FxHashSet>, type_cache: &'others mut FxHashMap, bool>, } @@ -222,15 +214,9 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx fn new( ap: &'ap mut AuxParams<'others, 'stmt, 'tcx>, cx: &'lc LateContext<'tcx>, - seen_types: &'others mut FxHashSet>, type_cache: &'others mut FxHashMap, bool>, ) -> Self { - Self { - ap, - cx, - seen_types, - type_cache, - } + Self { ap, cx, type_cache } } fn manage_has_expensive_expr_after_last_attr(&mut self) { @@ -288,7 +274,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o apa.counter = apa.counter.wrapping_add(1); apa.has_expensive_expr_after_last_attr = false; }; - let mut ac = AttrChecker::new(self.cx, self.seen_types, self.type_cache); + let mut ac = AttrChecker::new(self.cx, self.type_cache); if ac.has_sig_drop_attr(self.cx.typeck_results().expr_ty(expr)) { if let hir::StmtKind::Let(local) = self.ap.curr_stmt.kind && let hir::PatKind::Binding(_, hir_id, ident, _) = local.pat.kind -- cgit 1.4.1-3-g733a5 From 2855a876a76e52cee0db2df0488f22b10e228d0f Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 26 May 2024 10:50:30 +0700 Subject: fix typos of author lint --- clippy_lints/src/utils/author.rs | 2 +- tests/ui/author.stdout | 2 +- tests/ui/author/blocks.stdout | 6 +++--- tests/ui/author/call.stdout | 2 +- tests/ui/author/if.stdout | 2 +- tests/ui/author/issue_3849.stdout | 2 +- tests/ui/author/loop.stdout | 2 +- tests/ui/author/macro_in_closure.stdout | 2 +- tests/ui/author/matches.stdout | 4 ++-- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 4448c9ae3df..a3339cc62a9 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -733,7 +733,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { match stmt.value.kind { StmtKind::Let(local) => { bind!(self, local); - kind!("Local({local})"); + kind!("Let({local})"); self.option(field!(local.init), "init", |init| { self.expr(init); }); diff --git a/tests/ui/author.stdout b/tests/ui/author.stdout index d448db097a7..eed704e82fe 100644 --- a/tests/ui/author.stdout +++ b/tests/ui/author.stdout @@ -1,4 +1,4 @@ -if let StmtKind::Local(local) = stmt.kind +if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Cast(expr, cast_ty) = init.kind && let TyKind::Path(ref qpath) = cast_ty.kind diff --git a/tests/ui/author/blocks.stdout b/tests/ui/author/blocks.stdout index 80b928dd6cb..6bf48d5ba4e 100644 --- a/tests/ui/author/blocks.stdout +++ b/tests/ui/author/blocks.stdout @@ -1,12 +1,12 @@ if let ExprKind::Block(block, None) = expr.kind && block.stmts.len() == 3 - && let StmtKind::Local(local) = block.stmts[0].kind + && let StmtKind::Let(local) = block.stmts[0].kind && let Some(init) = local.init && let ExprKind::Lit(ref lit) = init.kind && let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind && name.as_str() == "x" - && let StmtKind::Local(local1) = block.stmts[1].kind + && let StmtKind::Let(local1) = block.stmts[1].kind && let Some(init1) = local1.init && let ExprKind::Lit(ref lit1) = init1.kind && let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node @@ -22,7 +22,7 @@ if let ExprKind::Block(block, None) = expr.kind } if let ExprKind::Block(block, None) = expr.kind && block.stmts.len() == 1 - && let StmtKind::Local(local) = block.stmts[0].kind + && let StmtKind::Let(local) = block.stmts[0].kind && let Some(init) = local.init && let ExprKind::Call(func, args) = init.kind && let ExprKind::Path(ref qpath) = func.kind diff --git a/tests/ui/author/call.stdout b/tests/ui/author/call.stdout index f040f6330a6..59d4da490fe 100644 --- a/tests/ui/author/call.stdout +++ b/tests/ui/author/call.stdout @@ -1,4 +1,4 @@ -if let StmtKind::Local(local) = stmt.kind +if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Call(func, args) = init.kind && let ExprKind::Path(ref qpath) = func.kind diff --git a/tests/ui/author/if.stdout b/tests/ui/author/if.stdout index 5d79618820d..a85dcddd331 100644 --- a/tests/ui/author/if.stdout +++ b/tests/ui/author/if.stdout @@ -1,4 +1,4 @@ -if let StmtKind::Local(local) = stmt.kind +if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::If(cond, then, Some(else_expr)) = init.kind && let ExprKind::DropTemps(expr) = cond.kind diff --git a/tests/ui/author/issue_3849.stdout b/tests/ui/author/issue_3849.stdout index 32a3127b85a..a5a8c0304ee 100644 --- a/tests/ui/author/issue_3849.stdout +++ b/tests/ui/author/issue_3849.stdout @@ -1,4 +1,4 @@ -if let StmtKind::Local(local) = stmt.kind +if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Call(func, args) = init.kind && let ExprKind::Path(ref qpath) = func.kind diff --git a/tests/ui/author/loop.stdout b/tests/ui/author/loop.stdout index 631105a2238..609d2491061 100644 --- a/tests/ui/author/loop.stdout +++ b/tests/ui/author/loop.stdout @@ -12,7 +12,7 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node && let ExprKind::Block(block, None) = body.kind && block.stmts.len() == 1 - && let StmtKind::Local(local) = block.stmts[0].kind + && let StmtKind::Let(local) = block.stmts[0].kind && let Some(init) = local.init && let ExprKind::Path(ref qpath1) = init.kind && match_qpath(qpath1, &["y"]) diff --git a/tests/ui/author/macro_in_closure.stdout b/tests/ui/author/macro_in_closure.stdout index b90c830e030..66caf382d89 100644 --- a/tests/ui/author/macro_in_closure.stdout +++ b/tests/ui/author/macro_in_closure.stdout @@ -1,4 +1,4 @@ -if let StmtKind::Local(local) = stmt.kind +if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Closure { capture_clause: CaptureBy::Ref, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = init.kind && let FnRetTy::DefaultReturn(_) = fn_decl.output diff --git a/tests/ui/author/matches.stdout b/tests/ui/author/matches.stdout index 30e4a9b2560..91b3b6f6877 100644 --- a/tests/ui/author/matches.stdout +++ b/tests/ui/author/matches.stdout @@ -1,4 +1,4 @@ -if let StmtKind::Local(local) = stmt.kind +if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Match(scrutinee, arms, MatchSource::Normal) = init.kind && let ExprKind::Lit(ref lit) = scrutinee.kind @@ -16,7 +16,7 @@ if let StmtKind::Local(local) = stmt.kind && arms[1].guard.is_none() && let ExprKind::Block(block, None) = arms[1].body.kind && block.stmts.len() == 1 - && let StmtKind::Local(local1) = block.stmts[0].kind + && let StmtKind::Let(local1) = block.stmts[0].kind && let Some(init1) = local1.init && let ExprKind::Lit(ref lit4) = init1.kind && let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node -- cgit 1.4.1-3-g733a5 From 5acc25e700363b4c3e5cddf5a32dfc5b4f28135c Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sat, 8 Jun 2024 20:18:31 +0100 Subject: Update `icu4x` dependencies --- tests/ui/unicode.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/unicode.stderr b/tests/ui/unicode.stderr index 9c365e1097d..b004493300e 100644 --- a/tests/ui/unicode.stderr +++ b/tests/ui/unicode.stderr @@ -11,7 +11,7 @@ error: invisible character detected --> tests/ui/unicode.rs:7:12 | LL | print!("Here >­< is a SHY, and ­another"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >\u{AD}< is a SHY, and \u{AD}another"` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >\u{AD}< is a SHY, and \u{AD}another"` error: invisible character detected --> tests/ui/unicode.rs:9:12 -- cgit 1.4.1-3-g733a5 From 36e1414b10af7ca487d6f84165e1f23a80375fd4 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 20 May 2024 17:53:07 +0000 Subject: add codegen test for #120440 --- tests/codegen/slice-pointer-nonnull-unwrap.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/codegen/slice-pointer-nonnull-unwrap.rs diff --git a/tests/codegen/slice-pointer-nonnull-unwrap.rs b/tests/codegen/slice-pointer-nonnull-unwrap.rs new file mode 100644 index 00000000000..51ea4a1f943 --- /dev/null +++ b/tests/codegen/slice-pointer-nonnull-unwrap.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -O +//@ min-llvm-version: 18 +#![crate_type = "lib"] + +use std::ptr::NonNull; + +// CHECK-LABEL: @slice_ptr_len_1 +// CHECK: {{.*}}: +// CHECK-NEXT: ret i64 %ptr.1 +#[no_mangle] +pub fn slice_ptr_len_1(ptr: *const [u8]) -> usize { + let ptr = ptr.cast_mut(); + if let Some(ptr) = NonNull::new(ptr) { + ptr.len() + } else { + // We know ptr is null, so we know ptr.wrapping_byte_add(1) is not null. + NonNull::new(ptr.wrapping_byte_add(1)).unwrap().len() + } +} -- cgit 1.4.1-3-g733a5 From f3c89f1751217f8ad2267d5acaed9b665392e9cc Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 20 May 2024 18:17:42 +0000 Subject: add codegen test for issue-118392, 71096 --- tests/codegen/issues/issue-118392.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/codegen/issues/issue-118392.rs diff --git a/tests/codegen/issues/issue-118392.rs b/tests/codegen/issues/issue-118392.rs new file mode 100644 index 00000000000..2cbb1f8b204 --- /dev/null +++ b/tests/codegen/issues/issue-118392.rs @@ -0,0 +1,11 @@ +//@ compile-flags: -O +//@ min-llvm-version: 18 +#![crate_type = "lib"] + +// CHECK-LABEL: @div2 +// CHECK: ashr i32 %a, 1 +// CHECK-NEXT: ret i32 +#[no_mangle] +pub fn div2(a: i32) -> i32 { + a.div_euclid(2) +} -- cgit 1.4.1-3-g733a5 From f37c576dbd350adf0644ca9a2b83e28d9d57a076 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 20 May 2024 18:18:52 +0000 Subject: add codegen test for #113757 --- .../issues/issue-113757-bounds-check-after-cmp-max.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs diff --git a/tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs b/tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs new file mode 100644 index 00000000000..5dedefc43d1 --- /dev/null +++ b/tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs @@ -0,0 +1,19 @@ +// in Rust 1.73, -O and opt-level=3 optimizes differently +//@ compile-flags: -C opt-level=3 +//@ min-llvm-version: 17 +#![crate_type = "lib"] + +use std::cmp::max; + +#[no_mangle] +// CHECK-LABEL: @foo +// CHECK-NOT: slice_start_index_len_fail +// CHECK-NOT: unreachable +pub fn foo(v: &mut Vec, size: usize)-> Option<&mut [u8]> { + if v.len() > max(1, size) { + let start = v.len() - size; + Some(&mut v[start..]) + } else { + None + } +} -- cgit 1.4.1-3-g733a5 From beabc5647bc81d62cebbe1d4a71a3666f8ade9d7 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 20 May 2024 18:38:45 +0000 Subject: add codegen test for #112509 --- .../issues/issue-112509-slice-get-andthen-get.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/codegen/issues/issue-112509-slice-get-andthen-get.rs diff --git a/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs b/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs new file mode 100644 index 00000000000..fc04a6cc41a --- /dev/null +++ b/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -O +//@ min-llvm-version: 17 +#![crate_type = "lib"] + +// CHECK-LABEL: @write_u8_variant_a +// CHECK: getelementptr +// CHECK-NEXT: icmp ugt +#[no_mangle] +pub fn write_u8_variant_a( + bytes: &mut [u8], + buf: u8, + offset: usize, +) -> Option<&mut [u8]> { + let buf = buf.to_le_bytes(); + bytes + .get_mut(offset..).and_then(|bytes| bytes.get_mut(..buf.len())) +} -- cgit 1.4.1-3-g733a5 From 15d07fb2cbb48ba85d69aa043c1d77909a565ea8 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 20 May 2024 19:22:49 +0000 Subject: Add codegen test for #111508 --- .../issues/issue-111508-vec-tryinto-array.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/codegen/issues/issue-111508-vec-tryinto-array.rs diff --git a/tests/codegen/issues/issue-111508-vec-tryinto-array.rs b/tests/codegen/issues/issue-111508-vec-tryinto-array.rs new file mode 100644 index 00000000000..2e7244e9713 --- /dev/null +++ b/tests/codegen/issues/issue-111508-vec-tryinto-array.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -O +// This regress since Rust version 1.72. +//@ min-llvm-version: 18.1.4 + +#![crate_type = "lib"] + +use std::convert::TryInto; + +const N: usize = 24; + +#[no_mangle] +// CHECK-LABEL: @example +// CHECK-NOT: unwrap_failed +pub fn example(a: Vec) -> u8 { + if a.len() != 32 { + return 0; + } + + let a: [u8; 32] = a.try_into().unwrap(); + + a[15] + a[N] +} -- cgit 1.4.1-3-g733a5 From ddb94dbd16760d6de5e3a9cbbffb66e161691786 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 20 May 2024 19:40:50 +0000 Subject: add codegen test for #110797 --- .../codegen/issues/issue-110797-enum-jump-same.rs | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/codegen/issues/issue-110797-enum-jump-same.rs diff --git a/tests/codegen/issues/issue-110797-enum-jump-same.rs b/tests/codegen/issues/issue-110797-enum-jump-same.rs new file mode 100644 index 00000000000..bfd10c0a582 --- /dev/null +++ b/tests/codegen/issues/issue-110797-enum-jump-same.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -O +// XXX: The x86-64 assembly get optimized correclty. But llvm-ir output is not until llvm 18? +//@ min-llvm-version: 18 + +#![crate_type = "lib"] + +pub enum K{ + A(Box<[i32]>), + B(Box<[u8]>), + C(Box<[String]>), + D(Box<[u16]>), +} + +#[no_mangle] +// CHECK-LABEL: @get_len +// CHECK: getelementptr inbounds +// CHECK-NEXT: load +// CHECK-NEXT: ret i64 +// CHECK-NOT: switch +pub fn get_len(arg: &K)->usize{ + match arg { + K::A(ref lst)=>lst.len(), + K::B(ref lst)=>lst.len(), + K::C(ref lst)=>lst.len(), + K::D(ref lst)=>lst.len(), + } +} -- cgit 1.4.1-3-g733a5 From 7d967ffa8df2ae74e4cff5d5ed7b53adedac00a2 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 20 May 2024 19:52:30 +0000 Subject: add codegen test for #109328 --- tests/codegen/issues/issue-109328-split_first.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/codegen/issues/issue-109328-split_first.rs diff --git a/tests/codegen/issues/issue-109328-split_first.rs b/tests/codegen/issues/issue-109328-split_first.rs new file mode 100644 index 00000000000..a43e653e1a2 --- /dev/null +++ b/tests/codegen/issues/issue-109328-split_first.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -O +//@ min-llvm-version: 17 + +#![crate_type = "lib"] + +#[no_mangle] +// CHECK-LABEL: @foo +// CHECK: getelementptr inbounds +// CHECK-NEXT: load i64 +// CHECK-NEXT: icmp eq i64 +// CHECK-NEXT: br i1 +#[no_mangle] +pub fn foo(input: &mut &[u64]) -> Option { + let (first, rest) = input.split_first()?; + *input = rest; + Some(*first) +} -- cgit 1.4.1-3-g733a5 From 8bd6c04cfc41e9952408fb8bed2db9c7e12a0ee6 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 20 May 2024 20:15:31 +0000 Subject: add codegen test for #93036 --- tests/codegen/issues/issue-93036-assert-index.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/codegen/issues/issue-93036-assert-index.rs diff --git a/tests/codegen/issues/issue-93036-assert-index.rs b/tests/codegen/issues/issue-93036-assert-index.rs new file mode 100644 index 00000000000..9e4437cc656 --- /dev/null +++ b/tests/codegen/issues/issue-93036-assert-index.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -O +//@ min-llvm-version: 17 + +#![crate_type = "lib"] + +#[no_mangle] +// CHECK-LABEL: @foo +// CHECK: {{.*}}: +// CHECK: ret +// CHECK-NOT: unreachable +pub fn foo(arr: &mut [u32]) { + for i in 0..arr.len() { + for j in 0..i { + assert!(j < arr.len()); + } + } +} + -- cgit 1.4.1-3-g733a5 From 2120ea5a913e6a0ea4137c43471f4d060629c6a8 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 20 May 2024 20:39:26 +0000 Subject: add assembly test for #83585 --- .../issue-83585-small-pod-struct-equality.rs | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/assembly/issue-83585-small-pod-struct-equality.rs diff --git a/tests/assembly/issue-83585-small-pod-struct-equality.rs b/tests/assembly/issue-83585-small-pod-struct-equality.rs new file mode 100644 index 00000000000..56d458d8514 --- /dev/null +++ b/tests/assembly/issue-83585-small-pod-struct-equality.rs @@ -0,0 +1,30 @@ +//@ assembly-output: emit-asm +//@ compile-flags:-Copt-level=3 +//@ only-x86_64 + +#![crate_type = "lib"] + +#[no_mangle] +type T = u8; +type T1 = (T, T, T, T, T, T, T, T); +type T2 = [T; 8]; + +#[no_mangle] +// CHECK-LABEL: foo1a +// CHECK: cmp +// CHECK-NEXT: set +// CHECK-NEXT: ret +pub fn foo1a(a: T1, b: T1) -> bool { + a == b +} + +#[no_mangle] +// CHECK-LABEL: foo1b +// CHECK: mov +// CHECK-NEXT: cmp +// CHECK-NEXT: set +// CHECK-NEXT: ret +pub fn foo1b(a: &T1, b: &T1) -> bool { + a == b +} + -- cgit 1.4.1-3-g733a5 From bf178187c7d7f671d233b012e6ebcd53e3d60a62 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 20 May 2024 21:20:33 +0000 Subject: add codegen test for #74938 --- tests/codegen/issues/issue-74938-array-split-at.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/codegen/issues/issue-74938-array-split-at.rs diff --git a/tests/codegen/issues/issue-74938-array-split-at.rs b/tests/codegen/issues/issue-74938-array-split-at.rs new file mode 100644 index 00000000000..1f8aa3868d7 --- /dev/null +++ b/tests/codegen/issues/issue-74938-array-split-at.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -O + +#![crate_type = "lib"] + +const N: usize = 3; +pub type T = u8; + +#[no_mangle] +// CHECK-LABEL: @split_mutiple +// CHECK-NOT: unreachable +pub fn split_mutiple(slice: &[T]) -> (&[T], &[T]) { + let len = slice.len() / N; + slice.split_at(len * N) +} + -- cgit 1.4.1-3-g733a5 From 5f527eb562ff670cf9545817575ff6a7f6088bc7 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 20 May 2024 21:33:53 +0000 Subject: add codegen test for #68667 --- tests/codegen/issues/issue-68667-unwrap-combinators.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/codegen/issues/issue-68667-unwrap-combinators.rs diff --git a/tests/codegen/issues/issue-68667-unwrap-combinators.rs b/tests/codegen/issues/issue-68667-unwrap-combinators.rs new file mode 100644 index 00000000000..05760dc9b55 --- /dev/null +++ b/tests/codegen/issues/issue-68667-unwrap-combinators.rs @@ -0,0 +1,17 @@ +#![crate_type = "lib"] + +//@ compile-flags: -O + +// MIR inlining now optimizes this code. + +// CHECK-LABEL: @unwrap_combinators +// CHECK: icmp +// CHECK-NEXT: icmp +// CHECK-NEXT: select i1 +// CHECK-NEXT: ret i1 +#[no_mangle] +pub fn unwrap_combinators(a: Option, b: i32) -> bool { + a.map(|t| t >= b) + .unwrap_or(false) +} + -- cgit 1.4.1-3-g733a5 From 95740fbfeddbc3e09a0a94cde4c3694cd5af17db Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 20 May 2024 21:50:31 +0000 Subject: add codegen test for #36010 --- .../codegen/issues/issue-36010-some-box-is_some.rs | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/codegen/issues/issue-36010-some-box-is_some.rs diff --git a/tests/codegen/issues/issue-36010-some-box-is_some.rs b/tests/codegen/issues/issue-36010-some-box-is_some.rs new file mode 100644 index 00000000000..b7179987e7d --- /dev/null +++ b/tests/codegen/issues/issue-36010-some-box-is_some.rs @@ -0,0 +1,29 @@ +#![crate_type = "lib"] + +//@ compile-flags: -O + +use std::mem; + +fn foo(a: &mut T, b: T) -> bool { + let b = Some(mem::replace(a, b)); + let ret = b.is_some(); + mem::forget(b); + return ret +} + +// CHECK-LABEL: @foo_u32 +// CHECK: store i32 +// CHECK-NEXT: ret i1 +#[no_mangle] +pub fn foo_u32(a: &mut u32, b: u32) -> bool { + foo(a, b) +} + +// CHECK-LABEL: @foo_box +// CHECK: store ptr +// CHECK-NEXT: ret i1 +#[no_mangle] +pub fn foo_box(a: &mut Box, b: Box) -> bool { + foo(a, b) +} + -- cgit 1.4.1-3-g733a5 From 3f9c5872b9307b7674555a97493dc5223724a184 Mon Sep 17 00:00:00 2001 From: alexey semenyuk Date: Sun, 9 Jun 2024 17:37:05 +0500 Subject: Filter from first typed symbol --- util/gh-pages/script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 7fd779fe9a4..7cca298df8e 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -397,7 +397,7 @@ $scope.bySearch = function (lint, index, array) { let searchStr = $scope.search; // It can be `null` I haven't missed this value - if (searchStr == null || searchStr.length < 3) { + if (searchStr == null) { return true; } searchStr = searchStr.toLowerCase(); -- cgit 1.4.1-3-g733a5 From f9edd864df9f85a9a6a2969fa74e0966f6565c36 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 9 Jun 2024 13:25:12 +0000 Subject: Apply suggestions from code review Co-authored-by: Nikita Popov --- .../assembly/issue-83585-small-pod-struct-equality.rs | 10 ++++------ tests/codegen/issues/issue-109328-split_first.rs | 5 ++--- tests/codegen/issues/issue-110797-enum-jump-same.rs | 19 +++++++++---------- .../codegen/issues/issue-111508-vec-tryinto-array.rs | 2 +- .../issues/issue-112509-slice-get-andthen-get.rs | 13 ++++--------- .../issues/issue-113757-bounds-check-after-cmp-max.rs | 5 ++--- tests/codegen/issues/issue-36010-some-box-is_some.rs | 7 +++---- .../codegen/issues/issue-68667-unwrap-combinators.rs | 4 +--- tests/codegen/issues/issue-74938-array-split-at.rs | 7 +++---- tests/codegen/issues/issue-93036-assert-index.rs | 4 ---- tests/codegen/slice-pointer-nonnull-unwrap.rs | 16 ++++++++-------- 11 files changed, 37 insertions(+), 55 deletions(-) diff --git a/tests/assembly/issue-83585-small-pod-struct-equality.rs b/tests/assembly/issue-83585-small-pod-struct-equality.rs index 56d458d8514..9b0d605666d 100644 --- a/tests/assembly/issue-83585-small-pod-struct-equality.rs +++ b/tests/assembly/issue-83585-small-pod-struct-equality.rs @@ -4,27 +4,25 @@ #![crate_type = "lib"] -#[no_mangle] type T = u8; type T1 = (T, T, T, T, T, T, T, T); type T2 = [T; 8]; -#[no_mangle] // CHECK-LABEL: foo1a // CHECK: cmp -// CHECK-NEXT: set +// CHECK-NEXT: sete // CHECK-NEXT: ret +#[no_mangle] pub fn foo1a(a: T1, b: T1) -> bool { a == b } -#[no_mangle] // CHECK-LABEL: foo1b // CHECK: mov // CHECK-NEXT: cmp -// CHECK-NEXT: set +// CHECK-NEXT: sete // CHECK-NEXT: ret +#[no_mangle] pub fn foo1b(a: &T1, b: &T1) -> bool { a == b } - diff --git a/tests/codegen/issues/issue-109328-split_first.rs b/tests/codegen/issues/issue-109328-split_first.rs index a43e653e1a2..d3844c3ec20 100644 --- a/tests/codegen/issues/issue-109328-split_first.rs +++ b/tests/codegen/issues/issue-109328-split_first.rs @@ -1,11 +1,10 @@ //@ compile-flags: -O -//@ min-llvm-version: 17 #![crate_type = "lib"] -#[no_mangle] // CHECK-LABEL: @foo -// CHECK: getelementptr inbounds +// CHECK-NEXT: {{.*}}: +// CHECK-NEXT: getelementptr inbounds // CHECK-NEXT: load i64 // CHECK-NEXT: icmp eq i64 // CHECK-NEXT: br i1 diff --git a/tests/codegen/issues/issue-110797-enum-jump-same.rs b/tests/codegen/issues/issue-110797-enum-jump-same.rs index bfd10c0a582..d52faef23ad 100644 --- a/tests/codegen/issues/issue-110797-enum-jump-same.rs +++ b/tests/codegen/issues/issue-110797-enum-jump-same.rs @@ -1,27 +1,26 @@ //@ compile-flags: -O -// XXX: The x86-64 assembly get optimized correclty. But llvm-ir output is not until llvm 18? //@ min-llvm-version: 18 #![crate_type = "lib"] -pub enum K{ +pub enum K { A(Box<[i32]>), B(Box<[u8]>), C(Box<[String]>), D(Box<[u16]>), } -#[no_mangle] // CHECK-LABEL: @get_len -// CHECK: getelementptr inbounds +// CHECK-NEXT: {{.*}}: +// CHECK-NEXT: getelementptr inbounds // CHECK-NEXT: load // CHECK-NEXT: ret i64 -// CHECK-NOT: switch -pub fn get_len(arg: &K)->usize{ +#[no_mangle] +pub fn get_len(arg: &K) -> usize { match arg { - K::A(ref lst)=>lst.len(), - K::B(ref lst)=>lst.len(), - K::C(ref lst)=>lst.len(), - K::D(ref lst)=>lst.len(), + K::A(ref lst) => lst.len(), + K::B(ref lst) => lst.len(), + K::C(ref lst) => lst.len(), + K::D(ref lst) => lst.len(), } } diff --git a/tests/codegen/issues/issue-111508-vec-tryinto-array.rs b/tests/codegen/issues/issue-111508-vec-tryinto-array.rs index 2e7244e9713..6415724b40a 100644 --- a/tests/codegen/issues/issue-111508-vec-tryinto-array.rs +++ b/tests/codegen/issues/issue-111508-vec-tryinto-array.rs @@ -8,9 +8,9 @@ use std::convert::TryInto; const N: usize = 24; -#[no_mangle] // CHECK-LABEL: @example // CHECK-NOT: unwrap_failed +#[no_mangle] pub fn example(a: Vec) -> u8 { if a.len() != 32 { return 0; diff --git a/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs b/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs index fc04a6cc41a..ae02c3fb79e 100644 --- a/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs +++ b/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs @@ -1,17 +1,12 @@ //@ compile-flags: -O -//@ min-llvm-version: 17 #![crate_type = "lib"] // CHECK-LABEL: @write_u8_variant_a -// CHECK: getelementptr +// CHECK-NEXT: {{.*}}: +// CHECK-NEXT: getelementptr // CHECK-NEXT: icmp ugt #[no_mangle] -pub fn write_u8_variant_a( - bytes: &mut [u8], - buf: u8, - offset: usize, -) -> Option<&mut [u8]> { +pub fn write_u8_variant_a(bytes: &mut [u8], buf: u8, offset: usize) -> Option<&mut [u8]> { let buf = buf.to_le_bytes(); - bytes - .get_mut(offset..).and_then(|bytes| bytes.get_mut(..buf.len())) + bytes.get_mut(offset..).and_then(|bytes| bytes.get_mut(..buf.len())) } diff --git a/tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs b/tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs index 5dedefc43d1..d495adf9980 100644 --- a/tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs +++ b/tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs @@ -1,15 +1,14 @@ // in Rust 1.73, -O and opt-level=3 optimizes differently //@ compile-flags: -C opt-level=3 -//@ min-llvm-version: 17 #![crate_type = "lib"] use std::cmp::max; -#[no_mangle] // CHECK-LABEL: @foo // CHECK-NOT: slice_start_index_len_fail // CHECK-NOT: unreachable -pub fn foo(v: &mut Vec, size: usize)-> Option<&mut [u8]> { +#[no_mangle] +pub fn foo(v: &mut Vec, size: usize) -> Option<&mut [u8]> { if v.len() > max(1, size) { let start = v.len() - size; Some(&mut v[start..]) diff --git a/tests/codegen/issues/issue-36010-some-box-is_some.rs b/tests/codegen/issues/issue-36010-some-box-is_some.rs index b7179987e7d..44c01096f15 100644 --- a/tests/codegen/issues/issue-36010-some-box-is_some.rs +++ b/tests/codegen/issues/issue-36010-some-box-is_some.rs @@ -8,12 +8,12 @@ fn foo(a: &mut T, b: T) -> bool { let b = Some(mem::replace(a, b)); let ret = b.is_some(); mem::forget(b); - return ret + return ret; } // CHECK-LABEL: @foo_u32 // CHECK: store i32 -// CHECK-NEXT: ret i1 +// CHECK-NEXT: ret i1 true #[no_mangle] pub fn foo_u32(a: &mut u32, b: u32) -> bool { foo(a, b) @@ -21,9 +21,8 @@ pub fn foo_u32(a: &mut u32, b: u32) -> bool { // CHECK-LABEL: @foo_box // CHECK: store ptr -// CHECK-NEXT: ret i1 +// CHECK-NEXT: ret i1 true #[no_mangle] pub fn foo_box(a: &mut Box, b: Box) -> bool { foo(a, b) } - diff --git a/tests/codegen/issues/issue-68667-unwrap-combinators.rs b/tests/codegen/issues/issue-68667-unwrap-combinators.rs index 05760dc9b55..6bd4c566a0c 100644 --- a/tests/codegen/issues/issue-68667-unwrap-combinators.rs +++ b/tests/codegen/issues/issue-68667-unwrap-combinators.rs @@ -11,7 +11,5 @@ // CHECK-NEXT: ret i1 #[no_mangle] pub fn unwrap_combinators(a: Option, b: i32) -> bool { - a.map(|t| t >= b) - .unwrap_or(false) + a.map(|t| t >= b).unwrap_or(false) } - diff --git a/tests/codegen/issues/issue-74938-array-split-at.rs b/tests/codegen/issues/issue-74938-array-split-at.rs index 1f8aa3868d7..2675e404ced 100644 --- a/tests/codegen/issues/issue-74938-array-split-at.rs +++ b/tests/codegen/issues/issue-74938-array-split-at.rs @@ -5,11 +5,10 @@ const N: usize = 3; pub type T = u8; -#[no_mangle] -// CHECK-LABEL: @split_mutiple +// CHECK-LABEL: @split_multiple // CHECK-NOT: unreachable -pub fn split_mutiple(slice: &[T]) -> (&[T], &[T]) { +#[no_mangle] +pub fn split_multiple(slice: &[T]) -> (&[T], &[T]) { let len = slice.len() / N; slice.split_at(len * N) } - diff --git a/tests/codegen/issues/issue-93036-assert-index.rs b/tests/codegen/issues/issue-93036-assert-index.rs index 9e4437cc656..7a2ea087266 100644 --- a/tests/codegen/issues/issue-93036-assert-index.rs +++ b/tests/codegen/issues/issue-93036-assert-index.rs @@ -1,12 +1,9 @@ //@ compile-flags: -O -//@ min-llvm-version: 17 #![crate_type = "lib"] #[no_mangle] // CHECK-LABEL: @foo -// CHECK: {{.*}}: -// CHECK: ret // CHECK-NOT: unreachable pub fn foo(arr: &mut [u32]) { for i in 0..arr.len() { @@ -15,4 +12,3 @@ pub fn foo(arr: &mut [u32]) { } } } - diff --git a/tests/codegen/slice-pointer-nonnull-unwrap.rs b/tests/codegen/slice-pointer-nonnull-unwrap.rs index 51ea4a1f943..48bf8fa88a0 100644 --- a/tests/codegen/slice-pointer-nonnull-unwrap.rs +++ b/tests/codegen/slice-pointer-nonnull-unwrap.rs @@ -5,15 +5,15 @@ use std::ptr::NonNull; // CHECK-LABEL: @slice_ptr_len_1 -// CHECK: {{.*}}: +// CHECK-NEXT: {{.*}}: // CHECK-NEXT: ret i64 %ptr.1 #[no_mangle] pub fn slice_ptr_len_1(ptr: *const [u8]) -> usize { - let ptr = ptr.cast_mut(); - if let Some(ptr) = NonNull::new(ptr) { - ptr.len() - } else { - // We know ptr is null, so we know ptr.wrapping_byte_add(1) is not null. - NonNull::new(ptr.wrapping_byte_add(1)).unwrap().len() - } + let ptr = ptr.cast_mut(); + if let Some(ptr) = NonNull::new(ptr) { + ptr.len() + } else { + // We know ptr is null, so we know ptr.wrapping_byte_add(1) is not null. + NonNull::new(ptr.wrapping_byte_add(1)).unwrap().len() + } } -- cgit 1.4.1-3-g733a5 From 55344c84a59412afeb6965945e24cbae7389ecab Mon Sep 17 00:00:00 2001 From: Artem Belyakov Date: Sun, 9 Jun 2024 21:01:00 +0300 Subject: Handle single chars with `to_string()` for `single_char_add_str` --- .../src/methods/single_char_insert_string.rs | 42 +++++++++++++++- .../src/methods/single_char_push_string.rs | 41 ++++++++++++++- tests/ui/single_char_add_str.fixed | 10 ++++ tests/ui/single_char_add_str.rs | 10 ++++ tests/ui/single_char_add_str.stderr | 58 ++++++++++++++++++---- 5 files changed, 148 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index 20ec2b74d81..f2af793a869 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -1,8 +1,9 @@ use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use rustc_ast::BorrowKind; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::{self as hir, ExprKind}; use rustc_lint::LateContext; use super::SINGLE_CHAR_ADD_STR; @@ -25,4 +26,43 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: applicability, ); } + + if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[1].kind + && let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind + && path_segment.ident.as_str() == "to_string" + && (is_ref_char(cx, method_arg) || is_char(cx, method_arg)) + { + let base_string_snippet = + snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); + let extension_string = + snippet_with_applicability(cx, method_arg.span.source_callsite(), "..", &mut applicability); + let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); + let deref_string = if is_ref_char(cx, method_arg) { "*" } else { "" }; + + let sugg = format!("{base_string_snippet}.insert({pos_arg}, {deref_string}{extension_string})"); + span_lint_and_sugg( + cx, + SINGLE_CHAR_ADD_STR, + expr.span, + "calling `insert_str()` using a single-character converted to string", + "consider using `insert` without `to_string()`", + sugg, + applicability, + ); + } +} + +fn is_ref_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + if cx.typeck_results().expr_ty(expr).is_ref() + && let rustc_middle::ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(expr).kind() + && ty.is_char() + { + return true; + } + + false +} + +fn is_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + cx.typeck_results().expr_ty(expr).is_char() } diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index 97c13825bc1..8c6e490a38f 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -1,8 +1,9 @@ use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use rustc_ast::BorrowKind; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::{self as hir, ExprKind}; use rustc_lint::LateContext; use super::SINGLE_CHAR_ADD_STR; @@ -24,4 +25,42 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: applicability, ); } + + if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[0].kind + && let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind + && path_segment.ident.as_str() == "to_string" + && (is_ref_char(cx, method_arg) || is_char(cx, method_arg)) + { + let base_string_snippet = + snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); + let extension_string = + snippet_with_applicability(cx, method_arg.span.source_callsite(), "..", &mut applicability); + let deref_string = if is_ref_char(cx, method_arg) { "*" } else { "" }; + + let sugg = format!("{base_string_snippet}.push({deref_string}{extension_string})"); + span_lint_and_sugg( + cx, + SINGLE_CHAR_ADD_STR, + expr.span, + "calling `push_str()` using a single-character converted to string", + "consider using `push` without `to_string()`", + sugg, + applicability, + ); + } +} + +fn is_ref_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + if cx.typeck_results().expr_ty(expr).is_ref() + && let rustc_middle::ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(expr).kind() + && ty.is_char() + { + return true; + } + + false +} + +fn is_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + cx.typeck_results().expr_ty(expr).is_char() } diff --git a/tests/ui/single_char_add_str.fixed b/tests/ui/single_char_add_str.fixed index eafd17f5387..aef15252b1b 100644 --- a/tests/ui/single_char_add_str.fixed +++ b/tests/ui/single_char_add_str.fixed @@ -21,6 +21,12 @@ fn main() { string.push('\u{0052}'); string.push('a'); + let c_ref = &'a'; + string.push(*c_ref); + let c = 'a'; + string.push(c); + string.push('a'); + get_string!().push('ö'); // `insert_str` tests @@ -41,5 +47,9 @@ fn main() { string.insert(Y, '"'); string.insert(Y, '\''); + string.insert(0, *c_ref); + string.insert(0, c); + string.insert(0, 'a'); + get_string!().insert(1, '?'); } diff --git a/tests/ui/single_char_add_str.rs b/tests/ui/single_char_add_str.rs index 5326c7cf24c..7f97250dacd 100644 --- a/tests/ui/single_char_add_str.rs +++ b/tests/ui/single_char_add_str.rs @@ -21,6 +21,12 @@ fn main() { string.push_str("\u{0052}"); string.push_str(r##"a"##); + let c_ref = &'a'; + string.push_str(&c_ref.to_string()); + let c = 'a'; + string.push_str(&c.to_string()); + string.push_str(&'a'.to_string()); + get_string!().push_str("ö"); // `insert_str` tests @@ -41,5 +47,9 @@ fn main() { string.insert_str(Y, r##"""##); string.insert_str(Y, r##"'"##); + string.insert_str(0, &c_ref.to_string()); + string.insert_str(0, &c.to_string()); + string.insert_str(0, &'a'.to_string()); + get_string!().insert_str(1, "?"); } diff --git a/tests/ui/single_char_add_str.stderr b/tests/ui/single_char_add_str.stderr index 89d75f20f55..7791c67578a 100644 --- a/tests/ui/single_char_add_str.stderr +++ b/tests/ui/single_char_add_str.stderr @@ -31,65 +31,101 @@ error: calling `push_str()` using a single-character string literal LL | string.push_str(r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')` +error: calling `push_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:25:5 + | +LL | string.push_str(&c_ref.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push(*c_ref)` + +error: calling `push_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:27:5 + | +LL | string.push_str(&c.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push(c)` + +error: calling `push_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:28:5 + | +LL | string.push_str(&'a'.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push('a')` + error: calling `push_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:24:5 + --> tests/ui/single_char_add_str.rs:30:5 | LL | get_string!().push_str("ö"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `get_string!().push('ö')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:29:5 + --> tests/ui/single_char_add_str.rs:35:5 | LL | string.insert_str(0, "R"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:30:5 + --> tests/ui/single_char_add_str.rs:36:5 | LL | string.insert_str(1, "'"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '\'')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:35:5 + --> tests/ui/single_char_add_str.rs:41:5 | LL | string.insert_str(0, "\x52"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '\x52')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:36:5 + --> tests/ui/single_char_add_str.rs:42:5 | LL | string.insert_str(0, "\u{0052}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '\u{0052}')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:38:5 + --> tests/ui/single_char_add_str.rs:44:5 | LL | string.insert_str(x, r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:40:5 + --> tests/ui/single_char_add_str.rs:46:5 | LL | string.insert_str(Y, r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:41:5 + --> tests/ui/single_char_add_str.rs:47:5 | LL | string.insert_str(Y, r##"""##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '"')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:42:5 + --> tests/ui/single_char_add_str.rs:48:5 | LL | string.insert_str(Y, r##"'"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '\'')` +error: calling `insert_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:50:5 + | +LL | string.insert_str(0, &c_ref.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, *c_ref)` + +error: calling `insert_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:51:5 + | +LL | string.insert_str(0, &c.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, c)` + +error: calling `insert_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:52:5 + | +LL | string.insert_str(0, &'a'.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, 'a')` + error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:44:5 + --> tests/ui/single_char_add_str.rs:54:5 | LL | get_string!().insert_str(1, "?"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')` -error: aborting due to 15 previous errors +error: aborting due to 21 previous errors -- cgit 1.4.1-3-g733a5 From f7723cada7191fba2313d410ea5a4327a878d589 Mon Sep 17 00:00:00 2001 From: Artem Belyakov Date: Sun, 9 Jun 2024 21:23:59 +0300 Subject: Fix dogfood test --- clippy_lints/src/methods/single_char_insert_string.rs | 2 +- clippy_lints/src/methods/single_char_push_string.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index f2af793a869..ba9ef9c84f9 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -29,7 +29,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[1].kind && let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind - && path_segment.ident.as_str() == "to_string" + && path_segment.ident.name == rustc_span::sym::to_string && (is_ref_char(cx, method_arg) || is_char(cx, method_arg)) { let base_string_snippet = diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index 8c6e490a38f..f00a5ab455e 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -28,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[0].kind && let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind - && path_segment.ident.as_str() == "to_string" + && path_segment.ident.name == rustc_span::sym::to_string && (is_ref_char(cx, method_arg) || is_char(cx, method_arg)) { let base_string_snippet = -- cgit 1.4.1-3-g733a5 From f7515ae9058786a61ffa30529f30575065b73450 Mon Sep 17 00:00:00 2001 From: Renato Lochetti Date: Sun, 9 Jun 2024 10:33:00 +0100 Subject: Don't lint indexing_slicing lints on proc macros --- clippy_lints/src/indexing_slicing.rs | 6 ++++-- tests/ui/indexing_slicing_index.rs | 20 ++++++++++++++++++ tests/ui/indexing_slicing_index.stderr | 32 ++++++++++++++-------------- tests/ui/indexing_slicing_slice.rs | 21 +++++++++++++++++++ tests/ui/indexing_slicing_slice.stderr | 38 +++++++++++++++++----------------- 5 files changed, 80 insertions(+), 37 deletions(-) diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index b13b4d145df..d54f2af65cd 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -2,8 +2,8 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::higher; use clippy_utils::ty::{deref_chain, get_adt_inherent_method}; +use clippy_utils::{higher, is_from_proc_macro}; use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -102,7 +102,9 @@ impl IndexingSlicing { impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if self.suppress_restriction_lint_in_const && cx.tcx.hir().is_inside_const_context(expr.hir_id) { + if (self.suppress_restriction_lint_in_const && cx.tcx.hir().is_inside_const_context(expr.hir_id)) + || is_from_proc_macro(cx, expr) + { return; } diff --git a/tests/ui/indexing_slicing_index.rs b/tests/ui/indexing_slicing_index.rs index 2e726141649..2af5fcc82a9 100644 --- a/tests/ui/indexing_slicing_index.rs +++ b/tests/ui/indexing_slicing_index.rs @@ -1,4 +1,5 @@ //@compile-flags: -Zdeduplicate-diagnostics=yes +//@aux-build: proc_macros.rs #![warn(clippy::indexing_slicing)] // We also check the out_of_bounds_indexing lint here, because it lints similar things and @@ -11,6 +12,9 @@ clippy::useless_vec )] +extern crate proc_macros; +use proc_macros::with_span; + const ARR: [i32; 2] = [1, 2]; const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false. //~^ ERROR: indexing may panic @@ -22,6 +26,22 @@ const fn idx4() -> usize { 4 } +with_span!( + span + + fn dont_lint_proc_macro_array() { + let x = [1, 2, 3, 4]; + let index: usize = 1; + x[index]; + x[10]; + + let x = vec![0; 5]; + let index: usize = 1; + x[index]; + x[10]; + } +); + fn main() { let x = [1, 2, 3, 4]; let index: usize = 1; diff --git a/tests/ui/indexing_slicing_index.stderr b/tests/ui/indexing_slicing_index.stderr index 386f91becf1..71677584d25 100644 --- a/tests/ui/indexing_slicing_index.stderr +++ b/tests/ui/indexing_slicing_index.stderr @@ -1,5 +1,5 @@ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:15:20 + --> tests/ui/indexing_slicing_index.rs:19:20 | LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false. | ^^^^^^^^^^ @@ -10,19 +10,19 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error[E0080]: evaluation of `main::{constant#3}` failed - --> tests/ui/indexing_slicing_index.rs:47:14 + --> tests/ui/indexing_slicing_index.rs:67:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 note: erroneous constant encountered - --> tests/ui/indexing_slicing_index.rs:47:5 + --> tests/ui/indexing_slicing_index.rs:67:5 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^^^^^^^^^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:28:5 + --> tests/ui/indexing_slicing_index.rs:48:5 | LL | x[index]; | ^^^^^^^^ @@ -30,7 +30,7 @@ LL | x[index]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:31:5 + --> tests/ui/indexing_slicing_index.rs:51:5 | LL | x[4]; | ^^^^ @@ -39,13 +39,13 @@ LL | x[4]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:33:5 + --> tests/ui/indexing_slicing_index.rs:53:5 | LL | x[1 << 3]; | ^^^^^^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:44:14 + --> tests/ui/indexing_slicing_index.rs:64:14 | LL | const { &ARR[idx()] }; | ^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | const { &ARR[idx()] }; = note: the suggestion might not be applicable in constant blocks error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:47:14 + --> tests/ui/indexing_slicing_index.rs:67:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ @@ -63,13 +63,13 @@ LL | const { &ARR[idx4()] }; = note: the suggestion might not be applicable in constant blocks error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:54:5 + --> tests/ui/indexing_slicing_index.rs:74:5 | LL | y[4]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:57:5 + --> tests/ui/indexing_slicing_index.rs:77:5 | LL | v[0]; | ^^^^ @@ -77,7 +77,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:59:5 + --> tests/ui/indexing_slicing_index.rs:79:5 | LL | v[10]; | ^^^^^ @@ -85,7 +85,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:61:5 + --> tests/ui/indexing_slicing_index.rs:81:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -93,13 +93,13 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:69:5 + --> tests/ui/indexing_slicing_index.rs:89:5 | LL | x[N]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:72:5 + --> tests/ui/indexing_slicing_index.rs:92:5 | LL | v[N]; | ^^^^ @@ -107,7 +107,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:74:5 + --> tests/ui/indexing_slicing_index.rs:94:5 | LL | v[M]; | ^^^^ @@ -115,7 +115,7 @@ LL | v[M]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:78:13 + --> tests/ui/indexing_slicing_index.rs:98:13 | LL | let _ = x[4]; | ^^^^ diff --git a/tests/ui/indexing_slicing_slice.rs b/tests/ui/indexing_slicing_slice.rs index 69291acd9c7..f37bcc4aa0c 100644 --- a/tests/ui/indexing_slicing_slice.rs +++ b/tests/ui/indexing_slicing_slice.rs @@ -1,3 +1,5 @@ +//@aux-build: proc_macros.rs + #![warn(clippy::indexing_slicing)] // We also check the out_of_bounds_indexing lint here, because it lints similar things and // we want to avoid false positives. @@ -11,6 +13,9 @@ )] #![warn(clippy::indexing_slicing)] +extern crate proc_macros; +use proc_macros::with_span; + use std::ops::Index; struct BoolMap { @@ -86,6 +91,22 @@ impl Index for Z { } } +with_span!( + span + + fn dont_lint_proc_macro() { + let x = [1, 2, 3, 4]; + let index: usize = 1; + &x[index..]; + &x[..10]; + + let x = vec![0; 5]; + let index: usize = 1; + &x[index..]; + &x[..10]; + } +); + fn main() { let x = [1, 2, 3, 4]; let index: usize = 1; diff --git a/tests/ui/indexing_slicing_slice.stderr b/tests/ui/indexing_slicing_slice.stderr index a7da3fe3faa..1e72506746e 100644 --- a/tests/ui/indexing_slicing_slice.stderr +++ b/tests/ui/indexing_slicing_slice.stderr @@ -1,5 +1,5 @@ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:94:6 + --> tests/ui/indexing_slicing_slice.rs:115:6 | LL | &x[index..]; | ^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | &x[index..]; = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:96:6 + --> tests/ui/indexing_slicing_slice.rs:117:6 | LL | &x[..index]; | ^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | &x[..index]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:98:6 + --> tests/ui/indexing_slicing_slice.rs:119:6 | LL | &x[index_from..index_to]; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | &x[index_from..index_to]; = help: consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:100:6 + --> tests/ui/indexing_slicing_slice.rs:121:6 | LL | &x[index_from..][..index_to]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | &x[index_from..][..index_to]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:100:6 + --> tests/ui/indexing_slicing_slice.rs:121:6 | LL | &x[index_from..][..index_to]; | ^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | &x[index_from..][..index_to]; = help: consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:103:6 + --> tests/ui/indexing_slicing_slice.rs:124:6 | LL | &x[5..][..10]; | ^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | &x[5..][..10]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:103:8 + --> tests/ui/indexing_slicing_slice.rs:124:8 | LL | &x[5..][..10]; | ^ @@ -58,7 +58,7 @@ LL | &x[5..][..10]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:107:6 + --> tests/ui/indexing_slicing_slice.rs:128:6 | LL | &x[0..][..3]; | ^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | &x[0..][..3]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:109:6 + --> tests/ui/indexing_slicing_slice.rs:130:6 | LL | &x[1..][..5]; | ^^^^^^^^^^^ @@ -74,19 +74,19 @@ LL | &x[1..][..5]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:117:12 + --> tests/ui/indexing_slicing_slice.rs:138:12 | LL | &y[0..=4]; | ^ error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:119:11 + --> tests/ui/indexing_slicing_slice.rs:140:11 | LL | &y[..=4]; | ^ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:125:6 + --> tests/ui/indexing_slicing_slice.rs:146:6 | LL | &v[10..100]; | ^^^^^^^^^^ @@ -94,7 +94,7 @@ LL | &v[10..100]; = help: consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:127:6 + --> tests/ui/indexing_slicing_slice.rs:148:6 | LL | &x[10..][..100]; | ^^^^^^^^^^^^^^ @@ -102,13 +102,13 @@ LL | &x[10..][..100]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:127:8 + --> tests/ui/indexing_slicing_slice.rs:148:8 | LL | &x[10..][..100]; | ^^ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:130:6 + --> tests/ui/indexing_slicing_slice.rs:151:6 | LL | &v[10..]; | ^^^^^^^ @@ -116,7 +116,7 @@ LL | &v[10..]; = help: consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:132:6 + --> tests/ui/indexing_slicing_slice.rs:153:6 | LL | &v[..100]; | ^^^^^^^^ @@ -124,7 +124,7 @@ LL | &v[..100]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_slice.rs:150:5 + --> tests/ui/indexing_slicing_slice.rs:171:5 | LL | map_with_get[true]; | ^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL | map_with_get[true]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_slice.rs:153:5 + --> tests/ui/indexing_slicing_slice.rs:174:5 | LL | s[0]; | ^^^^ @@ -140,7 +140,7 @@ LL | s[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_slice.rs:156:5 + --> tests/ui/indexing_slicing_slice.rs:177:5 | LL | y[0]; | ^^^^ -- cgit 1.4.1-3-g733a5 From 8c1f953772a025dcfec6dbd36544e415842ad1d1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Jun 2024 16:13:45 +0200 Subject: ScalarInt: size mismatches are a bug, do not delay the panic --- clippy_lints/src/large_const_arrays.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 2 +- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/zero_repeat_side_effects.rs | 3 +-- clippy_utils/src/consts.rs | 4 ++-- clippy_utils/src/ty.rs | 20 +++----------------- 6 files changed, 9 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 77d05020c82..7f8197c0cc0 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Array(element_type, cst) = ty.kind() && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() - && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) + && let element_count = element_count.to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) { diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index f0f3f53647b..c9bfc9c85d9 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { && !self.is_from_vec_macro(cx, expr.span) && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() - && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) + && let element_count = element_count.to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && !cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| { matches!( diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 76d9cee18aa..20a97645af9 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -199,7 +199,7 @@ impl<'tcx> NonCopyConst<'tcx> { .any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), ty::Adt(def, args) if def.is_enum() => { let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap(); - let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap()); + let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().to_u32()); fields .iter() .copied() diff --git a/clippy_lints/src/zero_repeat_side_effects.rs b/clippy_lints/src/zero_repeat_side_effects.rs index 848b49130dc..8796b8f61d1 100644 --- a/clippy_lints/src/zero_repeat_side_effects.rs +++ b/clippy_lints/src/zero_repeat_side_effects.rs @@ -56,8 +56,7 @@ impl LateLintPass<'_> for ZeroRepeatSideEffects { } else if let ExprKind::Repeat(inner_expr, _) = expr.kind && let ty::Array(_, cst) = cx.typeck_results().expr_ty(expr).kind() && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() - && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) - && element_count == 0 + && element_count.to_target_usize(cx.tcx) == 0 { inner_check(cx, expr, inner_expr, false); } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 5c9cad2b45d..e9e1aa7e445 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -810,14 +810,14 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> (ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), - ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))), + ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.to_bits(int.size()))), ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits( int.try_into().expect("invalid f32 bit representation"), ))), ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( int.try_into().expect("invalid f64 bit representation"), ))), - ty::RawPtr(_, _) => Some(Constant::RawPtr(int.assert_bits(int.size()))), + ty::RawPtr(_, _) => Some(Constant::RawPtr(int.to_bits(int.size()))), _ => None, }, (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index f0dac6f5d9c..6e5626297c9 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -23,7 +23,7 @@ use rustc_middle::ty::{ }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; -use rustc_target::abi::{Size, VariantIdx}; +use rustc_target::abi::VariantIdx; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Obligation, ObligationCause}; @@ -865,22 +865,8 @@ impl core::ops::Add for EnumValue { pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option { if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) { match tcx.type_of(id).instantiate_identity().kind() { - ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() { - 1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8), - 2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16), - 4 => i128::from(value.assert_bits(Size::from_bytes(4)) as u32 as i32), - 8 => i128::from(value.assert_bits(Size::from_bytes(8)) as u64 as i64), - 16 => value.assert_bits(Size::from_bytes(16)) as i128, - _ => return None, - })), - ty::Uint(_) => Some(EnumValue::Unsigned(match value.size().bytes() { - 1 => value.assert_bits(Size::from_bytes(1)), - 2 => value.assert_bits(Size::from_bytes(2)), - 4 => value.assert_bits(Size::from_bytes(4)), - 8 => value.assert_bits(Size::from_bytes(8)), - 16 => value.assert_bits(Size::from_bytes(16)), - _ => return None, - })), + ty::Int(_) => Some(EnumValue::Signed(value.to_int(value.size()))), + ty::Uint(_) => Some(EnumValue::Unsigned(value.to_uint(value.size()))), _ => None, } } else { -- cgit 1.4.1-3-g733a5 From bd6fca201551382e12f08de37c1f67bc3deb968d Mon Sep 17 00:00:00 2001 From: "许杰友 Jieyou Xu (Joe)" Date: Wed, 10 Apr 2024 14:17:16 +0000 Subject: Clarify `Command::new` behavior if passed programs with arguments --- library/std/src/process.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index c926c89f7a9..f351dab78dc 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -629,6 +629,25 @@ impl Command { /// .spawn() /// .expect("sh command failed to start"); /// ``` + /// + /// # Caveats + /// + /// [`Command::new`] is only intended to accept the path of the program. If you pass a program + /// path along with arguments like `Command::new("ls -l").spawn()`, it will try to search for + /// `ls -l` literally. The arguments need to be passed separately, such as via [`arg`] or + /// [`args`]. + /// + /// ```no_run + /// use std::process::Command; + /// + /// Command::new("ls") + /// .arg("-l") // arg passed separately + /// .spawn() + /// .expect("ls command failed to start"); + /// ``` + /// + /// [`arg`]: Self::arg + /// [`args`]: Self::args #[stable(feature = "process", since = "1.0.0")] pub fn new>(program: S) -> Command { Command { inner: imp::Command::new(program.as_ref()) } -- cgit 1.4.1-3-g733a5 From 8bd8f599eb0fb0e96ebffb438b20a85e5ccaaf1d Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 10 Jun 2024 13:51:29 +0000 Subject: Bump windows-bindgen to 0.57 --- Cargo.lock | 8 +- library/std/src/sys/pal/windows/c/windows_sys.rs | 483 ++++------------------- src/tools/generate-windows-sys/Cargo.toml | 2 +- 3 files changed, 71 insertions(+), 422 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 58d95f927bf..6635a4cf002 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6399,9 +6399,9 @@ dependencies = [ [[package]] name = "windows-bindgen" -version = "0.56.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28e3ea6330cf17fdcdce8bf08d0549ce93769dca9bedc6c39c36c8c0e17db46" +checksum = "1ccb96113d6277ba543c0f77e1c5494af8094bf9daf9b85acdc3f1b620e7c7b4" dependencies = [ "proc-macro2", "rayon", @@ -6422,9 +6422,9 @@ dependencies = [ [[package]] name = "windows-metadata" -version = "0.56.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3993f7827fff10c454e3a24847075598c7c08108304b8b07943c2c73d78f3b34" +checksum = "8308d076825b9d9e5abc64f8113e96d02b2aeeba869b20fdd65c7e70cda13dfc" [[package]] name = "windows-sys" diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 1da8871ae44..19f013d3347 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -1,4 +1,4 @@ -// Bindings generated by `windows-bindgen` 0.56.0 +// Bindings generated by `windows-bindgen` 0.57.0 #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)] #[link(name = "advapi32")] @@ -841,6 +841,7 @@ extern "system" { pub const ABOVE_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 32768u32; pub type ADDRESS_FAMILY = u16; #[repr(C)] +#[derive(Clone, Copy)] pub struct ADDRINFOA { pub ai_flags: i32, pub ai_family: i32, @@ -851,18 +852,13 @@ pub struct ADDRINFOA { pub ai_addr: *mut SOCKADDR, pub ai_next: *mut ADDRINFOA, } -impl Copy for ADDRINFOA {} -impl Clone for ADDRINFOA { - fn clone(&self) -> Self { - *self - } -} pub const AF_INET: ADDRESS_FAMILY = 2u16; pub const AF_INET6: ADDRESS_FAMILY = 23u16; pub const AF_UNIX: u16 = 1u16; pub const AF_UNSPEC: ADDRESS_FAMILY = 0u16; pub const ALL_PROCESSOR_GROUPS: u16 = 65535u16; #[repr(C)] +#[derive(Clone, Copy)] pub union ARM64_NT_NEON128 { pub Anonymous: ARM64_NT_NEON128_0, pub D: [f64; 2], @@ -870,27 +866,17 @@ pub union ARM64_NT_NEON128 { pub H: [u16; 8], pub B: [u8; 16], } -impl Copy for ARM64_NT_NEON128 {} -impl Clone for ARM64_NT_NEON128 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct ARM64_NT_NEON128_0 { pub Low: u64, pub High: i64, } -impl Copy for ARM64_NT_NEON128_0 {} -impl Clone for ARM64_NT_NEON128_0 { - fn clone(&self) -> Self { - *self - } -} pub const BELOW_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 16384u32; pub type BOOL = i32; pub type BOOLEAN = u8; #[repr(C)] +#[derive(Clone, Copy)] pub struct BY_HANDLE_FILE_INFORMATION { pub dwFileAttributes: u32, pub ftCreationTime: FILETIME, @@ -903,41 +889,26 @@ pub struct BY_HANDLE_FILE_INFORMATION { pub nFileIndexHigh: u32, pub nFileIndexLow: u32, } -impl Copy for BY_HANDLE_FILE_INFORMATION {} -impl Clone for BY_HANDLE_FILE_INFORMATION { - fn clone(&self) -> Self { - *self - } -} pub const CALLBACK_CHUNK_FINISHED: LPPROGRESS_ROUTINE_CALLBACK_REASON = 0u32; pub const CALLBACK_STREAM_SWITCH: LPPROGRESS_ROUTINE_CALLBACK_REASON = 1u32; pub type COMPARESTRING_RESULT = i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct CONDITION_VARIABLE { pub Ptr: *mut core::ffi::c_void, } -impl Copy for CONDITION_VARIABLE {} -impl Clone for CONDITION_VARIABLE { - fn clone(&self) -> Self { - *self - } -} pub type CONSOLE_MODE = u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct CONSOLE_READCONSOLE_CONTROL { pub nLength: u32, pub nInitialChars: u32, pub dwCtrlWakeupMask: u32, pub dwControlKeyState: u32, } -impl Copy for CONSOLE_READCONSOLE_CONTROL {} -impl Clone for CONSOLE_READCONSOLE_CONTROL { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "aarch64")] +#[derive(Clone, Copy)] pub struct CONTEXT { pub ContextFlags: CONTEXT_FLAGS, pub Cpsr: u32, @@ -952,30 +923,16 @@ pub struct CONTEXT { pub Wcr: [u32; 2], pub Wvr: [u64; 2], } -#[cfg(target_arch = "aarch64")] -impl Copy for CONTEXT {} -#[cfg(target_arch = "aarch64")] -impl Clone for CONTEXT { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "aarch64")] +#[derive(Clone, Copy)] pub union CONTEXT_0 { pub Anonymous: CONTEXT_0_0, pub X: [u64; 31], } -#[cfg(target_arch = "aarch64")] -impl Copy for CONTEXT_0 {} -#[cfg(target_arch = "aarch64")] -impl Clone for CONTEXT_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "aarch64")] +#[derive(Clone, Copy)] pub struct CONTEXT_0_0 { pub X0: u64, pub X1: u64, @@ -1009,16 +966,9 @@ pub struct CONTEXT_0_0 { pub Fp: u64, pub Lr: u64, } -#[cfg(target_arch = "aarch64")] -impl Copy for CONTEXT_0_0 {} -#[cfg(target_arch = "aarch64")] -impl Clone for CONTEXT_0_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +#[derive(Clone, Copy)] pub struct CONTEXT { pub P1Home: u64, pub P2Home: u64, @@ -1067,30 +1017,16 @@ pub struct CONTEXT { pub LastExceptionToRip: u64, pub LastExceptionFromRip: u64, } -#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] -impl Copy for CONTEXT {} -#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] -impl Clone for CONTEXT { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +#[derive(Clone, Copy)] pub union CONTEXT_0 { pub FltSave: XSAVE_FORMAT, pub Anonymous: CONTEXT_0_0, } -#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] -impl Copy for CONTEXT_0 {} -#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] -impl Clone for CONTEXT_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +#[derive(Clone, Copy)] pub struct CONTEXT_0_0 { pub Header: [M128A; 2], pub Legacy: [M128A; 8], @@ -1111,16 +1047,9 @@ pub struct CONTEXT_0_0 { pub Xmm14: M128A, pub Xmm15: M128A, } -#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] -impl Copy for CONTEXT_0_0 {} -#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] -impl Clone for CONTEXT_0_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "x86")] +#[derive(Clone, Copy)] pub struct CONTEXT { pub ContextFlags: CONTEXT_FLAGS, pub Dr0: u32, @@ -1148,14 +1077,6 @@ pub struct CONTEXT { pub SegSs: u32, pub ExtendedRegisters: [u8; 512], } -#[cfg(target_arch = "x86")] -impl Copy for CONTEXT {} -#[cfg(target_arch = "x86")] -impl Clone for CONTEXT { - fn clone(&self) -> Self { - *self - } -} pub type CONTEXT_FLAGS = u32; pub const CP_UTF8: u32 = 65001u32; pub const CREATE_ALWAYS: FILE_CREATION_DISPOSITION = 2u32; @@ -3068,6 +2989,7 @@ pub const ERROR_XML_PARSE_ERROR: WIN32_ERROR = 1465u32; pub type EXCEPTION_DISPOSITION = i32; pub const EXCEPTION_MAXIMUM_PARAMETERS: u32 = 15u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct EXCEPTION_RECORD { pub ExceptionCode: NTSTATUS, pub ExceptionFlags: u32, @@ -3076,12 +2998,6 @@ pub struct EXCEPTION_RECORD { pub NumberParameters: u32, pub ExceptionInformation: [usize; 15], } -impl Copy for EXCEPTION_RECORD {} -impl Clone for EXCEPTION_RECORD { - fn clone(&self) -> Self { - *self - } -} pub const EXCEPTION_STACK_OVERFLOW: NTSTATUS = 0xC00000FD_u32 as _; pub const EXTENDED_STARTUPINFO_PRESENT: PROCESS_CREATION_FLAGS = 524288u32; pub const E_NOTIMPL: HRESULT = 0x80004001_u32 as _; @@ -3095,40 +3011,25 @@ pub const FALSE: BOOL = 0i32; pub type FARPROC = Option isize>; pub const FAST_FAIL_FATAL_APP_EXIT: u32 = 7u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FD_SET { pub fd_count: u32, pub fd_array: [SOCKET; 64], } -impl Copy for FD_SET {} -impl Clone for FD_SET { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct FILETIME { pub dwLowDateTime: u32, pub dwHighDateTime: u32, } -impl Copy for FILETIME {} -impl Clone for FILETIME { - fn clone(&self) -> Self { - *self - } -} pub type FILE_ACCESS_RIGHTS = u32; pub const FILE_ADD_FILE: FILE_ACCESS_RIGHTS = 2u32; pub const FILE_ADD_SUBDIRECTORY: FILE_ACCESS_RIGHTS = 4u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_ALLOCATION_INFO { pub AllocationSize: i64, } -impl Copy for FILE_ALLOCATION_INFO {} -impl Clone for FILE_ALLOCATION_INFO { - fn clone(&self) -> Self { - *self - } -} pub const FILE_ALL_ACCESS: FILE_ACCESS_RIGHTS = 2032127u32; pub const FILE_APPEND_DATA: FILE_ACCESS_RIGHTS = 4u32; pub const FILE_ATTRIBUTE_ARCHIVE: FILE_FLAGS_AND_ATTRIBUTES = 32u32; @@ -3151,20 +3052,16 @@ pub const FILE_ATTRIBUTE_REPARSE_POINT: FILE_FLAGS_AND_ATTRIBUTES = 1024u32; pub const FILE_ATTRIBUTE_SPARSE_FILE: FILE_FLAGS_AND_ATTRIBUTES = 512u32; pub const FILE_ATTRIBUTE_SYSTEM: FILE_FLAGS_AND_ATTRIBUTES = 4u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_ATTRIBUTE_TAG_INFO { pub FileAttributes: u32, pub ReparseTag: u32, } -impl Copy for FILE_ATTRIBUTE_TAG_INFO {} -impl Clone for FILE_ATTRIBUTE_TAG_INFO { - fn clone(&self) -> Self { - *self - } -} pub const FILE_ATTRIBUTE_TEMPORARY: FILE_FLAGS_AND_ATTRIBUTES = 256u32; pub const FILE_ATTRIBUTE_UNPINNED: FILE_FLAGS_AND_ATTRIBUTES = 1048576u32; pub const FILE_ATTRIBUTE_VIRTUAL: FILE_FLAGS_AND_ATTRIBUTES = 65536u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_BASIC_INFO { pub CreationTime: i64, pub LastAccessTime: i64, @@ -3172,12 +3069,6 @@ pub struct FILE_BASIC_INFO { pub ChangeTime: i64, pub FileAttributes: u32, } -impl Copy for FILE_BASIC_INFO {} -impl Clone for FILE_BASIC_INFO { - fn clone(&self) -> Self { - *self - } -} pub const FILE_BEGIN: SET_FILE_POINTER_MOVE_METHOD = 0u32; pub const FILE_COMPLETE_IF_OPLOCKED: NTCREATEFILE_CREATE_OPTIONS = 256u32; pub const FILE_CONTAINS_EXTENDED_CREATE_INFORMATION: NTCREATEFILE_CREATE_OPTIONS = 268435456u32; @@ -3197,37 +3088,22 @@ pub const FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE: FILE_DISPOSITION_INFO pub const FILE_DISPOSITION_FLAG_ON_CLOSE: FILE_DISPOSITION_INFO_EX_FLAGS = 8u32; pub const FILE_DISPOSITION_FLAG_POSIX_SEMANTICS: FILE_DISPOSITION_INFO_EX_FLAGS = 2u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_DISPOSITION_INFO { pub DeleteFile: BOOLEAN, } -impl Copy for FILE_DISPOSITION_INFO {} -impl Clone for FILE_DISPOSITION_INFO { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_DISPOSITION_INFO_EX { pub Flags: FILE_DISPOSITION_INFO_EX_FLAGS, } -impl Copy for FILE_DISPOSITION_INFO_EX {} -impl Clone for FILE_DISPOSITION_INFO_EX { - fn clone(&self) -> Self { - *self - } -} pub type FILE_DISPOSITION_INFO_EX_FLAGS = u32; pub const FILE_END: SET_FILE_POINTER_MOVE_METHOD = 2u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_END_OF_FILE_INFO { pub EndOfFile: i64, } -impl Copy for FILE_END_OF_FILE_INFO {} -impl Clone for FILE_END_OF_FILE_INFO { - fn clone(&self) -> Self { - *self - } -} pub const FILE_EXECUTE: FILE_ACCESS_RIGHTS = 32u32; pub type FILE_FLAGS_AND_ATTRIBUTES = u32; pub const FILE_FLAG_BACKUP_SEMANTICS: FILE_FLAGS_AND_ATTRIBUTES = 33554432u32; @@ -3246,6 +3122,7 @@ pub const FILE_GENERIC_EXECUTE: FILE_ACCESS_RIGHTS = 1179808u32; pub const FILE_GENERIC_READ: FILE_ACCESS_RIGHTS = 1179785u32; pub const FILE_GENERIC_WRITE: FILE_ACCESS_RIGHTS = 1179926u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_ID_BOTH_DIR_INFO { pub NextEntryOffset: u32, pub FileIndex: u32, @@ -3263,23 +3140,12 @@ pub struct FILE_ID_BOTH_DIR_INFO { pub FileId: i64, pub FileName: [u16; 1], } -impl Copy for FILE_ID_BOTH_DIR_INFO {} -impl Clone for FILE_ID_BOTH_DIR_INFO { - fn clone(&self) -> Self { - *self - } -} pub type FILE_INFO_BY_HANDLE_CLASS = i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_IO_PRIORITY_HINT_INFO { pub PriorityHint: PRIORITY_HINT, } -impl Copy for FILE_IO_PRIORITY_HINT_INFO {} -impl Clone for FILE_IO_PRIORITY_HINT_INFO { - fn clone(&self) -> Self { - *self - } -} pub const FILE_LIST_DIRECTORY: FILE_ACCESS_RIGHTS = 1u32; pub const FILE_NAME_NORMALIZED: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32; pub const FILE_NAME_OPENED: GETFINALPATHNAMEBYHANDLE_FLAGS = 8u32; @@ -3310,6 +3176,7 @@ pub const FILE_SHARE_NONE: FILE_SHARE_MODE = 0u32; pub const FILE_SHARE_READ: FILE_SHARE_MODE = 1u32; pub const FILE_SHARE_WRITE: FILE_SHARE_MODE = 2u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_STANDARD_INFO { pub AllocationSize: i64, pub EndOfFile: i64, @@ -3317,12 +3184,6 @@ pub struct FILE_STANDARD_INFO { pub DeletePending: BOOLEAN, pub Directory: BOOLEAN, } -impl Copy for FILE_STANDARD_INFO {} -impl Clone for FILE_STANDARD_INFO { - fn clone(&self) -> Self { - *self - } -} pub const FILE_SUPERSEDE: NTCREATEFILE_CREATE_DISPOSITION = 0u32; pub const FILE_SYNCHRONOUS_IO_ALERT: NTCREATEFILE_CREATE_OPTIONS = 16u32; pub const FILE_SYNCHRONOUS_IO_NONALERT: NTCREATEFILE_CREATE_OPTIONS = 32u32; @@ -3340,6 +3201,7 @@ pub const FILE_WRITE_THROUGH: NTCREATEFILE_CREATE_OPTIONS = 2u32; pub const FIONBIO: i32 = -2147195266i32; #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +#[derive(Clone, Copy)] pub struct FLOATING_SAVE_AREA { pub ControlWord: u32, pub StatusWord: u32, @@ -3351,16 +3213,9 @@ pub struct FLOATING_SAVE_AREA { pub RegisterArea: [u8; 80], pub Cr0NpxState: u32, } -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] -impl Copy for FLOATING_SAVE_AREA {} -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] -impl Clone for FLOATING_SAVE_AREA { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "x86")] +#[derive(Clone, Copy)] pub struct FLOATING_SAVE_AREA { pub ControlWord: u32, pub StatusWord: u32, @@ -3372,14 +3227,6 @@ pub struct FLOATING_SAVE_AREA { pub RegisterArea: [u8; 80], pub Spare0: u32, } -#[cfg(target_arch = "x86")] -impl Copy for FLOATING_SAVE_AREA {} -#[cfg(target_arch = "x86")] -impl Clone for FLOATING_SAVE_AREA { - fn clone(&self) -> Self { - *self - } -} pub const FORMAT_MESSAGE_ALLOCATE_BUFFER: FORMAT_MESSAGE_OPTIONS = 256u32; pub const FORMAT_MESSAGE_ARGUMENT_ARRAY: FORMAT_MESSAGE_OPTIONS = 8192u32; pub const FORMAT_MESSAGE_FROM_HMODULE: FORMAT_MESSAGE_OPTIONS = 2048u32; @@ -3422,18 +3269,13 @@ pub const GENERIC_READ: GENERIC_ACCESS_RIGHTS = 2147483648u32; pub const GENERIC_WRITE: GENERIC_ACCESS_RIGHTS = 1073741824u32; pub type GETFINALPATHNAMEBYHANDLE_FLAGS = u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct GUID { pub data1: u32, pub data2: u16, pub data3: u16, pub data4: [u8; 8], } -impl Copy for GUID {} -impl Clone for GUID { - fn clone(&self) -> Self { - *self - } -} impl GUID { pub const fn from_u128(uuid: u128) -> Self { Self { @@ -3454,112 +3296,67 @@ pub type HMODULE = *mut core::ffi::c_void; pub type HRESULT = i32; pub const IDLE_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 64u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct IN6_ADDR { pub u: IN6_ADDR_0, } -impl Copy for IN6_ADDR {} -impl Clone for IN6_ADDR { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub union IN6_ADDR_0 { pub Byte: [u8; 16], pub Word: [u16; 8], } -impl Copy for IN6_ADDR_0 {} -impl Clone for IN6_ADDR_0 { - fn clone(&self) -> Self { - *self - } -} pub const INFINITE: u32 = 4294967295u32; pub const INHERIT_CALLER_PRIORITY: PROCESS_CREATION_FLAGS = 131072u32; pub const INHERIT_PARENT_AFFINITY: PROCESS_CREATION_FLAGS = 65536u32; #[repr(C)] +#[derive(Clone, Copy)] pub union INIT_ONCE { pub Ptr: *mut core::ffi::c_void, } -impl Copy for INIT_ONCE {} -impl Clone for INIT_ONCE { - fn clone(&self) -> Self { - *self - } -} pub const INIT_ONCE_INIT_FAILED: u32 = 4u32; pub const INVALID_FILE_ATTRIBUTES: u32 = 4294967295u32; pub const INVALID_SOCKET: SOCKET = -1i32 as _; #[repr(C)] +#[derive(Clone, Copy)] pub struct IN_ADDR { pub S_un: IN_ADDR_0, } -impl Copy for IN_ADDR {} -impl Clone for IN_ADDR { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub union IN_ADDR_0 { pub S_un_b: IN_ADDR_0_0, pub S_un_w: IN_ADDR_0_1, pub S_addr: u32, } -impl Copy for IN_ADDR_0 {} -impl Clone for IN_ADDR_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct IN_ADDR_0_0 { pub s_b1: u8, pub s_b2: u8, pub s_b3: u8, pub s_b4: u8, } -impl Copy for IN_ADDR_0_0 {} -impl Clone for IN_ADDR_0_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct IN_ADDR_0_1 { pub s_w1: u16, pub s_w2: u16, } -impl Copy for IN_ADDR_0_1 {} -impl Clone for IN_ADDR_0_1 { - fn clone(&self) -> Self { - *self - } -} pub const IO_REPARSE_TAG_MOUNT_POINT: u32 = 2684354563u32; pub const IO_REPARSE_TAG_SYMLINK: u32 = 2684354572u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct IO_STATUS_BLOCK { pub Anonymous: IO_STATUS_BLOCK_0, pub Information: usize, } -impl Copy for IO_STATUS_BLOCK {} -impl Clone for IO_STATUS_BLOCK { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub union IO_STATUS_BLOCK_0 { pub Status: NTSTATUS, pub Pointer: *mut core::ffi::c_void, } -impl Copy for IO_STATUS_BLOCK_0 {} -impl Clone for IO_STATUS_BLOCK_0 { - fn clone(&self) -> Self { - *self - } -} pub type IPPROTO = i32; pub const IPPROTO_AH: IPPROTO = 51i32; pub const IPPROTO_CBT: IPPROTO = 7i32; @@ -3601,45 +3398,30 @@ pub const IPPROTO_UDP: IPPROTO = 17i32; pub const IPV6_ADD_MEMBERSHIP: i32 = 12i32; pub const IPV6_DROP_MEMBERSHIP: i32 = 13i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct IPV6_MREQ { pub ipv6mr_multiaddr: IN6_ADDR, pub ipv6mr_interface: u32, } -impl Copy for IPV6_MREQ {} -impl Clone for IPV6_MREQ { - fn clone(&self) -> Self { - *self - } -} pub const IPV6_MULTICAST_LOOP: i32 = 11i32; pub const IPV6_V6ONLY: i32 = 27i32; pub const IP_ADD_MEMBERSHIP: i32 = 12i32; pub const IP_DROP_MEMBERSHIP: i32 = 13i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct IP_MREQ { pub imr_multiaddr: IN_ADDR, pub imr_interface: IN_ADDR, } -impl Copy for IP_MREQ {} -impl Clone for IP_MREQ { - fn clone(&self) -> Self { - *self - } -} pub const IP_MULTICAST_LOOP: i32 = 11i32; pub const IP_MULTICAST_TTL: i32 = 10i32; pub const IP_TTL: i32 = 4i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct LINGER { pub l_onoff: u16, pub l_linger: u16, } -impl Copy for LINGER {} -impl Clone for LINGER { - fn clone(&self) -> Self { - *self - } -} pub type LPOVERLAPPED_COMPLETION_ROUTINE = Option< unsafe extern "system" fn( dwerrorcode: u32, @@ -3673,16 +3455,11 @@ pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = Option< ), >; #[repr(C)] +#[derive(Clone, Copy)] pub struct M128A { pub Low: u64, pub High: i64, } -impl Copy for M128A {} -impl Clone for M128A { - fn clone(&self) -> Self { - *self - } -} pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: u32 = 16384u32; pub const MAX_PATH: u32 = 260u32; pub const MB_COMPOSITE: MULTI_BYTE_TO_WIDE_CHAR_FLAGS = 2u32; @@ -3710,6 +3487,7 @@ pub type NTCREATEFILE_CREATE_DISPOSITION = u32; pub type NTCREATEFILE_CREATE_OPTIONS = u32; pub type NTSTATUS = i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct OBJECT_ATTRIBUTES { pub Length: u32, pub RootDirectory: HANDLE, @@ -3718,50 +3496,29 @@ pub struct OBJECT_ATTRIBUTES { pub SecurityDescriptor: *const core::ffi::c_void, pub SecurityQualityOfService: *const core::ffi::c_void, } -impl Copy for OBJECT_ATTRIBUTES {} -impl Clone for OBJECT_ATTRIBUTES { - fn clone(&self) -> Self { - *self - } -} pub const OBJ_DONT_REPARSE: i32 = 4096i32; pub const OPEN_ALWAYS: FILE_CREATION_DISPOSITION = 4u32; pub const OPEN_EXISTING: FILE_CREATION_DISPOSITION = 3u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct OVERLAPPED { pub Internal: usize, pub InternalHigh: usize, pub Anonymous: OVERLAPPED_0, pub hEvent: HANDLE, } -impl Copy for OVERLAPPED {} -impl Clone for OVERLAPPED { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub union OVERLAPPED_0 { pub Anonymous: OVERLAPPED_0_0, pub Pointer: *mut core::ffi::c_void, } -impl Copy for OVERLAPPED_0 {} -impl Clone for OVERLAPPED_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct OVERLAPPED_0_0 { pub Offset: u32, pub OffsetHigh: u32, } -impl Copy for OVERLAPPED_0_0 {} -impl Clone for OVERLAPPED_0_0 { - fn clone(&self) -> Self { - *self - } -} pub type PCSTR = *const u8; pub type PCWSTR = *const u16; pub type PIO_APC_ROUTINE = Option< @@ -3788,18 +3545,13 @@ pub type PRIORITY_HINT = i32; pub type PROCESSOR_ARCHITECTURE = u16; pub type PROCESS_CREATION_FLAGS = u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct PROCESS_INFORMATION { pub hProcess: HANDLE, pub hThread: HANDLE, pub dwProcessId: u32, pub dwThreadId: u32, } -impl Copy for PROCESS_INFORMATION {} -impl Clone for PROCESS_INFORMATION { - fn clone(&self) -> Self { - *self - } -} pub const PROCESS_MODE_BACKGROUND_BEGIN: PROCESS_CREATION_FLAGS = 1048576u32; pub const PROCESS_MODE_BACKGROUND_END: PROCESS_CREATION_FLAGS = 2097152u32; pub const PROFILE_KERNEL: PROCESS_CREATION_FLAGS = 536870912u32; @@ -3822,17 +3574,12 @@ pub const SD_RECEIVE: WINSOCK_SHUTDOWN_HOW = 0i32; pub const SD_SEND: WINSOCK_SHUTDOWN_HOW = 1i32; pub const SECURITY_ANONYMOUS: FILE_FLAGS_AND_ATTRIBUTES = 0u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct SECURITY_ATTRIBUTES { pub nLength: u32, pub lpSecurityDescriptor: *mut core::ffi::c_void, pub bInheritHandle: BOOL, } -impl Copy for SECURITY_ATTRIBUTES {} -impl Clone for SECURITY_ATTRIBUTES { - fn clone(&self) -> Self { - *self - } -} pub const SECURITY_CONTEXT_TRACKING: FILE_FLAGS_AND_ATTRIBUTES = 262144u32; pub const SECURITY_DELEGATION: FILE_FLAGS_AND_ATTRIBUTES = 196608u32; pub const SECURITY_EFFECTIVE_ONLY: FILE_FLAGS_AND_ATTRIBUTES = 524288u32; @@ -3843,27 +3590,17 @@ pub const SECURITY_VALID_SQOS_FLAGS: FILE_FLAGS_AND_ATTRIBUTES = 2031616u32; pub type SEND_RECV_FLAGS = i32; pub type SET_FILE_POINTER_MOVE_METHOD = u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct SOCKADDR { pub sa_family: ADDRESS_FAMILY, pub sa_data: [i8; 14], } -impl Copy for SOCKADDR {} -impl Clone for SOCKADDR { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct SOCKADDR_UN { pub sun_family: ADDRESS_FAMILY, pub sun_path: [i8; 108], } -impl Copy for SOCKADDR_UN {} -impl Clone for SOCKADDR_UN { - fn clone(&self) -> Self { - *self - } -} pub type SOCKET = usize; pub const SOCKET_ERROR: i32 = -1i32; pub const SOCK_DGRAM: WINSOCK_SOCKET_TYPE = 2i32; @@ -3879,15 +3616,10 @@ pub const SO_RCVTIMEO: i32 = 4102i32; pub const SO_SNDTIMEO: i32 = 4101i32; pub const SPECIFIC_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 65535u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct SRWLOCK { pub Ptr: *mut core::ffi::c_void, } -impl Copy for SRWLOCK {} -impl Clone for SRWLOCK { - fn clone(&self) -> Self { - *self - } -} pub const STACK_SIZE_PARAM_IS_A_RESERVATION: THREAD_CREATION_FLAGS = 65536u32; pub const STANDARD_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 2031616u32; pub const STANDARD_RIGHTS_EXECUTE: FILE_ACCESS_RIGHTS = 131072u32; @@ -3909,17 +3641,13 @@ pub const STARTF_USESHOWWINDOW: STARTUPINFOW_FLAGS = 1u32; pub const STARTF_USESIZE: STARTUPINFOW_FLAGS = 2u32; pub const STARTF_USESTDHANDLES: STARTUPINFOW_FLAGS = 256u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct STARTUPINFOEXW { pub StartupInfo: STARTUPINFOW, pub lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST, } -impl Copy for STARTUPINFOEXW {} -impl Clone for STARTUPINFOEXW { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct STARTUPINFOW { pub cb: u32, pub lpReserved: PWSTR, @@ -3940,12 +3668,6 @@ pub struct STARTUPINFOW { pub hStdOutput: HANDLE, pub hStdError: HANDLE, } -impl Copy for STARTUPINFOW {} -impl Clone for STARTUPINFOW { - fn clone(&self) -> Self { - *self - } -} pub type STARTUPINFOW_FLAGS = u32; pub const STATUS_DELETE_PENDING: NTSTATUS = 0xC0000056_u32 as _; pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _; @@ -3964,6 +3686,7 @@ pub const SYMLINK_FLAG_RELATIVE: u32 = 1u32; pub type SYNCHRONIZATION_ACCESS_RIGHTS = u32; pub const SYNCHRONIZE: FILE_ACCESS_RIGHTS = 1048576u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct SYSTEM_INFO { pub Anonymous: SYSTEM_INFO_0, pub dwPageSize: u32, @@ -3976,34 +3699,18 @@ pub struct SYSTEM_INFO { pub wProcessorLevel: u16, pub wProcessorRevision: u16, } -impl Copy for SYSTEM_INFO {} -impl Clone for SYSTEM_INFO { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub union SYSTEM_INFO_0 { pub dwOemId: u32, pub Anonymous: SYSTEM_INFO_0_0, } -impl Copy for SYSTEM_INFO_0 {} -impl Clone for SYSTEM_INFO_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct SYSTEM_INFO_0_0 { pub wProcessorArchitecture: PROCESSOR_ARCHITECTURE, pub wReserved: u16, } -impl Copy for SYSTEM_INFO_0_0 {} -impl Clone for SYSTEM_INFO_0_0 { - fn clone(&self) -> Self { - *self - } -} pub const TCP_NODELAY: i32 = 1i32; pub const THREAD_CREATE_RUN_IMMEDIATELY: THREAD_CREATION_FLAGS = 0u32; pub const THREAD_CREATE_SUSPENDED: THREAD_CREATION_FLAGS = 4u32; @@ -4011,16 +3718,11 @@ pub type THREAD_CREATION_FLAGS = u32; pub const TIMER_ALL_ACCESS: SYNCHRONIZATION_ACCESS_RIGHTS = 2031619u32; pub const TIMER_MODIFY_STATE: SYNCHRONIZATION_ACCESS_RIGHTS = 2u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct TIMEVAL { pub tv_sec: i32, pub tv_usec: i32, } -impl Copy for TIMEVAL {} -impl Clone for TIMEVAL { - fn clone(&self) -> Self { - *self - } -} pub const TLS_OUT_OF_INDEXES: u32 = 4294967295u32; pub type TOKEN_ACCESS_MASK = u32; pub const TOKEN_ACCESS_PSEUDO_HANDLE: TOKEN_ACCESS_MASK = 24u32; @@ -4047,17 +3749,12 @@ pub const TOKEN_WRITE_OWNER: TOKEN_ACCESS_MASK = 524288u32; pub const TRUE: BOOL = 1i32; pub const TRUNCATE_EXISTING: FILE_CREATION_DISPOSITION = 5u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct UNICODE_STRING { pub Length: u16, pub MaximumLength: u16, pub Buffer: PWSTR, } -impl Copy for UNICODE_STRING {} -impl Clone for UNICODE_STRING { - fn clone(&self) -> Self { - *self - } -} pub const VOLUME_NAME_DOS: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32; pub const VOLUME_NAME_GUID: GETFINALPATHNAMEBYHANDLE_FLAGS = 1u32; pub const VOLUME_NAME_NONE: GETFINALPATHNAMEBYHANDLE_FLAGS = 4u32; @@ -4071,6 +3768,7 @@ pub const WAIT_TIMEOUT: WAIT_EVENT = 258u32; pub const WC_ERR_INVALID_CHARS: u32 = 128u32; pub type WIN32_ERROR = u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct WIN32_FIND_DATAW { pub dwFileAttributes: u32, pub ftCreationTime: FILETIME, @@ -4083,30 +3781,20 @@ pub struct WIN32_FIND_DATAW { pub cFileName: [u16; 260], pub cAlternateFileName: [u16; 14], } -impl Copy for WIN32_FIND_DATAW {} -impl Clone for WIN32_FIND_DATAW { - fn clone(&self) -> Self { - *self - } -} pub type WINSOCK_SHUTDOWN_HOW = i32; pub type WINSOCK_SOCKET_TYPE = i32; pub const WRITE_DAC: FILE_ACCESS_RIGHTS = 262144u32; pub const WRITE_OWNER: FILE_ACCESS_RIGHTS = 524288u32; pub const WSABASEERR: WSA_ERROR = 10000i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct WSABUF { pub len: u32, pub buf: PSTR, } -impl Copy for WSABUF {} -impl Clone for WSABUF { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +#[derive(Clone, Copy)] pub struct WSADATA { pub wVersion: u16, pub wHighVersion: u16, @@ -4116,16 +3804,9 @@ pub struct WSADATA { pub szDescription: [i8; 257], pub szSystemStatus: [i8; 129], } -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] -impl Copy for WSADATA {} -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] -impl Clone for WSADATA { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "x86")] +#[derive(Clone, Copy)] pub struct WSADATA { pub wVersion: u16, pub wHighVersion: u16, @@ -4135,14 +3816,6 @@ pub struct WSADATA { pub iMaxUdpDg: u16, pub lpVendorInfo: PSTR, } -#[cfg(target_arch = "x86")] -impl Copy for WSADATA {} -#[cfg(target_arch = "x86")] -impl Clone for WSADATA { - fn clone(&self) -> Self { - *self - } -} pub const WSAEACCES: WSA_ERROR = 10013i32; pub const WSAEADDRINUSE: WSA_ERROR = 10048i32; pub const WSAEADDRNOTAVAIL: WSA_ERROR = 10049i32; @@ -4198,17 +3871,13 @@ pub const WSANOTINITIALISED: WSA_ERROR = 10093i32; pub const WSANO_DATA: WSA_ERROR = 11004i32; pub const WSANO_RECOVERY: WSA_ERROR = 11003i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct WSAPROTOCOLCHAIN { pub ChainLen: i32, pub ChainEntries: [u32; 7], } -impl Copy for WSAPROTOCOLCHAIN {} -impl Clone for WSAPROTOCOLCHAIN { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct WSAPROTOCOL_INFOW { pub dwServiceFlags1: u32, pub dwServiceFlags2: u32, @@ -4231,12 +3900,6 @@ pub struct WSAPROTOCOL_INFOW { pub dwProviderReserved: u32, pub szProtocol: [u16; 256], } -impl Copy for WSAPROTOCOL_INFOW {} -impl Clone for WSAPROTOCOL_INFOW { - fn clone(&self) -> Self { - *self - } -} pub const WSASERVICE_NOT_FOUND: WSA_ERROR = 10108i32; pub const WSASYSCALLFAILURE: WSA_ERROR = 10107i32; pub const WSASYSNOTREADY: WSA_ERROR = 10091i32; @@ -4287,6 +3950,7 @@ pub const WSA_WAIT_EVENT_0: WSA_ERROR = 0i32; pub const WSA_WAIT_IO_COMPLETION: WSA_ERROR = 192i32; #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +#[derive(Clone, Copy)] pub struct XSAVE_FORMAT { pub ControlWord: u16, pub StatusWord: u16, @@ -4305,16 +3969,9 @@ pub struct XSAVE_FORMAT { pub XmmRegisters: [M128A; 16], pub Reserved4: [u8; 96], } -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] -impl Copy for XSAVE_FORMAT {} -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] -impl Clone for XSAVE_FORMAT { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "x86")] +#[derive(Clone, Copy)] pub struct XSAVE_FORMAT { pub ControlWord: u16, pub StatusWord: u16, @@ -4333,12 +3990,4 @@ pub struct XSAVE_FORMAT { pub XmmRegisters: [M128A; 8], pub Reserved4: [u8; 224], } -#[cfg(target_arch = "x86")] -impl Copy for XSAVE_FORMAT {} -#[cfg(target_arch = "x86")] -impl Clone for XSAVE_FORMAT { - fn clone(&self) -> Self { - *self - } -} // ignore-tidy-filelength diff --git a/src/tools/generate-windows-sys/Cargo.toml b/src/tools/generate-windows-sys/Cargo.toml index 8b971d6efe7..ebf3082fb4f 100644 --- a/src/tools/generate-windows-sys/Cargo.toml +++ b/src/tools/generate-windows-sys/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies.windows-bindgen] -version = "0.56.0" +version = "0.57.0" -- cgit 1.4.1-3-g733a5 From ab0f87ec66f104c300f0a2dfd95a8e30a770155d Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Tue, 11 Jun 2024 07:45:16 +0000 Subject: Fix tests for 32 bits targets --- tests/assembly/issue-83585-small-pod-struct-equality.rs | 13 ++++++------- tests/codegen/issues/issue-109328-split_first.rs | 4 ++-- tests/codegen/issues/issue-110797-enum-jump-same.rs | 4 ++-- tests/codegen/slice-pointer-nonnull-unwrap.rs | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/assembly/issue-83585-small-pod-struct-equality.rs b/tests/assembly/issue-83585-small-pod-struct-equality.rs index 9b0d605666d..14bec1337f0 100644 --- a/tests/assembly/issue-83585-small-pod-struct-equality.rs +++ b/tests/assembly/issue-83585-small-pod-struct-equality.rs @@ -1,27 +1,26 @@ //@ assembly-output: emit-asm -//@ compile-flags:-Copt-level=3 +//@ compile-flags: -Copt-level=3 //@ only-x86_64 #![crate_type = "lib"] type T = u8; type T1 = (T, T, T, T, T, T, T, T); -type T2 = [T; 8]; // CHECK-LABEL: foo1a -// CHECK: cmp +// CHECK: cmpq // CHECK-NEXT: sete -// CHECK-NEXT: ret +// CHECK-NEXT: {{retq|popq}} #[no_mangle] pub fn foo1a(a: T1, b: T1) -> bool { a == b } // CHECK-LABEL: foo1b -// CHECK: mov -// CHECK-NEXT: cmp +// CHECK: movq +// CHECK: cmpq // CHECK-NEXT: sete -// CHECK-NEXT: ret +// CHECK-NEXT: {{retq|popq}} #[no_mangle] pub fn foo1b(a: &T1, b: &T1) -> bool { a == b diff --git a/tests/codegen/issues/issue-109328-split_first.rs b/tests/codegen/issues/issue-109328-split_first.rs index d3844c3ec20..7f7957593d2 100644 --- a/tests/codegen/issues/issue-109328-split_first.rs +++ b/tests/codegen/issues/issue-109328-split_first.rs @@ -5,8 +5,8 @@ // CHECK-LABEL: @foo // CHECK-NEXT: {{.*}}: // CHECK-NEXT: getelementptr inbounds -// CHECK-NEXT: load i64 -// CHECK-NEXT: icmp eq i64 +// CHECK-NEXT: load [[TYPE:i(32|64)]] +// CHECK-NEXT: icmp eq [[TYPE]] // CHECK-NEXT: br i1 #[no_mangle] pub fn foo(input: &mut &[u64]) -> Option { diff --git a/tests/codegen/issues/issue-110797-enum-jump-same.rs b/tests/codegen/issues/issue-110797-enum-jump-same.rs index d52faef23ad..f34b191ac70 100644 --- a/tests/codegen/issues/issue-110797-enum-jump-same.rs +++ b/tests/codegen/issues/issue-110797-enum-jump-same.rs @@ -13,8 +13,8 @@ pub enum K { // CHECK-LABEL: @get_len // CHECK-NEXT: {{.*}}: // CHECK-NEXT: getelementptr inbounds -// CHECK-NEXT: load -// CHECK-NEXT: ret i64 +// CHECK-NEXT: load [[TYPE:i(32|64)]] +// CHECK-NEXT: ret [[TYPE]] #[no_mangle] pub fn get_len(arg: &K) -> usize { match arg { diff --git a/tests/codegen/slice-pointer-nonnull-unwrap.rs b/tests/codegen/slice-pointer-nonnull-unwrap.rs index 48bf8fa88a0..2c4a959685f 100644 --- a/tests/codegen/slice-pointer-nonnull-unwrap.rs +++ b/tests/codegen/slice-pointer-nonnull-unwrap.rs @@ -6,7 +6,7 @@ use std::ptr::NonNull; // CHECK-LABEL: @slice_ptr_len_1 // CHECK-NEXT: {{.*}}: -// CHECK-NEXT: ret i64 %ptr.1 +// CHECK-NEXT: ret {{i(32|64)}} %ptr.1 #[no_mangle] pub fn slice_ptr_len_1(ptr: *const [u8]) -> usize { let ptr = ptr.cast_mut(); -- cgit 1.4.1-3-g733a5 From bb8eb44511d24b6081c15dbada56f80813d99a4c Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Tue, 11 Jun 2024 12:40:03 +0200 Subject: Unify guarantees about the default allocator `std::alloc` said that the default allocator is unspecified for all crrate types except `cdylib` and `staticlib`. Adjust `std::alloc::System` documentation to say the same. Fixes #125870. --- library/std/src/alloc.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index b98fbbf762f..dc4924cdf58 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -73,7 +73,9 @@ pub use alloc_crate::alloc::*; /// work, such as to serve alignment requests greater than the alignment /// provided directly by the backing system allocator. /// -/// This type implements the `GlobalAlloc` trait and Rust programs by default +/// This type implements the [`GlobalAlloc`] trait. Currently the default +/// global allocator is unspecified. Libraries, however, like `cdylib`s and +/// `staticlib`s are guaranteed to use the [`System`] by default and as such /// work as if they had this definition: /// /// ```rust -- cgit 1.4.1-3-g733a5 From c86b19f1ef262eeb1992a91879b38ffbed07a1a7 Mon Sep 17 00:00:00 2001 From: AurelienFT Date: Tue, 11 Jun 2024 21:56:14 +0200 Subject: Add lint to check manual pattern char comparison and merge its code with single_char_pattern lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 3 +- clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/methods/mod.rs | 35 ---- .../src/methods/path_buf_push_overwrite.rs | 2 +- .../src/methods/single_char_insert_string.rs | 5 +- clippy_lints/src/methods/single_char_pattern.rs | 64 ------ .../src/methods/single_char_push_string.rs | 5 +- clippy_lints/src/methods/utils.rs | 45 ---- .../src/misc_early/zero_prefixed_literal.rs | 4 +- clippy_lints/src/string_patterns.rs | 227 +++++++++++++++++++++ clippy_utils/src/source.rs | 45 ++++ tests/ui/manual_pattern_char_comparison.fixed | 49 +++++ tests/ui/manual_pattern_char_comparison.rs | 49 +++++ tests/ui/manual_pattern_char_comparison.stderr | 59 ++++++ tests/ui/search_is_some.rs | 1 + tests/ui/search_is_some.stderr | 16 +- 18 files changed, 451 insertions(+), 163 deletions(-) delete mode 100644 clippy_lints/src/methods/single_char_pattern.rs create mode 100644 clippy_lints/src/string_patterns.rs create mode 100644 tests/ui/manual_pattern_char_comparison.fixed create mode 100644 tests/ui/manual_pattern_char_comparison.rs create mode 100644 tests/ui/manual_pattern_char_comparison.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 711b7fb7914..d7bcd7a1968 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5532,6 +5532,7 @@ Released 2018-09-13 [`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or +[`manual_pattern_char_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains [`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index a9f2dd4499a..7e43a99e9f2 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -448,7 +448,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::SEEK_TO_START_INSTEAD_OF_REWIND_INFO, crate::methods::SHOULD_IMPLEMENT_TRAIT_INFO, crate::methods::SINGLE_CHAR_ADD_STR_INFO, - crate::methods::SINGLE_CHAR_PATTERN_INFO, crate::methods::SKIP_WHILE_NEXT_INFO, crate::methods::STABLE_SORT_PRIMITIVE_INFO, crate::methods::STRING_EXTEND_CHARS_INFO, @@ -656,6 +655,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO, crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO, crate::std_instead_of_core::STD_INSTEAD_OF_CORE_INFO, + crate::string_patterns::MANUAL_PATTERN_CHAR_COMPARISON_INFO, + crate::string_patterns::SINGLE_CHAR_PATTERN_INFO, crate::strings::STRING_ADD_INFO, crate::strings::STRING_ADD_ASSIGN_INFO, crate::strings::STRING_FROM_UTF8_AS_BYTES_INFO, diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 4ec9bd757ff..4d301daabe4 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { return; } - if is_whole && !sym_str.contains(|c| c == 'e' || c == 'E') { + if is_whole && !sym_str.contains(['e', 'E']) { // Normalize the literal by stripping the fractional portion if sym_str.split('.').next().unwrap() != float_str { // If the type suffix is missing the suggestion would be diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6946c2986f4..c65581d5203 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -326,6 +326,7 @@ mod size_of_in_element_count; mod size_of_ref; mod slow_vector_initialization; mod std_instead_of_core; +mod string_patterns; mod strings; mod strlen_on_c_strings; mod suspicious_operation_groupings; @@ -1167,6 +1168,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { ..Default::default() }) }); + store.register_late_pass(|_| Box::new(string_patterns::StringPatterns)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c3699d6341a..6200716afbe 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -94,7 +94,6 @@ mod seek_from_current; mod seek_to_start_instead_of_rewind; mod single_char_add_str; mod single_char_insert_string; -mod single_char_pattern; mod single_char_push_string; mod skip_while_next; mod stable_sort_primitive; @@ -1141,38 +1140,6 @@ declare_clippy_lint! { "not returning type containing `Self` in a `new` method" } -declare_clippy_lint! { - /// ### What it does - /// Checks for string methods that receive a single-character - /// `str` as an argument, e.g., `_.split("x")`. - /// - /// ### Why is this bad? - /// While this can make a perf difference on some systems, - /// benchmarks have proven inconclusive. But at least using a - /// char literal makes it clear that we are looking at a single - /// character. - /// - /// ### Known problems - /// Does not catch multi-byte unicode characters. This is by - /// design, on many machines, splitting by a non-ascii char is - /// actually slower. Please do your own measurements instead of - /// relying solely on the results of this lint. - /// - /// ### Example - /// ```rust,ignore - /// _.split("x"); - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// _.split('x'); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub SINGLE_CHAR_PATTERN, - pedantic, - "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" -} - declare_clippy_lint! { /// ### What it does /// Checks for calling `.step_by(0)` on iterators which panics. @@ -4169,7 +4136,6 @@ impl_lint_pass!(Methods => [ FLAT_MAP_OPTION, INEFFICIENT_TO_STRING, NEW_RET_NO_SELF, - SINGLE_CHAR_PATTERN, SINGLE_CHAR_ADD_STR, SEARCH_IS_SOME, FILTER_NEXT, @@ -4324,7 +4290,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args); single_char_add_str::check(cx, expr, receiver, args); into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver); - single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args); unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, &self.msrv); }, ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { diff --git a/clippy_lints/src/methods/path_buf_push_overwrite.rs b/clippy_lints/src/methods/path_buf_push_overwrite.rs index 04a27cc98f3..2d3007e50b8 100644 --- a/clippy_lints/src/methods/path_buf_push_overwrite.rs +++ b/clippy_lints/src/methods/path_buf_push_overwrite.rs @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t lit.span, "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition", "try", - format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')), + format!("\"{}\"", pushed_path_lit.trim_start_matches(['/', '\\'])), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index ba9ef9c84f9..e2f76ac114c 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -1,6 +1,5 @@ -use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, str_literal_to_char_literal}; use rustc_ast::BorrowKind; use rustc_errors::Applicability; use rustc_hir::{self as hir, ExprKind}; @@ -11,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `insert_str` pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability, false) { + if let Some(extension_string) = str_literal_to_char_literal(cx, &args[1], &mut applicability, false) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability); let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs deleted file mode 100644 index 982a7901c45..00000000000 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ /dev/null @@ -1,64 +0,0 @@ -use super::utils::get_hint_if_single_char_arg; -use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::LateContext; -use rustc_middle::ty; -use rustc_span::symbol::Symbol; - -use super::SINGLE_CHAR_PATTERN; - -const PATTERN_METHODS: [(&str, usize); 22] = [ - ("contains", 0), - ("starts_with", 0), - ("ends_with", 0), - ("find", 0), - ("rfind", 0), - ("split", 0), - ("split_inclusive", 0), - ("rsplit", 0), - ("split_terminator", 0), - ("rsplit_terminator", 0), - ("splitn", 1), - ("rsplitn", 1), - ("split_once", 0), - ("rsplit_once", 0), - ("matches", 0), - ("rmatches", 0), - ("match_indices", 0), - ("rmatch_indices", 0), - ("trim_start_matches", 0), - ("trim_end_matches", 0), - ("replace", 0), - ("replacen", 0), -]; - -/// lint for length-1 `str`s for methods in `PATTERN_METHODS` -pub(super) fn check( - cx: &LateContext<'_>, - _expr: &hir::Expr<'_>, - method_name: Symbol, - receiver: &hir::Expr<'_>, - args: &[hir::Expr<'_>], -) { - for &(method, pos) in &PATTERN_METHODS { - if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() - && ty.is_str() - && method_name.as_str() == method - && args.len() > pos - && let arg = &args[pos] - && let mut applicability = Applicability::MachineApplicable - && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability, true) - { - span_lint_and_sugg( - cx, - SINGLE_CHAR_PATTERN, - arg.span, - "single-character string constant used as pattern", - "consider using a `char`", - hint, - applicability, - ); - } - } -} diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index f00a5ab455e..4ae8634305d 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -1,6 +1,5 @@ -use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, str_literal_to_char_literal}; use rustc_ast::BorrowKind; use rustc_errors::Applicability; use rustc_hir::{self as hir, ExprKind}; @@ -11,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `push_str` pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability, false) { + if let Some(extension_string) = str_literal_to_char_literal(cx, &args[0], &mut applicability, false) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); let sugg = format!("{base_string_snippet}.push({extension_string})"); diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 5d58c73f8b2..0d2b0a31317 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -1,8 +1,5 @@ -use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{get_parent_expr, path_to_local_id, usage}; -use rustc_ast::ast; -use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, QPath, Stmt, StmtKind}; use rustc_lint::LateContext; @@ -49,48 +46,6 @@ pub(super) fn derefs_to_slice<'tcx>( } } -pub(super) fn get_hint_if_single_char_arg( - cx: &LateContext<'_>, - arg: &Expr<'_>, - applicability: &mut Applicability, - ascii_only: bool, -) -> Option { - if let ExprKind::Lit(lit) = &arg.kind - && let ast::LitKind::Str(r, style) = lit.node - && let string = r.as_str() - && let len = if ascii_only { - string.len() - } else { - string.chars().count() - } - && len == 1 - { - let snip = snippet_with_applicability(cx, arg.span, string, applicability); - let ch = if let ast::StrStyle::Raw(nhash) = style { - let nhash = nhash as usize; - // for raw string: r##"a"## - &snip[(nhash + 2)..(snip.len() - 1 - nhash)] - } else { - // for regular string: "a" - &snip[1..(snip.len() - 1)] - }; - - let hint = format!( - "'{}'", - match ch { - "'" => "\\'", - r"\" => "\\\\", - "\\\"" => "\"", // no need to escape `"` in `'"'` - _ => ch, - } - ); - - Some(hint) - } else { - None - } -} - /// The core logic of `check_for_loop_iter` in `unnecessary_iter_cloned.rs`, this function wraps a /// use of `CloneOrCopyVisitor`. pub(super) fn clone_or_copy_needed<'tcx>( diff --git a/clippy_lints/src/misc_early/zero_prefixed_literal.rs b/clippy_lints/src/misc_early/zero_prefixed_literal.rs index 4f9578d1b25..61f4684c9e3 100644 --- a/clippy_lints/src/misc_early/zero_prefixed_literal.rs +++ b/clippy_lints/src/misc_early/zero_prefixed_literal.rs @@ -6,7 +6,7 @@ use rustc_span::Span; use super::ZERO_PREFIXED_LITERAL; pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str) { - let trimmed_lit_snip = lit_snip.trim_start_matches(|c| c == '_' || c == '0'); + let trimmed_lit_snip = lit_snip.trim_start_matches(['_', '0']); span_lint_and_then( cx, ZERO_PREFIXED_LITERAL, @@ -20,7 +20,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str) { Applicability::MaybeIncorrect, ); // do not advise to use octal form if the literal cannot be expressed in base 8. - if !lit_snip.contains(|c| c == '8' || c == '9') { + if !lit_snip.contains(['8', '9']) { diag.span_suggestion( lit_span, "if you mean to use an octal constant, use `0o`", diff --git a/clippy_lints/src/string_patterns.rs b/clippy_lints/src/string_patterns.rs new file mode 100644 index 00000000000..64b5b8f9f27 --- /dev/null +++ b/clippy_lints/src/string_patterns.rs @@ -0,0 +1,227 @@ +use std::ops::ControlFlow; + +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::eager_or_lazy::switch_to_eager_eval; +use clippy_utils::macros::matching_root_macro_call; +use clippy_utils::path_to_local_id; +use clippy_utils::source::{snippet, str_literal_to_char_literal}; +use clippy_utils::visitors::{for_each_expr, Descend}; +use itertools::Itertools; +use rustc_ast::{BinOpKind, LitKind}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, PatKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::declare_lint_pass; +use rustc_span::{sym, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for manual `char` comparison in string patterns + /// + /// ### Why is this bad? + /// This can be written more concisely using a `char` or an array of `char`. + /// This is more readable and more optimized when comparing to only one `char`. + /// + /// ### Example + /// ```no_run + /// "Hello World!".trim_end_matches(|c| c == '.' || c == ',' || c == '!' || c == '?'); + /// ``` + /// Use instead: + /// ```no_run + /// "Hello World!".trim_end_matches(['.', ',', '!', '?']); + /// ``` + #[clippy::version = "1.80.0"] + pub MANUAL_PATTERN_CHAR_COMPARISON, + style, + "manual char comparison in string patterns" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for string methods that receive a single-character + /// `str` as an argument, e.g., `_.split("x")`. + /// + /// ### Why is this bad? + /// While this can make a perf difference on some systems, + /// benchmarks have proven inconclusive. But at least using a + /// char literal makes it clear that we are looking at a single + /// character. + /// + /// ### Known problems + /// Does not catch multi-byte unicode characters. This is by + /// design, on many machines, splitting by a non-ascii char is + /// actually slower. Please do your own measurements instead of + /// relying solely on the results of this lint. + /// + /// ### Example + /// ```rust,ignore + /// _.split("x"); + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// _.split('x'); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub SINGLE_CHAR_PATTERN, + pedantic, + "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" +} + +declare_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]); + +const PATTERN_METHODS: [(&str, usize); 22] = [ + ("contains", 0), + ("starts_with", 0), + ("ends_with", 0), + ("find", 0), + ("rfind", 0), + ("split", 0), + ("split_inclusive", 0), + ("rsplit", 0), + ("split_terminator", 0), + ("rsplit_terminator", 0), + ("splitn", 1), + ("rsplitn", 1), + ("split_once", 0), + ("rsplit_once", 0), + ("matches", 0), + ("rmatches", 0), + ("match_indices", 0), + ("rmatch_indices", 0), + ("trim_start_matches", 0), + ("trim_end_matches", 0), + ("replace", 0), + ("replacen", 0), +]; + +fn check_single_char_pattern_lint(cx: &LateContext<'_>, arg: &Expr<'_>) { + let mut applicability = Applicability::MachineApplicable; + if let Some(hint) = str_literal_to_char_literal(cx, arg, &mut applicability, true) { + span_lint_and_sugg( + cx, + SINGLE_CHAR_PATTERN, + arg.span, + "single-character string constant used as pattern", + "consider using a `char`", + hint, + applicability, + ); + } +} + +fn get_char_span<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { + if cx.typeck_results().expr_ty_adjusted(expr).is_char() + && !expr.span.from_expansion() + && switch_to_eager_eval(cx, expr) + { + Some(expr.span) + } else { + None + } +} + +fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>) { + if let ExprKind::Closure(closure) = method_arg.kind + && let body = cx.tcx.hir().body(closure.body) + && let Some(PatKind::Binding(_, binding, ..)) = body.params.first().map(|p| p.pat.kind) + { + let mut set_char_spans: Vec = Vec::new(); + + // We want to retrieve all the comparisons done. + // They are ordered in a nested way and so we need to traverse the AST to collect them all. + if for_each_expr(cx, body.value, |sub_expr| -> ControlFlow<(), Descend> { + match sub_expr.kind { + ExprKind::Binary(op, left, right) if op.node == BinOpKind::Eq => { + if path_to_local_id(left, binding) + && let Some(span) = get_char_span(cx, right) + { + set_char_spans.push(span); + ControlFlow::Continue(Descend::No) + } else if path_to_local_id(right, binding) + && let Some(span) = get_char_span(cx, left) + { + set_char_spans.push(span); + ControlFlow::Continue(Descend::No) + } else { + ControlFlow::Break(()) + } + }, + ExprKind::Binary(op, _, _) if op.node == BinOpKind::Or => ControlFlow::Continue(Descend::Yes), + ExprKind::Match(match_value, [arm, _], _) => { + if matching_root_macro_call(cx, sub_expr.span, sym::matches_macro).is_none() + || arm.guard.is_some() + || !path_to_local_id(match_value, binding) + { + return ControlFlow::Break(()); + } + if arm.pat.walk_short(|pat| match pat.kind { + PatKind::Lit(expr) if let ExprKind::Lit(lit) = expr.kind => { + if let LitKind::Char(_) = lit.node { + set_char_spans.push(lit.span); + } + true + }, + PatKind::Or(_) => true, + _ => false, + }) { + ControlFlow::Continue(Descend::No) + } else { + ControlFlow::Break(()) + } + }, + _ => ControlFlow::Break(()), + } + }) + .is_some() + { + return; + } + span_lint_and_then( + cx, + MANUAL_PATTERN_CHAR_COMPARISON, + method_arg.span, + "this manual char comparison can be written more succinctly", + |diag| { + if let [set_char_span] = set_char_spans[..] { + diag.span_suggestion( + method_arg.span, + "consider using a `char`", + snippet(cx, set_char_span, "c"), + Applicability::MachineApplicable, + ); + } else { + diag.span_suggestion( + method_arg.span, + "consider using an array of `char`", + format!( + "[{}]", + set_char_spans.into_iter().map(|span| snippet(cx, span, "c")).join(", ") + ), + Applicability::MachineApplicable, + ); + } + }, + ); + } +} + +impl<'tcx> LateLintPass<'tcx> for StringPatterns { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if !expr.span.from_expansion() + && let ExprKind::MethodCall(method, receiver, args, _) = expr.kind + && let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() + && ty.is_str() + && let method_name = method.ident.name.as_str() + && let Some(&(_, pos)) = PATTERN_METHODS + .iter() + .find(|(array_method_name, _)| *array_method_name == method_name) + && let Some(arg) = args.get(pos) + { + check_single_char_pattern_lint(cx, arg); + + check_manual_pattern_char_comparison(cx, arg); + } + } +} diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 69f593fe04a..b7ff7ebe910 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -2,6 +2,7 @@ #![allow(clippy::module_name_repetitions)] +use rustc_ast::{LitKind, StrStyle}; use rustc_data_structures::sync::Lrc; use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; @@ -500,6 +501,50 @@ pub fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span { extended.with_lo(extended.lo() - BytePos(1)) } +/// Converts `expr` to a `char` literal if it's a `str` literal containing a single +/// character (or a single byte with `ascii_only`) +pub fn str_literal_to_char_literal( + cx: &LateContext<'_>, + expr: &Expr<'_>, + applicability: &mut Applicability, + ascii_only: bool, +) -> Option { + if let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Str(r, style) = lit.node + && let string = r.as_str() + && let len = if ascii_only { + string.len() + } else { + string.chars().count() + } + && len == 1 + { + let snip = snippet_with_applicability(cx, expr.span, string, applicability); + let ch = if let StrStyle::Raw(nhash) = style { + let nhash = nhash as usize; + // for raw string: r##"a"## + &snip[(nhash + 2)..(snip.len() - 1 - nhash)] + } else { + // for regular string: "a" + &snip[1..(snip.len() - 1)] + }; + + let hint = format!( + "'{}'", + match ch { + "'" => "\\'", + r"\" => "\\\\", + "\\\"" => "\"", // no need to escape `"` in `'"'` + _ => ch, + } + ); + + Some(hint) + } else { + None + } +} + #[cfg(test)] mod test { use super::{reindent_multiline, without_block_comments}; diff --git a/tests/ui/manual_pattern_char_comparison.fixed b/tests/ui/manual_pattern_char_comparison.fixed new file mode 100644 index 00000000000..588226b87e8 --- /dev/null +++ b/tests/ui/manual_pattern_char_comparison.fixed @@ -0,0 +1,49 @@ +#![warn(clippy::manual_pattern_char_comparison)] + +struct NotStr; + +impl NotStr { + fn find(&self, _: impl FnMut(char) -> bool) {} +} + +fn main() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(['.', ',', '!', '?']); + sentence.split(['\n', 'X']); + sentence.split(['\n', 'X']); + sentence.splitn(3, 'X'); + sentence.splitn(3, |c: char| c.is_whitespace() || c == 'X'); + let char_compare = 'X'; + sentence.splitn(3, char_compare); + sentence.split(['\n', 'X', 'Y']); + sentence.splitn(3, 'X'); + sentence.splitn(3, ['X', 'W']); + sentence.find('🎈'); + + let not_str = NotStr; + not_str.find(|c: char| c == 'X'); + + "".find(|c| c == 'a' || c > 'z'); + + let x = true; + "".find(|c| c == 'a' || x || c == 'b'); + + let d = 'd'; + "".find(|c| c == 'a' || d == 'b'); + + "".find(|c| match c { + 'a' | 'b' => true, + _ => c.is_ascii(), + }); + + "".find(|c| matches!(c, 'a' | 'b' if false)); + + "".find(|c| matches!(c, 'a' | '1'..'4')); + "".find(|c| c == 'a' || matches!(c, '1'..'4')); + macro_rules! m { + ($e:expr) => { + $e == '?' + }; + } + "".find(|c| m!(c)); +} diff --git a/tests/ui/manual_pattern_char_comparison.rs b/tests/ui/manual_pattern_char_comparison.rs new file mode 100644 index 00000000000..5078f3ee27f --- /dev/null +++ b/tests/ui/manual_pattern_char_comparison.rs @@ -0,0 +1,49 @@ +#![warn(clippy::manual_pattern_char_comparison)] + +struct NotStr; + +impl NotStr { + fn find(&self, _: impl FnMut(char) -> bool) {} +} + +fn main() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); + sentence.split(|c: char| c == '\n' || c == 'X'); + sentence.split(|c| c == '\n' || c == 'X'); + sentence.splitn(3, |c: char| c == 'X'); + sentence.splitn(3, |c: char| c.is_whitespace() || c == 'X'); + let char_compare = 'X'; + sentence.splitn(3, |c: char| c == char_compare); + sentence.split(|c: char| matches!(c, '\n' | 'X' | 'Y')); + sentence.splitn(3, |c: char| matches!(c, 'X')); + sentence.splitn(3, |c: char| matches!(c, 'X' | 'W')); + sentence.find(|c| c == '🎈'); + + let not_str = NotStr; + not_str.find(|c: char| c == 'X'); + + "".find(|c| c == 'a' || c > 'z'); + + let x = true; + "".find(|c| c == 'a' || x || c == 'b'); + + let d = 'd'; + "".find(|c| c == 'a' || d == 'b'); + + "".find(|c| match c { + 'a' | 'b' => true, + _ => c.is_ascii(), + }); + + "".find(|c| matches!(c, 'a' | 'b' if false)); + + "".find(|c| matches!(c, 'a' | '1'..'4')); + "".find(|c| c == 'a' || matches!(c, '1'..'4')); + macro_rules! m { + ($e:expr) => { + $e == '?' + }; + } + "".find(|c| m!(c)); +} diff --git a/tests/ui/manual_pattern_char_comparison.stderr b/tests/ui/manual_pattern_char_comparison.stderr new file mode 100644 index 00000000000..b6b51794a11 --- /dev/null +++ b/tests/ui/manual_pattern_char_comparison.stderr @@ -0,0 +1,59 @@ +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:11:31 + | +LL | sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['.', ',', '!', '?']` + | + = note: `-D clippy::manual-pattern-char-comparison` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_pattern_char_comparison)]` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:12:20 + | +LL | sentence.split(|c: char| c == '\n' || c == 'X'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['\n', 'X']` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:13:20 + | +LL | sentence.split(|c| c == '\n' || c == 'X'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['\n', 'X']` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:14:24 + | +LL | sentence.splitn(3, |c: char| c == 'X'); + | ^^^^^^^^^^^^^^^^^^ help: consider using a `char`: `'X'` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:17:24 + | +LL | sentence.splitn(3, |c: char| c == char_compare); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a `char`: `char_compare` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:18:20 + | +LL | sentence.split(|c: char| matches!(c, '\n' | 'X' | 'Y')); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['\n', 'X', 'Y']` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:19:24 + | +LL | sentence.splitn(3, |c: char| matches!(c, 'X')); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a `char`: `'X'` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:20:24 + | +LL | sentence.splitn(3, |c: char| matches!(c, 'X' | 'W')); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['X', 'W']` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:21:19 + | +LL | sentence.find(|c| c == '🎈'); + | ^^^^^^^^^^^^^ help: consider using a `char`: `'🎈'` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/search_is_some.rs b/tests/ui/search_is_some.rs index e8a0920b645..9a9aaba56ad 100644 --- a/tests/ui/search_is_some.rs +++ b/tests/ui/search_is_some.rs @@ -1,5 +1,6 @@ //@aux-build:option_helpers.rs #![warn(clippy::search_is_some)] +#![allow(clippy::manual_pattern_char_comparison)] #![allow(clippy::useless_vec)] #![allow(dead_code)] extern crate option_helpers; diff --git a/tests/ui/search_is_some.stderr b/tests/ui/search_is_some.stderr index b5f84d23284..b5ef5534177 100644 --- a/tests/ui/search_is_some.stderr +++ b/tests/ui/search_is_some.stderr @@ -1,5 +1,5 @@ error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:15:13 + --> tests/ui/search_is_some.rs:16:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -13,7 +13,7 @@ LL | | ).is_some(); = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` error: called `is_some()` after searching an `Iterator` with `position` - --> tests/ui/search_is_some.rs:21:13 + --> tests/ui/search_is_some.rs:22:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -25,7 +25,7 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `rposition` - --> tests/ui/search_is_some.rs:27:13 + --> tests/ui/search_is_some.rs:28:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -37,13 +37,13 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:42:20 + --> tests/ui/search_is_some.rs:43:20 | LL | let _ = (0..1).find(some_closure).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(some_closure)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:52:13 + --> tests/ui/search_is_some.rs:53:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -55,7 +55,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `position` - --> tests/ui/search_is_some.rs:58:13 + --> tests/ui/search_is_some.rs:59:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -67,7 +67,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `rposition` - --> tests/ui/search_is_some.rs:64:13 + --> tests/ui/search_is_some.rs:65:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -79,7 +79,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:79:13 + --> tests/ui/search_is_some.rs:80:13 | LL | let _ = (0..1).find(some_closure).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(0..1).any(some_closure)` -- cgit 1.4.1-3-g733a5 From cc37e3c1828a3033c116f239a6540e1bf5fad96d Mon Sep 17 00:00:00 2001 From: "许杰友 Jieyou Xu (Joe)" Date: Sun, 9 Jun 2024 16:26:25 +0000 Subject: compiletest: compile rmake.rs with -Dunused_must_use --- src/tools/compiletest/src/runtest.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index dbe016b8305..cc15961b46e 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3551,6 +3551,10 @@ impl<'test> TestCx<'test> { .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) .env("LLVM_COMPONENTS", &self.config.llvm_components); + // In test code we want to be very pedantic about values being silently discarded that are + // annotated with `#[must_use]`. + cmd.arg("-Dunused_must_use"); + if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() { let mut stage0_sysroot = build_root.clone(); stage0_sysroot.push("stage0-sysroot"); -- cgit 1.4.1-3-g733a5 From 43afafcdb37d5a47d6b4139175bb667ade0d6784 Mon Sep 17 00:00:00 2001 From: "许杰友 Jieyou Xu (Joe)" Date: Tue, 11 Jun 2024 21:02:54 +0000 Subject: run-make-support: add #[must_use] annotations --- src/tools/run-make-support/src/cc.rs | 1 + src/tools/run-make-support/src/clang.rs | 1 + src/tools/run-make-support/src/command.rs | 3 +++ src/tools/run-make-support/src/diff/mod.rs | 1 + src/tools/run-make-support/src/lib.rs | 17 +++++++++++++++++ src/tools/run-make-support/src/llvm_readobj.rs | 1 + src/tools/run-make-support/src/rustc.rs | 1 + src/tools/run-make-support/src/rustdoc.rs | 1 + 8 files changed, 26 insertions(+) diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/cc.rs index 8694740cfc3..31b9e8a23b8 100644 --- a/src/tools/run-make-support/src/cc.rs +++ b/src/tools/run-make-support/src/cc.rs @@ -15,6 +15,7 @@ pub fn cc() -> Cc { /// A platform-specific C compiler invocation builder. The specific C compiler used is /// passed down from compiletest. #[derive(Debug)] +#[must_use] pub struct Cc { cmd: Command, } diff --git a/src/tools/run-make-support/src/clang.rs b/src/tools/run-make-support/src/clang.rs index a31004659c1..c23e41ebe21 100644 --- a/src/tools/run-make-support/src/clang.rs +++ b/src/tools/run-make-support/src/clang.rs @@ -11,6 +11,7 @@ pub fn clang() -> Clang { /// A `clang` invocation builder. #[derive(Debug)] +#[must_use] pub struct Clang { cmd: Command, } diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index d689dc2f979..7cbc61bdf33 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -148,14 +148,17 @@ pub struct CompletedProcess { } impl CompletedProcess { + #[must_use] pub fn stdout_utf8(&self) -> String { String::from_utf8(self.output.stdout.clone()).expect("stdout is not valid UTF-8") } + #[must_use] pub fn stderr_utf8(&self) -> String { String::from_utf8(self.output.stderr.clone()).expect("stderr is not valid UTF-8") } + #[must_use] pub fn status(&self) -> ExitStatus { self.output.status } diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs index 0fb6fec9d58..105cdbc7b32 100644 --- a/src/tools/run-make-support/src/diff/mod.rs +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -13,6 +13,7 @@ pub fn diff() -> Diff { } #[derive(Debug)] +#[must_use] pub struct Diff { expected: Option, expected_name: Option, diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index b920f9a07db..9f8cd3bea7c 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -35,6 +35,7 @@ pub use rustc::{aux_build, rustc, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; #[track_caller] +#[must_use] pub fn env_var(name: &str) -> String { match env::var(name) { Ok(v) => v, @@ -43,6 +44,7 @@ pub fn env_var(name: &str) -> String { } #[track_caller] +#[must_use] pub fn env_var_os(name: &str) -> OsString { match env::var_os(name) { Some(v) => v, @@ -51,32 +53,38 @@ pub fn env_var_os(name: &str) -> OsString { } /// `TARGET` +#[must_use] pub fn target() -> String { env_var("TARGET") } /// Check if target is windows-like. +#[must_use] pub fn is_windows() -> bool { target().contains("windows") } /// Check if target uses msvc. +#[must_use] pub fn is_msvc() -> bool { target().contains("msvc") } /// Check if target uses macOS. +#[must_use] pub fn is_darwin() -> bool { target().contains("darwin") } #[track_caller] +#[must_use] pub fn python_command() -> Command { let python_path = env_var("PYTHON"); Command::new(python_path) } #[track_caller] +#[must_use] pub fn htmldocck() -> Command { let mut python = python_command(); python.arg(source_root().join("src/etc/htmldocck.py")); @@ -89,11 +97,13 @@ pub fn path>(p: P) -> PathBuf { } /// Path to the root rust-lang/rust source checkout. +#[must_use] pub fn source_root() -> PathBuf { env_var("SOURCE_ROOT").into() } /// Construct the static library name based on the platform. +#[must_use] pub fn static_lib_name(name: &str) -> String { // See tools.mk (irrelevant lines omitted): // @@ -118,6 +128,7 @@ pub fn static_lib_name(name: &str) -> String { } /// Construct the dynamic library name based on the platform. +#[must_use] pub fn dynamic_lib_name(name: &str) -> String { // See tools.mk (irrelevant lines omitted): // @@ -144,6 +155,7 @@ pub fn dynamic_lib_name(name: &str) -> String { } } +#[must_use] pub fn dynamic_lib_extension() -> &'static str { if is_darwin() { "dylib" @@ -155,16 +167,19 @@ pub fn dynamic_lib_extension() -> &'static str { } /// Generate the name a rust library (rlib) would have. +#[must_use] pub fn rust_lib_name(name: &str) -> String { format!("lib{name}.rlib") } /// Construct the binary name based on platform. +#[must_use] pub fn bin_name(name: &str) -> String { if is_windows() { format!("{name}.exe") } else { name.to_string() } } /// Return the current working directory. +#[must_use] pub fn cwd() -> PathBuf { env::current_dir().unwrap() } @@ -172,6 +187,7 @@ pub fn cwd() -> PathBuf { /// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is /// available on the platform! #[track_caller] +#[must_use] pub fn cygpath_windows>(path: P) -> String { let caller = panic::Location::caller(); let mut cygpath = Command::new("cygpath"); @@ -187,6 +203,7 @@ pub fn cygpath_windows>(path: P) -> String { /// Run `uname`. This assumes that `uname` is available on the platform! #[track_caller] +#[must_use] pub fn uname() -> String { let caller = panic::Location::caller(); let mut uname = Command::new("uname"); diff --git a/src/tools/run-make-support/src/llvm_readobj.rs b/src/tools/run-make-support/src/llvm_readobj.rs index 57ddfc205e6..3c719356e8f 100644 --- a/src/tools/run-make-support/src/llvm_readobj.rs +++ b/src/tools/run-make-support/src/llvm_readobj.rs @@ -12,6 +12,7 @@ pub fn llvm_readobj() -> LlvmReadobj { /// A `llvm-readobj` invocation builder. #[derive(Debug)] +#[must_use] pub struct LlvmReadobj { cmd: Command, } diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 32fa5018d80..39950f43176 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -18,6 +18,7 @@ pub fn aux_build() -> Rustc { /// A `rustc` invocation builder. #[derive(Debug)] +#[must_use] pub struct Rustc { cmd: Command, } diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs index 332906f739a..93078561254 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -17,6 +17,7 @@ pub fn rustdoc() -> Rustdoc { } #[derive(Debug)] +#[must_use] pub struct Rustdoc { cmd: Command, } -- cgit 1.4.1-3-g733a5 -- cgit 1.4.1-3-g733a5 From f6ab5e997cc8afa1d4a2910ab5db0e529e773fbc Mon Sep 17 00:00:00 2001 From: "许杰友 Jieyou Xu (Joe)" Date: Sun, 9 Jun 2024 16:29:14 +0000 Subject: run-make-support: bump version --- Cargo.lock | 2 +- src/tools/run-make-support/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5ea9fee8a6..9d3eada2810 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3452,7 +3452,7 @@ dependencies = [ [[package]] name = "run_make_support" -version = "0.1.0" +version = "0.2.0" dependencies = [ "gimli 0.28.1", "object 0.34.0", diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 5450620e7f0..2f7f51442f1 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "run_make_support" -version = "0.1.0" +version = "0.2.0" edition = "2021" [dependencies] -- cgit 1.4.1-3-g733a5 From 5b126ed35857154274fe7f2e69c19b7c74a5fc30 Mon Sep 17 00:00:00 2001 From: "许杰友 Jieyou Xu (Joe)" Date: Sun, 9 Jun 2024 16:27:15 +0000 Subject: run-make-support: update changelog --- src/tools/run-make-support/CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/tools/run-make-support/CHANGELOG.md b/src/tools/run-make-support/CHANGELOG.md index a37de9fda80..c1b7b618a92 100644 --- a/src/tools/run-make-support/CHANGELOG.md +++ b/src/tools/run-make-support/CHANGELOG.md @@ -10,6 +10,22 @@ changes to the support library). This support library will probably never reach 1.0. Please bump the minor version in `Cargo.toml` if you make any breaking changes or other significant changes, or bump the patch version for bug fixes. +## [0.2.0] - 2024-06-11 + +### Added + +- Added `fs_wrapper` module which provides panic-on-fail helpers for their respective `std::fs` + counterparts, the motivation is to: + - Reduce littering `.unwrap()` or `.expect()` everywhere for fs operations + - Help the test writer avoid forgetting to check fs results (even though enforced by + `-Dunused_must_use`) + - Provide better panic messages by default +- Added `path()` helper which creates a `Path` relative to `cwd()` (but is less noisy). + +### Changed + +- Marked many functions with `#[must_use]`, and rmake.rs are now compiled with `-Dunused_must_use`. + ## [0.1.0] - 2024-06-09 ### Changed -- cgit 1.4.1-3-g733a5 From 27ecb71635f0a168d8827fb4efc33b122c291e9c Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Tue, 11 Jun 2024 15:16:47 -0700 Subject: `UniqueRc`: support allocators and `T: ?Sized`. Added the following (all unstable): * Defaulted type pararameter `A: Allocator`. * `UniqueRc::new_in()`. * `T: ?Sized` where possible. * `impl CoerceUnsized for UniqueRc`. * Drive-by doc polish: links and periods at the end of sentences. These changes are motivated by supporting the implementation of unsized `Rc::make_mut()` (PR #116113), but are also intended to be obvious generalizations of `UniqueRc` to support the things `Rc` does. --- library/alloc/src/rc.rs | 95 +++++++++++++++++++++++++++++-------------- library/alloc/src/rc/tests.rs | 26 ++++++++++++ 2 files changed, 91 insertions(+), 30 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index f3a4803e0d4..336fd52d92f 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -3516,7 +3516,7 @@ fn data_offset_align(align: usize) -> usize { layout.size() + layout.padding_needed_for(align) } -/// A uniquely owned `Rc` +/// A uniquely owned [`Rc`]. /// /// This represents an `Rc` that is known to be uniquely owned -- that is, have exactly one strong /// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong @@ -3554,13 +3554,24 @@ fn data_offset_align(align: usize) -> usize { /// including fallible or async constructors. #[unstable(feature = "unique_rc_arc", issue = "112566")] #[derive(Debug)] -pub struct UniqueRc { +pub struct UniqueRc< + T: ?Sized, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { ptr: NonNull>, phantom: PhantomData>, + alloc: A, } +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl, U: ?Sized, A: Allocator> CoerceUnsized> + for UniqueRc +{ +} + +// Depends on A = Global impl UniqueRc { - /// Creates a new `UniqueRc` + /// Creates a new `UniqueRc`. /// /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. @@ -3569,34 +3580,36 @@ impl UniqueRc { #[cfg(not(no_global_oom_handling))] #[unstable(feature = "unique_rc_arc", issue = "112566")] pub fn new(value: T) -> Self { - Self { - ptr: Box::leak(Box::new(RcBox { + Self::new_in(value, Global) + } +} + +impl UniqueRc { + /// Creates a new `UniqueRc` in the provided allocator. + /// + /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. + /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will + /// point to the new [`Rc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn new_in(value: T, alloc: A) -> Self { + let (ptr, alloc) = Box::into_unique(Box::new_in( + RcBox { strong: Cell::new(0), // keep one weak reference so if all the weak pointers that are created are dropped // the UniqueRc still stays valid. weak: Cell::new(1), value, - })) - .into(), - phantom: PhantomData, - } - } - - /// Creates a new weak reference to the `UniqueRc` - /// - /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted - /// to a [`Rc`] using [`UniqueRc::into_rc`]. - #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn downgrade(this: &Self) -> Weak { - // SAFETY: This pointer was allocated at creation time and we guarantee that we only have - // one strong reference before converting to a regular Rc. - unsafe { - this.ptr.as_ref().inc_weak(); - } - Weak { ptr: this.ptr, alloc: Global } + }, + alloc, + )); + Self { ptr: ptr.into(), phantom: PhantomData, alloc } } +} - /// Converts the `UniqueRc` into a regular [`Rc`] +impl UniqueRc { + /// Converts the `UniqueRc` into a regular [`Rc`]. /// /// This consumes the `UniqueRc` and returns a regular [`Rc`] that contains the `value` that /// is passed to `into_rc`. @@ -3604,19 +3617,41 @@ impl UniqueRc { /// Any weak references created before this method is called can now be upgraded to strong /// references. #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn into_rc(this: Self) -> Rc { + pub fn into_rc(this: Self) -> Rc { let mut this = ManuallyDrop::new(this); + + // Move the allocator out. + // SAFETY: `this.alloc` will not be accessed again, nor dropped because it is in + // a `ManuallyDrop`. + let alloc: A = unsafe { ptr::read(&this.alloc) }; + // SAFETY: This pointer was allocated at creation time so we know it is valid. unsafe { // Convert our weak reference into a strong reference this.ptr.as_mut().strong.set(1); - Rc::from_inner(this.ptr) + Rc::from_inner_in(this.ptr, alloc) + } + } +} + +impl UniqueRc { + /// Creates a new weak reference to the `UniqueRc`. + /// + /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted + /// to a [`Rc`] using [`UniqueRc::into_rc`]. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn downgrade(this: &Self) -> Weak { + // SAFETY: This pointer was allocated at creation time and we guarantee that we only have + // one strong reference before converting to a regular Rc. + unsafe { + this.ptr.as_ref().inc_weak(); } + Weak { ptr: this.ptr, alloc: this.alloc.clone() } } } #[unstable(feature = "unique_rc_arc", issue = "112566")] -impl Deref for UniqueRc { +impl Deref for UniqueRc { type Target = T; fn deref(&self) -> &T { @@ -3626,7 +3661,7 @@ impl Deref for UniqueRc { } #[unstable(feature = "unique_rc_arc", issue = "112566")] -impl DerefMut for UniqueRc { +impl DerefMut for UniqueRc { fn deref_mut(&mut self) -> &mut T { // SAFETY: This pointer was allocated at creation time so we know it is valid. We know we // have unique ownership and therefore it's safe to make a mutable reference because @@ -3636,7 +3671,7 @@ impl DerefMut for UniqueRc { } #[unstable(feature = "unique_rc_arc", issue = "112566")] -unsafe impl<#[may_dangle] T> Drop for UniqueRc { +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc { fn drop(&mut self) { unsafe { // destroy the contained object @@ -3646,7 +3681,7 @@ unsafe impl<#[may_dangle] T> Drop for UniqueRc { self.ptr.as_ref().dec_weak(); if self.ptr.as_ref().weak() == 0 { - Global.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); + self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); } } } diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index c8a40603d9d..0f09be7721f 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -606,6 +606,23 @@ fn test_unique_rc_drops_contents() { assert!(dropped); } +/// Exercise the non-default allocator usage. +#[test] +fn test_unique_rc_with_alloc_drops_contents() { + let mut dropped = false; + struct DropMe<'a>(&'a mut bool); + impl Drop for DropMe<'_> { + fn drop(&mut self) { + *self.0 = true; + } + } + { + let rc = UniqueRc::new_in(DropMe(&mut dropped), std::alloc::System); + drop(rc); + } + assert!(dropped); +} + #[test] fn test_unique_rc_weak_clone_holding_ref() { let mut v = UniqueRc::new(0u8); @@ -614,3 +631,12 @@ fn test_unique_rc_weak_clone_holding_ref() { let _ = w.clone(); // touch weak count *r = 123; } + +#[test] +fn test_unique_rc_unsizing_coercion() { + let mut rc: UniqueRc<[u8]> = UniqueRc::new([0u8; 3]); + assert_eq!(rc.len(), 3); + rc[0] = 123; + let rc: Rc<[u8]> = UniqueRc::into_rc(rc); + assert_eq!(*rc, [123, 0, 0]); +} -- cgit 1.4.1-3-g733a5 From 17a7ab73e32b1974e56f84173610540194c8ee9f Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 12 Jun 2024 11:36:55 +0300 Subject: unify git command preperation Due to https://github.com/rust-lang/rust/issues/125954, we had to modify git invocations with certain flags in https://github.com/rust-lang/rust/pull/126255. However, because there are so many instances of `Command::new("git")` in bootstrap, it is difficult to apply these solutions to all of them. This PR creates a helper function that unifies the git usage in bootstrap. Meaning, whenever special flags or hacks are needed, we can apply them to this single function which makes things much simpler for the bootstrap team. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/format.rs | 12 ++--- src/bootstrap/src/core/build_steps/llvm.rs | 4 +- src/bootstrap/src/core/build_steps/setup.rs | 13 +++--- src/bootstrap/src/core/build_steps/toolstate.rs | 29 +++++------- src/bootstrap/src/core/config/config.rs | 30 +++++-------- src/bootstrap/src/lib.rs | 60 +++++++++++-------------- src/bootstrap/src/utils/channel.rs | 15 +++---- src/bootstrap/src/utils/helpers.rs | 16 +++++++ 8 files changed, 84 insertions(+), 95 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 0caa39d78ac..4608600bdf2 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -1,7 +1,7 @@ //! Runs rustfmt on the repository. use crate::core::builder::Builder; -use crate::utils::helpers::{output, program_out_of_date, t}; +use crate::utils::helpers::{self, output, program_out_of_date, t}; use build_helper::ci::CiEnv; use build_helper::git::get_git_modified_files; use ignore::WalkBuilder; @@ -160,7 +160,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { override_builder.add(&format!("!{ignore}")).expect(&ignore); } } - let git_available = match Command::new("git") + let git_available = match helpers::git(None) .arg("--version") .stdout(Stdio::null()) .stderr(Stdio::null()) @@ -172,9 +172,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { let mut adjective = None; if git_available { - let in_working_tree = match build - .config - .git() + let in_working_tree = match helpers::git(Some(&build.src)) .arg("rev-parse") .arg("--is-inside-work-tree") .stdout(Stdio::null()) @@ -186,9 +184,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { }; if in_working_tree { let untracked_paths_output = output( - build - .config - .git() + helpers::git(Some(&build.src)) .arg("status") .arg("--porcelain") .arg("-z") diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 8ca7af2febe..e7dc981bb09 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -159,7 +159,7 @@ pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String { // in that case. let closest_upstream = get_git_merge_base(&config.git_config(), Some(&config.src)) .unwrap_or_else(|_| "HEAD".into()); - let mut rev_list = config.git(); + let mut rev_list = helpers::git(Some(&config.src)); rev_list.args(&[ PathBuf::from("rev-list"), format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(), @@ -252,7 +252,7 @@ pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { // We assume we have access to git, so it's okay to unconditionally pass // `true` here. let llvm_sha = detect_llvm_sha(config, true); - let head_sha = output(config.git().arg("rev-parse").arg("HEAD")); + let head_sha = output(helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD")); let head_sha = head_sha.trim(); llvm_sha == head_sha } diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index df38d6166eb..947c74f32c9 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -8,7 +8,7 @@ use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::t; use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY; -use crate::utils::helpers::hex_encode; +use crate::utils::helpers::{self, hex_encode}; use crate::Config; use sha2::Digest; use std::env::consts::EXE_SUFFIX; @@ -482,10 +482,13 @@ impl Step for Hook { // install a git hook to automatically run tidy, if they want fn install_git_hook_maybe(config: &Config) -> io::Result<()> { - let git = config.git().args(["rev-parse", "--git-common-dir"]).output().map(|output| { - assert!(output.status.success(), "failed to run `git`"); - PathBuf::from(t!(String::from_utf8(output.stdout)).trim()) - })?; + let git = helpers::git(Some(&config.src)) + .args(["rev-parse", "--git-common-dir"]) + .output() + .map(|output| { + assert!(output.status.success(), "failed to run `git`"); + PathBuf::from(t!(String::from_utf8(output.stdout)).trim()) + })?; let hooks_dir = git.join("hooks"); let dst = hooks_dir.join("pre-push"); if dst.exists() { diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs index ca3756df4d7..9e6d03349b5 100644 --- a/src/bootstrap/src/core/build_steps/toolstate.rs +++ b/src/bootstrap/src/core/build_steps/toolstate.rs @@ -5,7 +5,7 @@ //! [Toolstate]: https://forge.rust-lang.org/infra/toolstate.html use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; -use crate::utils::helpers::t; +use crate::utils::helpers::{self, t}; use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; use std::env; @@ -13,7 +13,6 @@ use std::fmt; use std::fs; use std::io::{Seek, SeekFrom}; use std::path::{Path, PathBuf}; -use std::process::Command; use std::time; // Each cycle is 42 days long (6 weeks); the last week is 35..=42 then. @@ -102,12 +101,8 @@ fn print_error(tool: &str, submodule: &str) { fn check_changed_files(toolstates: &HashMap, ToolState>) { // Changed files - let output = std::process::Command::new("git") - .arg("diff") - .arg("--name-status") - .arg("HEAD") - .arg("HEAD^") - .output(); + let output = + helpers::git(None).arg("diff").arg("--name-status").arg("HEAD").arg("HEAD^").output(); let output = match output { Ok(o) => o, Err(e) => { @@ -324,7 +319,7 @@ fn checkout_toolstate_repo() { t!(fs::remove_dir_all(TOOLSTATE_DIR)); } - let status = Command::new("git") + let status = helpers::git(None) .arg("clone") .arg("--depth=1") .arg(toolstate_repo()) @@ -342,7 +337,7 @@ fn checkout_toolstate_repo() { /// Sets up config and authentication for modifying the toolstate repo. fn prepare_toolstate_config(token: &str) { fn git_config(key: &str, value: &str) { - let status = Command::new("git").arg("config").arg("--global").arg(key).arg(value).status(); + let status = helpers::git(None).arg("config").arg("--global").arg(key).arg(value).status(); let success = match status { Ok(s) => s.success(), Err(_) => false, @@ -406,8 +401,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { publish_test_results(current_toolstate); // `git commit` failing means nothing to commit. - let status = t!(Command::new("git") - .current_dir(TOOLSTATE_DIR) + let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("commit") .arg("-a") .arg("-m") @@ -418,8 +412,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { break; } - let status = t!(Command::new("git") - .current_dir(TOOLSTATE_DIR) + let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("push") .arg("origin") .arg("master") @@ -431,15 +424,13 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { } eprintln!("Sleeping for 3 seconds before retrying push"); std::thread::sleep(std::time::Duration::from_secs(3)); - let status = t!(Command::new("git") - .current_dir(TOOLSTATE_DIR) + let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("fetch") .arg("origin") .arg("master") .status()); assert!(status.success()); - let status = t!(Command::new("git") - .current_dir(TOOLSTATE_DIR) + let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("reset") .arg("--hard") .arg("origin/master") @@ -458,7 +449,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { /// `publish_toolstate.py` script if the PR passes all tests and is merged to /// master. fn publish_test_results(current_toolstate: &ToolstateData) { - let commit = t!(std::process::Command::new("git").arg("rev-parse").arg("HEAD").output()); + let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").output()); let commit = t!(String::from_utf8(commit.stdout)); let toolstate_serialized = t!(serde_json::to_string(¤t_toolstate)); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 36b44d0169c..c0871ec0981 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -20,7 +20,7 @@ use crate::core::build_steps::llvm; use crate::core::config::flags::{Color, Flags, Warnings}; use crate::utils::cache::{Interned, INTERNER}; use crate::utils::channel::{self, GitInfo}; -use crate::utils::helpers::{exe, output, t}; +use crate::utils::helpers::{self, exe, output, t}; use build_helper::exit; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -1248,7 +1248,7 @@ impl Config { // Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary, // running on a completely different machine from where it was compiled. - let mut cmd = Command::new("git"); + let mut cmd = helpers::git(None); // NOTE: we cannot support running from outside the repository because the only other path we have available // is set at compile time, which can be wrong if bootstrap was downloaded rather than compiled locally. // We still support running outside the repository if we find we aren't in a git directory. @@ -2090,15 +2090,6 @@ impl Config { build_helper::util::try_run(cmd, self.is_verbose()) } - /// A git invocation which runs inside the source directory. - /// - /// Use this rather than `Command::new("git")` in order to support out-of-tree builds. - pub(crate) fn git(&self) -> Command { - let mut git = Command::new("git"); - git.current_dir(&self.src); - git - } - pub(crate) fn test_args(&self) -> Vec<&str> { let mut test_args = match self.cmd { Subcommand::Test { ref test_args, .. } @@ -2130,7 +2121,7 @@ impl Config { "`Config::read_file_by_commit` is not supported in non-git sources." ); - let mut git = self.git(); + let mut git = helpers::git(Some(&self.src)); git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap())); output(&mut git) } @@ -2436,7 +2427,8 @@ impl Config { }; // Handle running from a directory other than the top level - let top_level = output(self.git().args(["rev-parse", "--show-toplevel"])); + let top_level = + output(helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"])); let top_level = top_level.trim_end(); let compiler = format!("{top_level}/compiler/"); let library = format!("{top_level}/library/"); @@ -2444,7 +2436,7 @@ impl Config { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( - self.git() + helpers::git(Some(&self.src)) .arg("rev-list") .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) .args(["-n1", "--first-parent", "HEAD"]), @@ -2459,8 +2451,7 @@ impl Config { } // Warn if there were changes to the compiler or standard library since the ancestor commit. - let has_changes = !t!(self - .git() + let has_changes = !t!(helpers::git(Some(&self.src)) .args(["diff-index", "--quiet", commit, "--", &compiler, &library]) .status()) .success(); @@ -2533,13 +2524,14 @@ impl Config { if_unchanged: bool, ) -> Option { // Handle running from a directory other than the top level - let top_level = output(self.git().args(["rev-parse", "--show-toplevel"])); + let top_level = + output(helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"])); let top_level = top_level.trim_end(); // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( - self.git() + helpers::git(Some(&self.src)) .arg("rev-list") .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) .args(["-n1", "--first-parent", "HEAD"]), @@ -2554,7 +2546,7 @@ impl Config { } // Warn if there were changes to the compiler or standard library since the ancestor commit. - let mut git = self.git(); + let mut git = helpers::git(Some(&self.src)); git.args(["diff-index", "--quiet", commit, "--"]); for path in modified_paths { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index cde090637e0..58704f05498 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -522,14 +522,10 @@ impl Build { // check_submodule let checked_out_hash = - output(Command::new("git").args(["rev-parse", "HEAD"]).current_dir(&absolute_path)); + output(helpers::git(Some(&absolute_path)).args(["rev-parse", "HEAD"])); // update_submodules - let recorded = output( - Command::new("git") - .args(["ls-tree", "HEAD"]) - .arg(relative_path) - .current_dir(&self.config.src), - ); + let recorded = + output(helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path)); let actual_hash = recorded .split_whitespace() .nth(2) @@ -543,10 +539,7 @@ impl Build { println!("Updating submodule {}", relative_path.display()); self.run( - Command::new("git") - .args(["submodule", "-q", "sync"]) - .arg(relative_path) - .current_dir(&self.config.src), + helpers::git(Some(&self.src)).args(["submodule", "-q", "sync"]).arg(relative_path), ); // Try passing `--progress` to start, then run git again without if that fails. @@ -554,9 +547,7 @@ impl Build { // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository, // even though that has no relation to the upstream for the submodule. let current_branch = { - let output = self - .config - .git() + let output = helpers::git(Some(&self.src)) .args(["symbolic-ref", "--short", "HEAD"]) .stderr(Stdio::inherit()) .output(); @@ -568,7 +559,7 @@ impl Build { } }; - let mut git = self.config.git(); + let mut git = helpers::git(Some(&self.src)); if let Some(branch) = current_branch { // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name. // This syntax isn't accepted by `branch.{branch}`. Strip it. @@ -590,11 +581,11 @@ impl Build { // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). // diff-index reports the modifications through the exit status let has_local_modifications = !self.run_cmd( - BootstrapCommand::from( - Command::new("git") - .args(["diff-index", "--quiet", "HEAD"]) - .current_dir(&absolute_path), - ) + BootstrapCommand::from(helpers::git(Some(&absolute_path)).args([ + "diff-index", + "--quiet", + "HEAD", + ])) .allow_failure() .output_mode(match self.is_verbose() { true => OutputMode::PrintAll, @@ -602,14 +593,14 @@ impl Build { }), ); if has_local_modifications { - self.run(Command::new("git").args(["stash", "push"]).current_dir(&absolute_path)); + self.run(helpers::git(Some(&absolute_path)).args(["stash", "push"])); } - self.run(Command::new("git").args(["reset", "-q", "--hard"]).current_dir(&absolute_path)); - self.run(Command::new("git").args(["clean", "-qdfx"]).current_dir(&absolute_path)); + self.run(helpers::git(Some(&absolute_path)).args(["reset", "-q", "--hard"])); + self.run(helpers::git(Some(&absolute_path)).args(["clean", "-qdfx"])); if has_local_modifications { - self.run(Command::new("git").args(["stash", "pop"]).current_dir(absolute_path)); + self.run(helpers::git(Some(&absolute_path)).args(["stash", "pop"])); } } @@ -621,8 +612,7 @@ impl Build { return; } let output = output( - self.config - .git() + helpers::git(Some(&self.src)) .args(["config", "--file"]) .arg(&self.config.src.join(".gitmodules")) .args(["--get-regexp", "path"]), @@ -1563,10 +1553,14 @@ impl Build { // Figure out how many merge commits happened since we branched off master. // That's our beta number! // (Note that we use a `..` range, not the `...` symmetric difference.) - output(self.config.git().arg("rev-list").arg("--count").arg("--merges").arg(format!( - "refs/remotes/origin/{}..HEAD", - self.config.stage0_metadata.config.nightly_branch - ))) + output( + helpers::git(Some(&self.src)).arg("rev-list").arg("--count").arg("--merges").arg( + format!( + "refs/remotes/origin/{}..HEAD", + self.config.stage0_metadata.config.nightly_branch + ), + ), + ) }); let n = count.trim().parse().unwrap(); self.prerelease_version.set(Some(n)); @@ -1984,15 +1978,13 @@ fn envify(s: &str) -> String { /// In case of errors during `git` command execution (e.g., in tarball sources), default values /// are used to prevent panics. pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String { - let diff = Command::new("git") - .current_dir(dir) + let diff = helpers::git(Some(dir)) .arg("diff") .output() .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) .unwrap_or_default(); - let status = Command::new("git") - .current_dir(dir) + let status = helpers::git(Some(dir)) .arg("status") .arg("--porcelain") .arg("-z") diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs index 88988c33916..ce82c52f049 100644 --- a/src/bootstrap/src/utils/channel.rs +++ b/src/bootstrap/src/utils/channel.rs @@ -7,11 +7,12 @@ use std::fs; use std::path::Path; -use std::process::Command; use crate::utils::helpers::{output, t}; use crate::Build; +use super::helpers; + #[derive(Clone, Default)] pub enum GitInfo { /// This is not a git repository. @@ -44,7 +45,7 @@ impl GitInfo { } // Make sure git commands work - match Command::new("git").arg("rev-parse").current_dir(dir).output() { + match helpers::git(Some(dir)).arg("rev-parse").output() { Ok(ref out) if out.status.success() => {} _ => return GitInfo::Absent, } @@ -57,17 +58,15 @@ impl GitInfo { // Ok, let's scrape some info let ver_date = output( - Command::new("git") - .current_dir(dir) + helpers::git(Some(dir)) .arg("log") .arg("-1") .arg("--date=short") .arg("--pretty=format:%cd"), ); - let ver_hash = output(Command::new("git").current_dir(dir).arg("rev-parse").arg("HEAD")); - let short_ver_hash = output( - Command::new("git").current_dir(dir).arg("rev-parse").arg("--short=9").arg("HEAD"), - ); + let ver_hash = output(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD")); + let short_ver_hash = + output(helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD")); GitInfo::Present(Some(Info { commit_date: ver_date.trim().to_string(), sha: ver_hash.trim().to_string(), diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 278359cb08e..ed2aa2143f0 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -598,3 +598,19 @@ pub fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String { }; format!("--check-cfg=cfg({name}{next})") } + +/// Prepares `Command` that runs git inside the source directory if given. +/// +/// Whenever a git invocation is needed, this function should be preferred over +/// manually building a git `Command`. This approach allows us to manage bootstrap-specific +/// needs/hacks from a single source, rather than applying them on next to every `Command::new("git")`, +/// which is painful to ensure that the required change is applied on each one of them correctly. +pub fn git(source_dir: Option<&Path>) -> Command { + let mut git = Command::new("git"); + + if let Some(source_dir) = source_dir { + git.current_dir(source_dir); + } + + git +} -- cgit 1.4.1-3-g733a5 From 64450732be8c3111360589e9f8c44eab83f449e0 Mon Sep 17 00:00:00 2001 From: r0cky Date: Wed, 12 Jun 2024 17:58:20 +0800 Subject: Add pub struct with allow(dead_code) into worklist --- compiler/rustc_passes/src/dead.rs | 2 +- .../dead-code/allow-unconstructed-pub-struct.rs | 33 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 2cb3c5d8965..d849305d996 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -898,7 +898,7 @@ fn create_and_seed_worklist( match tcx.def_kind(id) { DefKind::Impl { .. } => false, DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), - DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()), + DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), _ => true }) .map(|id| (id, ComesFromAllowExpect::No)) diff --git a/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs b/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs new file mode 100644 index 00000000000..8cd1524045b --- /dev/null +++ b/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs @@ -0,0 +1,33 @@ +//@ check-pass + +mod ffi { + use super::*; + + extern "C" { + pub fn DomPromise_AddRef(promise: *const Promise); + pub fn DomPromise_Release(promise: *const Promise); + } +} + +#[repr(C)] +#[allow(unused)] +pub struct Promise { + private: [u8; 0], + __nosync: ::std::marker::PhantomData<::std::rc::Rc>, +} + +pub unsafe trait RefCounted { + unsafe fn addref(&self); + unsafe fn release(&self); +} + +unsafe impl RefCounted for Promise { + unsafe fn addref(&self) { + ffi::DomPromise_AddRef(self) + } + unsafe fn release(&self) { + ffi::DomPromise_Release(self) + } +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From d0112c68498470fe2945956b7ed24c5053cbf182 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 7 Jun 2024 14:54:42 +0000 Subject: Spell out other trait diagnostic --- .../traits/error_reporting/type_err_ctxt_ext.rs | 2 +- tests/ui/binop/binary-op-suggest-deref.stderr | 8 +- tests/ui/binop/binop-mul-i32-f32.stderr | 8 +- tests/ui/binop/shift-various-bad-types.stderr | 48 +++++------ tests/ui/const-generics/exhaustive-value.stderr | 16 ++-- .../const-eval/const-eval-overflow-3b.stderr | 8 +- .../const-eval/const-eval-overflow-4b.stderr | 8 +- tests/ui/consts/too_generic_eval_ice.stderr | 16 ++-- .../issue-21659-show-relevant-trait-impls-1.stderr | 4 +- .../issue-21659-show-relevant-trait-impls-2.stderr | 12 +-- .../issue-39802-show-5-trait-impls.stderr | 30 +++---- tests/ui/impl-trait/equality.stderr | 8 +- tests/ui/issues/issue-11771.stderr | 32 +++---- tests/ui/issues/issue-24352.stderr | 8 +- tests/ui/issues/issue-50582.stderr | 16 ++-- .../invalid-iterator-chain-fixable.stderr | 12 +-- .../invalid-iterator-chain-with-int-infer.stderr | 4 +- tests/ui/iterators/invalid-iterator-chain.stderr | 20 ++--- .../lazy-type-alias/trailing-where-clause.stderr | 12 +-- tests/ui/mismatched_types/binops.stderr | 56 ++++++------- tests/ui/never_type/issue-13352.stderr | 8 +- .../not-suggest-float-literal.stderr | 98 +++++++++++----------- .../suggest-float-literal.stderr | 64 +++++++------- tests/ui/on-unimplemented/multiple-impls.stderr | 24 +++--- tests/ui/on-unimplemented/slice-index.stderr | 4 +- tests/ui/on-unimplemented/sum.stderr | 8 +- tests/ui/span/multiline-span-simple.stderr | 8 +- tests/ui/suggestions/into-str.stderr | 12 +-- .../ui/suggestions/issue-71394-no-from-impl.stderr | 16 ++-- .../inheritance/repeated-supertrait-ambig.stderr | 12 +-- .../unevaluated-const-impl-trait-ref.fails.stderr | 4 +- .../question-mark-result-err-mismatch.stderr | 12 +-- tests/ui/try-trait/bad-interconversion.stderr | 20 ++--- tests/ui/try-trait/issue-32709.stderr | 16 ++-- tests/ui/try-trait/option-to-result.stderr | 8 +- tests/ui/try-trait/try-on-option.stderr | 4 +- .../constrain_in_projection2.current.stderr | 4 +- .../nested-tait-inference2.current.stderr | 4 +- tests/ui/type/type-check-defaults.stderr | 8 +- tests/ui/typeck/issue-81293.stderr | 8 +- tests/ui/typeck/issue-90101.stderr | 10 +-- tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr | 16 ++-- 42 files changed, 348 insertions(+), 348 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index aeb7f587a26..72c1ec9e986 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -2064,7 +2064,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if all_traits_equal { format!("\n {}", c.self_ty()) } else { - format!("\n {c}") + format!("\n `{}` implements `{}`", c.self_ty(), c.print_only_trait_path()) } }) .collect(); diff --git a/tests/ui/binop/binary-op-suggest-deref.stderr b/tests/ui/binop/binary-op-suggest-deref.stderr index 47af51e2106..ec17074e305 100644 --- a/tests/ui/binop/binary-op-suggest-deref.stderr +++ b/tests/ui/binop/binary-op-suggest-deref.stderr @@ -303,10 +303,10 @@ LL | let _ = FOO & (*"Sized".to_string().into_boxed_str()); | = help: the trait `BitAnd` is not implemented for `i32` = help: the following other types implement trait `BitAnd`: - <&'a i32 as BitAnd> - <&i32 as BitAnd<&i32>> - > - + `&'a i32` implements `BitAnd` + `&i32` implements `BitAnd<&i32>` + `i32` implements `BitAnd<&i32>` + `i32` implements `BitAnd` error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/binary-op-suggest-deref.rs:78:17 diff --git a/tests/ui/binop/binop-mul-i32-f32.stderr b/tests/ui/binop/binop-mul-i32-f32.stderr index 29e1ff91834..33d8fba172c 100644 --- a/tests/ui/binop/binop-mul-i32-f32.stderr +++ b/tests/ui/binop/binop-mul-i32-f32.stderr @@ -6,10 +6,10 @@ LL | x * y | = help: the trait `Mul` is not implemented for `i32` = help: the following other types implement trait `Mul`: - <&'a i32 as Mul> - <&i32 as Mul<&i32>> - > - + `&'a i32` implements `Mul` + `&i32` implements `Mul<&i32>` + `i32` implements `Mul<&i32>` + `i32` implements `Mul` error: aborting due to 1 previous error diff --git a/tests/ui/binop/shift-various-bad-types.stderr b/tests/ui/binop/shift-various-bad-types.stderr index 38db66f86b4..7313cb3fb84 100644 --- a/tests/ui/binop/shift-various-bad-types.stderr +++ b/tests/ui/binop/shift-various-bad-types.stderr @@ -6,14 +6,14 @@ LL | 22 >> p.char; | = help: the trait `Shr` is not implemented for `{integer}` = help: the following other types implement trait `Shr`: - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` and 568 others error[E0277]: no implementation for `{integer} >> &str` @@ -24,14 +24,14 @@ LL | 22 >> p.str; | = help: the trait `Shr<&str>` is not implemented for `{integer}` = help: the following other types implement trait `Shr`: - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` and 568 others error[E0277]: no implementation for `{integer} >> &Panolpy` @@ -42,14 +42,14 @@ LL | 22 >> p; | = help: the trait `Shr<&Panolpy>` is not implemented for `{integer}` = help: the following other types implement trait `Shr`: - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` and 568 others error[E0308]: mismatched types diff --git a/tests/ui/const-generics/exhaustive-value.stderr b/tests/ui/const-generics/exhaustive-value.stderr index acaa0cf1a50..791bb19ffe8 100644 --- a/tests/ui/const-generics/exhaustive-value.stderr +++ b/tests/ui/const-generics/exhaustive-value.stderr @@ -5,14 +5,14 @@ LL | <() as Foo>::test() | ^^ the trait `Foo` is not implemented for `()` | = help: the following other types implement trait `Foo`: - <() as Foo<0>> - <() as Foo<100>> - <() as Foo<101>> - <() as Foo<102>> - <() as Foo<103>> - <() as Foo<104>> - <() as Foo<105>> - <() as Foo<106>> + `()` implements `Foo<0>` + `()` implements `Foo<100>` + `()` implements `Foo<101>` + `()` implements `Foo<102>` + `()` implements `Foo<103>` + `()` implements `Foo<104>` + `()` implements `Foo<105>` + `()` implements `Foo<106>` and 248 others error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr index 05f33c33946..0d9b718cd06 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -12,10 +12,10 @@ LL | = [0; (i8::MAX + 1u8) as usize]; | = help: the trait `Add` is not implemented for `i8` = help: the following other types implement trait `Add`: - <&'a i8 as Add> - <&i8 as Add<&i8>> - > - + `&'a i8` implements `Add` + `&i8` implements `Add<&i8>` + `i8` implements `Add<&i8>` + `i8` implements `Add` error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr index d019f5920b5..32fe30dc882 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -12,10 +12,10 @@ LL | : [u32; (i8::MAX as i8 + 1u8) as usize] | = help: the trait `Add` is not implemented for `i8` = help: the following other types implement trait `Add`: - <&'a i8 as Add> - <&i8 as Add<&i8>> - > - + `&'a i8` implements `Add` + `&i8` implements `Add<&i8>` + `i8` implements `Add<&i8>` + `i8` implements `Add` error[E0604]: only `u8` can be cast as `char`, not `i8` --> $DIR/const-eval-overflow-4b.rs:22:13 diff --git a/tests/ui/consts/too_generic_eval_ice.stderr b/tests/ui/consts/too_generic_eval_ice.stderr index 54dffa3befc..58a61b938d6 100644 --- a/tests/ui/consts/too_generic_eval_ice.stderr +++ b/tests/ui/consts/too_generic_eval_ice.stderr @@ -22,14 +22,14 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; Self::HOST_SIZE]` = help: the following other types implement trait `PartialEq`: - <&[T] as PartialEq>> - <&[T] as PartialEq<[U; N]>> - <&mut [T] as PartialEq>> - <&mut [T] as PartialEq<[U; N]>> - <[T; N] as PartialEq<&[U]>> - <[T; N] as PartialEq<&mut [U]>> - <[T; N] as PartialEq<[U; N]>> - <[T; N] as PartialEq<[U]>> + `&[T]` implements `PartialEq>` + `&[T]` implements `PartialEq<[U; N]>` + `&mut [T]` implements `PartialEq>` + `&mut [T]` implements `PartialEq<[U; N]>` + `[T; N]` implements `PartialEq<&[U]>` + `[T; N]` implements `PartialEq<&mut [U]>` + `[T; N]` implements `PartialEq<[U; N]>` + `[T; N]` implements `PartialEq<[U]>` and 3 others error: aborting due to 3 previous errors diff --git a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr index 9cbce93c8e0..9d335b391eb 100644 --- a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr +++ b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr @@ -7,8 +7,8 @@ LL | f1.foo(1usize); | required by a bound introduced by this call | = help: the following other types implement trait `Foo`: - > - > + `Bar` implements `Foo` + `Bar` implements `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr index a2b7d804cb8..f9d71807960 100644 --- a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr +++ b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr @@ -7,12 +7,12 @@ LL | f1.foo(1usize); | required by a bound introduced by this call | = help: the following other types implement trait `Foo`: - > - > - > - > - > - > + `Bar` implements `Foo` + `Bar` implements `Foo` + `Bar` implements `Foo` + `Bar` implements `Foo` + `Bar` implements `Foo` + `Bar` implements `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr index 7229b9ac986..b5020304439 100644 --- a/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr +++ b/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr @@ -7,11 +7,11 @@ LL | Foo::::bar(&1i8); | required by a bound introduced by this call | = help: the following other types implement trait `Foo`: - > - > - > - > - > + `i8` implements `Foo` + `i8` implements `Foo` + `i8` implements `Foo` + `i8` implements `Foo` + `i8` implements `Foo` error[E0277]: the trait bound `u8: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:25:21 @@ -22,10 +22,10 @@ LL | Foo::::bar(&1u8); | required by a bound introduced by this call | = help: the following other types implement trait `Foo`: - > - > - > - > + `u8` implements `Foo` + `u8` implements `Foo` + `u8` implements `Foo` + `u8` implements `Foo` error[E0277]: the trait bound `bool: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:26:21 @@ -36,12 +36,12 @@ LL | Foo::::bar(&true); | required by a bound introduced by this call | = help: the following other types implement trait `Foo`: - > - > - > - > - > - > + `bool` implements `Foo` + `bool` implements `Foo` + `bool` implements `Foo` + `bool` implements `Foo` + `bool` implements `Foo` + `bool` implements `Foo` error: aborting due to 3 previous errors diff --git a/tests/ui/impl-trait/equality.stderr b/tests/ui/impl-trait/equality.stderr index 69f4cbbbf42..12d886a0024 100644 --- a/tests/ui/impl-trait/equality.stderr +++ b/tests/ui/impl-trait/equality.stderr @@ -30,10 +30,10 @@ LL | n + sum_to(n - 1) | = help: the trait `Add` is not implemented for `u32` = help: the following other types implement trait `Add`: - <&'a u32 as Add> - <&u32 as Add<&u32>> - > - + `&'a u32` implements `Add` + `&u32` implements `Add<&u32>` + `u32` implements `Add<&u32>` + `u32` implements `Add` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/issues/issue-11771.stderr b/tests/ui/issues/issue-11771.stderr index d4a4647f6a1..8205ee0c38d 100644 --- a/tests/ui/issues/issue-11771.stderr +++ b/tests/ui/issues/issue-11771.stderr @@ -6,14 +6,14 @@ LL | 1 + | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - <&'a f128 as Add> - <&'a f16 as Add> - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> + `&'a f128` implements `Add` + `&'a f16` implements `Add` + `&'a f32` implements `Add` + `&'a f64` implements `Add` + `&'a i128` implements `Add` + `&'a i16` implements `Add` + `&'a i32` implements `Add` + `&'a i64` implements `Add` and 56 others error[E0277]: cannot add `()` to `{integer}` @@ -24,14 +24,14 @@ LL | 1 + | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - <&'a f128 as Add> - <&'a f16 as Add> - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> + `&'a f128` implements `Add` + `&'a f16` implements `Add` + `&'a f32` implements `Add` + `&'a f64` implements `Add` + `&'a i128` implements `Add` + `&'a i16` implements `Add` + `&'a i32` implements `Add` + `&'a i64` implements `Add` and 56 others error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-24352.stderr b/tests/ui/issues/issue-24352.stderr index a9f886158e1..2e7dc254d91 100644 --- a/tests/ui/issues/issue-24352.stderr +++ b/tests/ui/issues/issue-24352.stderr @@ -6,10 +6,10 @@ LL | 1.0f64 - 1 | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - <&'a f64 as Sub> - <&f64 as Sub<&f64>> - > - + `&'a f64` implements `Sub` + `&f64` implements `Sub<&f64>` + `f64` implements `Sub<&f64>` + `f64` implements `Sub` help: consider using a floating-point literal by writing it with `.0` | LL | 1.0f64 - 1.0 diff --git a/tests/ui/issues/issue-50582.stderr b/tests/ui/issues/issue-50582.stderr index b765d2f087d..7203fdeb0bb 100644 --- a/tests/ui/issues/issue-50582.stderr +++ b/tests/ui/issues/issue-50582.stderr @@ -16,14 +16,14 @@ LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - <&'a f128 as Add> - <&'a f16 as Add> - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> + `&'a f128` implements `Add` + `&'a f16` implements `Add` + `&'a f32` implements `Add` + `&'a f64` implements `Add` + `&'a i128` implements `Add` + `&'a i16` implements `Add` + `&'a i32` implements `Add` + `&'a i64` implements `Add` and 56 others error: aborting due to 2 previous errors diff --git a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr index 4d1e4207fdc..a7685e4938d 100644 --- a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr @@ -33,8 +33,8 @@ LL | println!("{}", scores.sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:14:10 | @@ -66,8 +66,8 @@ LL | .sum::(), | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:23:14 | @@ -99,8 +99,8 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:27:38 | diff --git a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr index 9381a98e077..189f089ba51 100644 --- a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr @@ -8,8 +8,8 @@ LL | let x = Some(()).iter().map(|()| 1).sum::(); | = help: the trait `Sum<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Sum`: - > - + `f32` implements `Sum<&'a f32>` + `f32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-with-int-infer.rs:2:29 | diff --git a/tests/ui/iterators/invalid-iterator-chain.stderr b/tests/ui/iterators/invalid-iterator-chain.stderr index 6129a724f44..f72a9f702dc 100644 --- a/tests/ui/iterators/invalid-iterator-chain.stderr +++ b/tests/ui/iterators/invalid-iterator-chain.stderr @@ -33,8 +33,8 @@ LL | println!("{}", scores.sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:12:10 | @@ -65,8 +65,8 @@ LL | .sum::(), | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:25:14 | @@ -104,8 +104,8 @@ LL | .sum::(), | = help: the trait `Sum` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:33:14 | @@ -134,8 +134,8 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:38:38 | @@ -162,8 +162,8 @@ LL | println!("{}", vec![(), ()].iter().sum::()); | = help: the trait `Sum<&()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:39:33 | diff --git a/tests/ui/lazy-type-alias/trailing-where-clause.stderr b/tests/ui/lazy-type-alias/trailing-where-clause.stderr index 534df382eb6..9fabbe91d25 100644 --- a/tests/ui/lazy-type-alias/trailing-where-clause.stderr +++ b/tests/ui/lazy-type-alias/trailing-where-clause.stderr @@ -5,12 +5,12 @@ LL | let _: Alias<()>; | ^^ the trait `From<()>` is not implemented for `String` | = help: the following other types implement trait `From`: - > - > - > - >> - >> - > + `String` implements `From<&String>` + `String` implements `From<&mut str>` + `String` implements `From<&str>` + `String` implements `From>` + `String` implements `From>` + `String` implements `From` note: required by a bound in `Alias` --> $DIR/trailing-where-clause.rs:8:13 | diff --git a/tests/ui/mismatched_types/binops.stderr b/tests/ui/mismatched_types/binops.stderr index 099c580a056..92f21a67c37 100644 --- a/tests/ui/mismatched_types/binops.stderr +++ b/tests/ui/mismatched_types/binops.stderr @@ -6,14 +6,14 @@ LL | 1 + Some(1); | = help: the trait `Add>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - <&'a f128 as Add> - <&'a f16 as Add> - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> + `&'a f128` implements `Add` + `&'a f16` implements `Add` + `&'a f32` implements `Add` + `&'a f64` implements `Add` + `&'a i128` implements `Add` + `&'a i16` implements `Add` + `&'a i32` implements `Add` + `&'a i64` implements `Add` and 56 others error[E0277]: cannot subtract `Option<{integer}>` from `usize` @@ -24,10 +24,10 @@ LL | 2 as usize - Some(1); | = help: the trait `Sub>` is not implemented for `usize` = help: the following other types implement trait `Sub`: - <&'a usize as Sub> - <&usize as Sub<&usize>> - > - + `&'a usize` implements `Sub` + `&usize` implements `Sub<&usize>` + `usize` implements `Sub<&usize>` + `usize` implements `Sub` error[E0277]: cannot multiply `{integer}` by `()` --> $DIR/binops.rs:4:7 @@ -37,14 +37,14 @@ LL | 3 * (); | = help: the trait `Mul<()>` is not implemented for `{integer}` = help: the following other types implement trait `Mul`: - <&'a f128 as Mul> - <&'a f16 as Mul> - <&'a f32 as Mul> - <&'a f64 as Mul> - <&'a i128 as Mul> - <&'a i16 as Mul> - <&'a i32 as Mul> - <&'a i64 as Mul> + `&'a f128` implements `Mul` + `&'a f16` implements `Mul` + `&'a f32` implements `Mul` + `&'a f64` implements `Mul` + `&'a i128` implements `Mul` + `&'a i16` implements `Mul` + `&'a i32` implements `Mul` + `&'a i64` implements `Mul` and 57 others error[E0277]: cannot divide `{integer}` by `&str` @@ -55,14 +55,14 @@ LL | 4 / ""; | = help: the trait `Div<&str>` is not implemented for `{integer}` = help: the following other types implement trait `Div`: - <&'a f128 as Div> - <&'a f16 as Div> - <&'a f32 as Div> - <&'a f64 as Div> - <&'a i128 as Div> - <&'a i16 as Div> - <&'a i32 as Div> - <&'a i64 as Div> + `&'a f128` implements `Div` + `&'a f16` implements `Div` + `&'a f32` implements `Div` + `&'a f64` implements `Div` + `&'a i128` implements `Div` + `&'a i16` implements `Div` + `&'a i32` implements `Div` + `&'a i64` implements `Div` and 62 others error[E0277]: can't compare `{integer}` with `String` diff --git a/tests/ui/never_type/issue-13352.stderr b/tests/ui/never_type/issue-13352.stderr index 1b979d93446..7134e4d40a6 100644 --- a/tests/ui/never_type/issue-13352.stderr +++ b/tests/ui/never_type/issue-13352.stderr @@ -6,10 +6,10 @@ LL | 2_usize + (loop {}); | = help: the trait `Add<()>` is not implemented for `usize` = help: the following other types implement trait `Add`: - <&'a usize as Add> - <&usize as Add<&usize>> - > - + `&'a usize` implements `Add` + `&usize` implements `Add<&usize>` + `usize` implements `Add<&usize>` + `usize` implements `Add` error: aborting due to 1 previous error diff --git a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr index 14685a3f937..a910666bd56 100644 --- a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr @@ -6,10 +6,10 @@ LL | x + 100.0 | = help: the trait `Add<{float}>` is not implemented for `u8` = help: the following other types implement trait `Add`: - <&'a u8 as Add> - <&u8 as Add<&u8>> - > - + `&'a u8` implements `Add` + `&u8` implements `Add<&u8>` + `u8` implements `Add<&u8>` + `u8` implements `Add` error[E0277]: cannot add `&str` to `f64` --> $DIR/not-suggest-float-literal.rs:6:7 @@ -19,10 +19,10 @@ LL | x + "foo" | = help: the trait `Add<&str>` is not implemented for `f64` = help: the following other types implement trait `Add`: - <&'a f64 as Add> - <&f64 as Add<&f64>> - > - + `&'a f64` implements `Add` + `&f64` implements `Add<&f64>` + `f64` implements `Add<&f64>` + `f64` implements `Add` error[E0277]: cannot add `{integer}` to `f64` --> $DIR/not-suggest-float-literal.rs:11:7 @@ -32,10 +32,10 @@ LL | x + y | = help: the trait `Add<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Add`: - <&'a f64 as Add> - <&f64 as Add<&f64>> - > - + `&'a f64` implements `Add` + `&f64` implements `Add<&f64>` + `f64` implements `Add<&f64>` + `f64` implements `Add` error[E0277]: cannot subtract `{float}` from `u8` --> $DIR/not-suggest-float-literal.rs:15:7 @@ -45,10 +45,10 @@ LL | x - 100.0 | = help: the trait `Sub<{float}>` is not implemented for `u8` = help: the following other types implement trait `Sub`: - <&'a u8 as Sub> - <&u8 as Sub<&u8>> - > - + `&'a u8` implements `Sub` + `&u8` implements `Sub<&u8>` + `u8` implements `Sub<&u8>` + `u8` implements `Sub` error[E0277]: cannot subtract `&str` from `f64` --> $DIR/not-suggest-float-literal.rs:19:7 @@ -58,10 +58,10 @@ LL | x - "foo" | = help: the trait `Sub<&str>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - <&'a f64 as Sub> - <&f64 as Sub<&f64>> - > - + `&'a f64` implements `Sub` + `&f64` implements `Sub<&f64>` + `f64` implements `Sub<&f64>` + `f64` implements `Sub` error[E0277]: cannot subtract `{integer}` from `f64` --> $DIR/not-suggest-float-literal.rs:24:7 @@ -71,10 +71,10 @@ LL | x - y | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - <&'a f64 as Sub> - <&f64 as Sub<&f64>> - > - + `&'a f64` implements `Sub` + `&f64` implements `Sub<&f64>` + `f64` implements `Sub<&f64>` + `f64` implements `Sub` error[E0277]: cannot multiply `u8` by `{float}` --> $DIR/not-suggest-float-literal.rs:28:7 @@ -84,10 +84,10 @@ LL | x * 100.0 | = help: the trait `Mul<{float}>` is not implemented for `u8` = help: the following other types implement trait `Mul`: - <&'a u8 as Mul> - <&u8 as Mul<&u8>> - > - + `&'a u8` implements `Mul` + `&u8` implements `Mul<&u8>` + `u8` implements `Mul<&u8>` + `u8` implements `Mul` error[E0277]: cannot multiply `f64` by `&str` --> $DIR/not-suggest-float-literal.rs:32:7 @@ -97,10 +97,10 @@ LL | x * "foo" | = help: the trait `Mul<&str>` is not implemented for `f64` = help: the following other types implement trait `Mul`: - <&'a f64 as Mul> - <&f64 as Mul<&f64>> - > - + `&'a f64` implements `Mul` + `&f64` implements `Mul<&f64>` + `f64` implements `Mul<&f64>` + `f64` implements `Mul` error[E0277]: cannot multiply `f64` by `{integer}` --> $DIR/not-suggest-float-literal.rs:37:7 @@ -110,10 +110,10 @@ LL | x * y | = help: the trait `Mul<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Mul`: - <&'a f64 as Mul> - <&f64 as Mul<&f64>> - > - + `&'a f64` implements `Mul` + `&f64` implements `Mul<&f64>` + `f64` implements `Mul<&f64>` + `f64` implements `Mul` error[E0277]: cannot divide `u8` by `{float}` --> $DIR/not-suggest-float-literal.rs:41:7 @@ -123,11 +123,11 @@ LL | x / 100.0 | = help: the trait `Div<{float}>` is not implemented for `u8` = help: the following other types implement trait `Div`: - <&'a u8 as Div> - <&u8 as Div<&u8>> - > - >> - + `&'a u8` implements `Div` + `&u8` implements `Div<&u8>` + `u8` implements `Div<&u8>` + `u8` implements `Div>` + `u8` implements `Div` error[E0277]: cannot divide `f64` by `&str` --> $DIR/not-suggest-float-literal.rs:45:7 @@ -137,10 +137,10 @@ LL | x / "foo" | = help: the trait `Div<&str>` is not implemented for `f64` = help: the following other types implement trait `Div`: - <&'a f64 as Div> - <&f64 as Div<&f64>> - > - + `&'a f64` implements `Div` + `&f64` implements `Div<&f64>` + `f64` implements `Div<&f64>` + `f64` implements `Div` error[E0277]: cannot divide `f64` by `{integer}` --> $DIR/not-suggest-float-literal.rs:50:7 @@ -150,10 +150,10 @@ LL | x / y | = help: the trait `Div<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Div`: - <&'a f64 as Div> - <&f64 as Div<&f64>> - > - + `&'a f64` implements `Div` + `&f64` implements `Div<&f64>` + `f64` implements `Div<&f64>` + `f64` implements `Div` error: aborting due to 12 previous errors diff --git a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr index 03779d35637..8585ac485db 100644 --- a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr @@ -6,10 +6,10 @@ LL | x + 100 | = help: the trait `Add<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&f32 as Add<&f32>> - > - + `&'a f32` implements `Add` + `&f32` implements `Add<&f32>` + `f32` implements `Add<&f32>` + `f32` implements `Add` help: consider using a floating-point literal by writing it with `.0` | LL | x + 100.0 @@ -23,10 +23,10 @@ LL | x + 100 | = help: the trait `Add<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Add`: - <&'a f64 as Add> - <&f64 as Add<&f64>> - > - + `&'a f64` implements `Add` + `&f64` implements `Add<&f64>` + `f64` implements `Add<&f64>` + `f64` implements `Add` help: consider using a floating-point literal by writing it with `.0` | LL | x + 100.0 @@ -40,10 +40,10 @@ LL | x - 100 | = help: the trait `Sub<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Sub`: - <&'a f32 as Sub> - <&f32 as Sub<&f32>> - > - + `&'a f32` implements `Sub` + `&f32` implements `Sub<&f32>` + `f32` implements `Sub<&f32>` + `f32` implements `Sub` help: consider using a floating-point literal by writing it with `.0` | LL | x - 100.0 @@ -57,10 +57,10 @@ LL | x - 100 | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - <&'a f64 as Sub> - <&f64 as Sub<&f64>> - > - + `&'a f64` implements `Sub` + `&f64` implements `Sub<&f64>` + `f64` implements `Sub<&f64>` + `f64` implements `Sub` help: consider using a floating-point literal by writing it with `.0` | LL | x - 100.0 @@ -74,10 +74,10 @@ LL | x * 100 | = help: the trait `Mul<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Mul`: - <&'a f32 as Mul> - <&f32 as Mul<&f32>> - > - + `&'a f32` implements `Mul` + `&f32` implements `Mul<&f32>` + `f32` implements `Mul<&f32>` + `f32` implements `Mul` help: consider using a floating-point literal by writing it with `.0` | LL | x * 100.0 @@ -91,10 +91,10 @@ LL | x * 100 | = help: the trait `Mul<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Mul`: - <&'a f64 as Mul> - <&f64 as Mul<&f64>> - > - + `&'a f64` implements `Mul` + `&f64` implements `Mul<&f64>` + `f64` implements `Mul<&f64>` + `f64` implements `Mul` help: consider using a floating-point literal by writing it with `.0` | LL | x * 100.0 @@ -108,10 +108,10 @@ LL | x / 100 | = help: the trait `Div<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Div`: - <&'a f32 as Div> - <&f32 as Div<&f32>> - > - + `&'a f32` implements `Div` + `&f32` implements `Div<&f32>` + `f32` implements `Div<&f32>` + `f32` implements `Div` help: consider using a floating-point literal by writing it with `.0` | LL | x / 100.0 @@ -125,10 +125,10 @@ LL | x / 100 | = help: the trait `Div<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Div`: - <&'a f64 as Div> - <&f64 as Div<&f64>> - > - + `&'a f64` implements `Div` + `&f64` implements `Div<&f64>` + `f64` implements `Div<&f64>` + `f64` implements `Div` help: consider using a floating-point literal by writing it with `.0` | LL | x / 100.0 diff --git a/tests/ui/on-unimplemented/multiple-impls.stderr b/tests/ui/on-unimplemented/multiple-impls.stderr index b50dc251baa..ba4e43ff359 100644 --- a/tests/ui/on-unimplemented/multiple-impls.stderr +++ b/tests/ui/on-unimplemented/multiple-impls.stderr @@ -8,8 +8,8 @@ LL | Index::index(&[] as &[i32], 2u32); | = help: the trait `Index` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> + `[i32]` implements `Index>` + `[i32]` implements `Index>` error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:36:33 @@ -21,8 +21,8 @@ LL | Index::index(&[] as &[i32], Foo(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> + `[i32]` implements `Index>` + `[i32]` implements `Index>` error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:39:33 @@ -34,8 +34,8 @@ LL | Index::index(&[] as &[i32], Bar(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> + `[i32]` implements `Index>` + `[i32]` implements `Index>` error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/multiple-impls.rs:33:5 @@ -45,8 +45,8 @@ LL | Index::index(&[] as &[i32], 2u32); | = help: the trait `Index` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> + `[i32]` implements `Index>` + `[i32]` implements `Index>` error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:36:5 @@ -56,8 +56,8 @@ LL | Index::index(&[] as &[i32], Foo(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> + `[i32]` implements `Index>` + `[i32]` implements `Index>` error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:39:5 @@ -67,8 +67,8 @@ LL | Index::index(&[] as &[i32], Bar(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> + `[i32]` implements `Index>` + `[i32]` implements `Index>` error: aborting due to 6 previous errors diff --git a/tests/ui/on-unimplemented/slice-index.stderr b/tests/ui/on-unimplemented/slice-index.stderr index f17f3cfce8d..0f8d105abef 100644 --- a/tests/ui/on-unimplemented/slice-index.stderr +++ b/tests/ui/on-unimplemented/slice-index.stderr @@ -17,8 +17,8 @@ LL | x[..1i32]; | = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo`, which is required by `[i32]: Index<_>` = help: the following other types implement trait `SliceIndex`: - as SliceIndex<[T]>> - as SliceIndex> + `RangeTo` implements `SliceIndex<[T]>` + `RangeTo` implements `SliceIndex` = note: required for `[i32]` to implement `Index>` error: aborting due to 2 previous errors diff --git a/tests/ui/on-unimplemented/sum.stderr b/tests/ui/on-unimplemented/sum.stderr index 65bab458cf1..f8e266a8727 100644 --- a/tests/ui/on-unimplemented/sum.stderr +++ b/tests/ui/on-unimplemented/sum.stderr @@ -8,8 +8,8 @@ LL | vec![(), ()].iter().sum::(); | = help: the trait `Sum<&()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:4:18 | @@ -30,8 +30,8 @@ LL | vec![(), ()].iter().product::(); | = help: the trait `Product<&()>` is not implemented for `i32` = help: the following other types implement trait `Product`: - > - + `i32` implements `Product<&'a i32>` + `i32` implements `Product` note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:7:18 | diff --git a/tests/ui/span/multiline-span-simple.stderr b/tests/ui/span/multiline-span-simple.stderr index 2de792b03d7..2454769863b 100644 --- a/tests/ui/span/multiline-span-simple.stderr +++ b/tests/ui/span/multiline-span-simple.stderr @@ -6,10 +6,10 @@ LL | foo(1 as u32 + | = help: the trait `Add<()>` is not implemented for `u32` = help: the following other types implement trait `Add`: - <&'a u32 as Add> - <&u32 as Add<&u32>> - > - + `&'a u32` implements `Add` + `&u32` implements `Add<&u32>` + `u32` implements `Add<&u32>` + `u32` implements `Add` error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/into-str.stderr b/tests/ui/suggestions/into-str.stderr index 2fdfab8bdc5..6c1e1ec428f 100644 --- a/tests/ui/suggestions/into-str.stderr +++ b/tests/ui/suggestions/into-str.stderr @@ -8,12 +8,12 @@ LL | foo(String::new()); | = note: to coerce a `String` into a `&str`, use `&*` as a prefix = help: the following other types implement trait `From`: - > - > - > - >> - >> - > + `String` implements `From<&String>` + `String` implements `From<&mut str>` + `String` implements `From<&str>` + `String` implements `From>` + `String` implements `From>` + `String` implements `From` = note: required for `String` to implement `Into<&str>` note: required by a bound in `foo` --> $DIR/into-str.rs:1:31 diff --git a/tests/ui/suggestions/issue-71394-no-from-impl.stderr b/tests/ui/suggestions/issue-71394-no-from-impl.stderr index e626b5b0eb7..79f5dcf4b73 100644 --- a/tests/ui/suggestions/issue-71394-no-from-impl.stderr +++ b/tests/ui/suggestions/issue-71394-no-from-impl.stderr @@ -5,14 +5,14 @@ LL | let _: &[i8] = data.into(); | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`, which is required by `&[u8]: Into<_>` | = help: the following other types implement trait `From`: - <[T; 10] as From<(T, T, T, T, T, T, T, T, T, T)>> - <[T; 11] as From<(T, T, T, T, T, T, T, T, T, T, T)>> - <[T; 12] as From<(T, T, T, T, T, T, T, T, T, T, T, T)>> - <[T; 1] as From<(T,)>> - <[T; 2] as From<(T, T)>> - <[T; 3] as From<(T, T, T)>> - <[T; 4] as From<(T, T, T, T)>> - <[T; 5] as From<(T, T, T, T, T)>> + `[T; 10]` implements `From<(T, T, T, T, T, T, T, T, T, T)>` + `[T; 11]` implements `From<(T, T, T, T, T, T, T, T, T, T, T)>` + `[T; 12]` implements `From<(T, T, T, T, T, T, T, T, T, T, T, T)>` + `[T; 1]` implements `From<(T,)>` + `[T; 2]` implements `From<(T, T)>` + `[T; 3]` implements `From<(T, T, T)>` + `[T; 4]` implements `From<(T, T, T, T)>` + `[T; 5]` implements `From<(T, T, T, T, T)>` and 6 others = note: required for `&[u8]` to implement `Into<&[i8]>` diff --git a/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr b/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr index 7027fa69e03..6f7c9fa11d4 100644 --- a/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr +++ b/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr @@ -7,8 +7,8 @@ LL | c.same_as(22) | required by a bound introduced by this call | = help: the following other types implement trait `CompareTo`: - > - > + `i64` implements `CompareTo` + `i64` implements `CompareTo` error[E0277]: the trait bound `C: CompareTo` is not satisfied --> $DIR/repeated-supertrait-ambig.rs:30:15 @@ -30,8 +30,8 @@ LL | ::same_as(c, 22) | ^^^^^^^^^^^^^^^^^ the trait `CompareTo` is not implemented for `dyn CompareToInts` | = help: the following other types implement trait `CompareTo`: - > - > + `i64` implements `CompareTo` + `i64` implements `CompareTo` error[E0277]: the trait bound `C: CompareTo` is not satisfied --> $DIR/repeated-supertrait-ambig.rs:38:27 @@ -55,8 +55,8 @@ LL | assert_eq!(22_i64.same_as(22), true); | required by a bound introduced by this call | = help: the following other types implement trait `CompareTo`: - > - > + `i64` implements `CompareTo` + `i64` implements `CompareTo` error: aborting due to 5 previous errors diff --git a/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr b/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr index 4be90c702a0..efdc9f8fc9f 100644 --- a/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr +++ b/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr @@ -5,8 +5,8 @@ LL | needs::<1>(); | ^ the trait `Trait<1>` is not implemented for `()` | = help: the following other types implement trait `Trait`: - <() as Trait<0>> - <() as Trait<2>> + `()` implements `Trait<0>` + `()` implements `Trait<2>` note: required by a bound in `needs` --> $DIR/unevaluated-const-impl-trait-ref.rs:10:38 | diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr index 8a6c5fc10c5..66276bcbe3b 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.stderr +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -31,12 +31,12 @@ LL | .map_err(|_| ())?; | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: - > - > - > - >> - >> - > + `String` implements `From<&String>` + `String` implements `From<&mut str>` + `String` implements `From<&str>` + `String` implements `From>` + `String` implements `From>` + `String` implements `From` = note: required for `Result<(), String>` to implement `FromResidual>` error[E0277]: `?` couldn't convert the error to `String` diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index e3edec6a4c7..c30b6334fed 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -10,8 +10,8 @@ LL | Ok(Err(123_i32)?) | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: - > - > + `u8` implements `From` + `u8` implements `From` = note: required for `Result` to implement `FromResidual>` error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` @@ -24,8 +24,8 @@ LL | Some(3)?; | = help: the trait `FromResidual>` is not implemented for `Result` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual>> + `Result` implements `FromResidual>` + `Result` implements `FromResidual>` error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` --> $DIR/bad-interconversion.rs:17:31 @@ -37,8 +37,8 @@ LL | Ok(ControlFlow::Break(123)?) | = help: the trait `FromResidual>` is not implemented for `Result` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual>> + `Result` implements `FromResidual>` + `Result` implements `FromResidual>` error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/bad-interconversion.rs:22:22 @@ -50,8 +50,8 @@ LL | Some(Err("hello")?) | = help: the trait `FromResidual>` is not implemented for `Option` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual> + `Option` implements `FromResidual>` + `Option` implements `FromResidual` error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option` --> $DIR/bad-interconversion.rs:27:33 @@ -63,8 +63,8 @@ LL | Some(ControlFlow::Break(123)?) | = help: the trait `FromResidual>` is not implemented for `Option` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual> + `Option` implements `FromResidual>` + `Option` implements `FromResidual` error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` --> $DIR/bad-interconversion.rs:32:39 diff --git a/tests/ui/try-trait/issue-32709.stderr b/tests/ui/try-trait/issue-32709.stderr index a0dd18fa039..9b77f578437 100644 --- a/tests/ui/try-trait/issue-32709.stderr +++ b/tests/ui/try-trait/issue-32709.stderr @@ -10,14 +10,14 @@ LL | Err(5)?; | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: - <(T, T) as From<[T; 2]>> - <(T, T, T) as From<[T; 3]>> - <(T, T, T, T) as From<[T; 4]>> - <(T, T, T, T, T) as From<[T; 5]>> - <(T, T, T, T, T, T) as From<[T; 6]>> - <(T, T, T, T, T, T, T) as From<[T; 7]>> - <(T, T, T, T, T, T, T, T) as From<[T; 8]>> - <(T, T, T, T, T, T, T, T, T) as From<[T; 9]>> + `(T, T)` implements `From<[T; 2]>` + `(T, T, T)` implements `From<[T; 3]>` + `(T, T, T, T)` implements `From<[T; 4]>` + `(T, T, T, T, T)` implements `From<[T; 5]>` + `(T, T, T, T, T, T)` implements `From<[T; 6]>` + `(T, T, T, T, T, T, T)` implements `From<[T; 7]>` + `(T, T, T, T, T, T, T, T)` implements `From<[T; 8]>` + `(T, T, T, T, T, T, T, T, T)` implements `From<[T; 9]>` and 4 others = note: required for `Result` to implement `FromResidual>` diff --git a/tests/ui/try-trait/option-to-result.stderr b/tests/ui/try-trait/option-to-result.stderr index fabc1ff2c76..2d97226275d 100644 --- a/tests/ui/try-trait/option-to-result.stderr +++ b/tests/ui/try-trait/option-to-result.stderr @@ -9,8 +9,8 @@ LL | a?; | = help: the trait `FromResidual>` is not implemented for `Result<(), ()>` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual>> + `Result` implements `FromResidual>` + `Result` implements `FromResidual>` error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/option-to-result.rs:11:6 @@ -23,8 +23,8 @@ LL | a?; | = help: the trait `FromResidual>` is not implemented for `Option` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual> + `Option` implements `FromResidual>` + `Option` implements `FromResidual` error: aborting due to 2 previous errors diff --git a/tests/ui/try-trait/try-on-option.stderr b/tests/ui/try-trait/try-on-option.stderr index fad6a1fe823..84a51a078af 100644 --- a/tests/ui/try-trait/try-on-option.stderr +++ b/tests/ui/try-trait/try-on-option.stderr @@ -9,8 +9,8 @@ LL | x?; | = help: the trait `FromResidual>` is not implemented for `Result` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual>> + `Result` implements `FromResidual>` + `Result` implements `FromResidual>` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option.rs:11:6 diff --git a/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr b/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr index 69df5c77f9d..909f1f6d61c 100644 --- a/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr +++ b/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr @@ -5,8 +5,8 @@ LL | let x = >::Assoc::default(); | ^^^ the trait `Trait` is not implemented for `Foo` | = help: the following other types implement trait `Trait`: - > - > + `Foo` implements `Trait<()>` + `Foo` implements `Trait` error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/nested-tait-inference2.current.stderr b/tests/ui/type-alias-impl-trait/nested-tait-inference2.current.stderr index 614bc09872f..9da3926ac70 100644 --- a/tests/ui/type-alias-impl-trait/nested-tait-inference2.current.stderr +++ b/tests/ui/type-alias-impl-trait/nested-tait-inference2.current.stderr @@ -8,8 +8,8 @@ LL | () | -- return type was inferred to be `()` here | = help: the following other types implement trait `Foo`: - <() as Foo<()>> - <() as Foo> + `()` implements `Foo<()>` + `()` implements `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/type/type-check-defaults.stderr b/tests/ui/type/type-check-defaults.stderr index 9ba63ffe9c9..499e8142cc8 100644 --- a/tests/ui/type/type-check-defaults.stderr +++ b/tests/ui/type/type-check-defaults.stderr @@ -66,10 +66,10 @@ LL | trait ProjectionPred> where T::Item : Add {} | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: - <&'a i32 as Add> - <&i32 as Add<&i32>> - > - + `&'a i32` implements `Add` + `&i32` implements `Add<&i32>` + `i32` implements `Add<&i32>` + `i32` implements `Add` error: aborting due to 7 previous errors diff --git a/tests/ui/typeck/issue-81293.stderr b/tests/ui/typeck/issue-81293.stderr index 6976be71135..3c48db335b5 100644 --- a/tests/ui/typeck/issue-81293.stderr +++ b/tests/ui/typeck/issue-81293.stderr @@ -21,10 +21,10 @@ LL | a = c + b * 5; | = help: the trait `Add` is not implemented for `usize` = help: the following other types implement trait `Add`: - <&'a usize as Add> - <&usize as Add<&usize>> - > - + `&'a usize` implements `Add` + `&usize` implements `Add<&usize>` + `usize` implements `Add<&usize>` + `usize` implements `Add` error: aborting due to 3 previous errors diff --git a/tests/ui/typeck/issue-90101.stderr b/tests/ui/typeck/issue-90101.stderr index 800d7e9594a..d6832d1b34f 100644 --- a/tests/ui/typeck/issue-90101.stderr +++ b/tests/ui/typeck/issue-90101.stderr @@ -7,11 +7,11 @@ LL | func(Path::new("hello").to_path_buf().to_string_lossy(), "world") | required by a bound introduced by this call | = help: the following other types implement trait `From`: - > - >> - >> - > - > + `PathBuf` implements `From<&T>` + `PathBuf` implements `From>` + `PathBuf` implements `From>` + `PathBuf` implements `From` + `PathBuf` implements `From` = note: required for `Cow<'_, str>` to implement `Into` note: required by a bound in `func` --> $DIR/issue-90101.rs:3:20 diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr index 964fd4af009..5b8a49d22c7 100644 --- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -6,10 +6,10 @@ LL | >::add(1, 2); | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: - <&'a i32 as Add> - <&i32 as Add<&i32>> - > - + `&'a i32` implements `Add` + `&i32` implements `Add<&i32>` + `i32` implements `Add<&i32>` + `i32` implements `Add` error[E0277]: cannot add `u32` to `i32` --> $DIR/ufcs-qpath-self-mismatch.rs:4:5 @@ -19,10 +19,10 @@ LL | >::add(1, 2); | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: - <&'a i32 as Add> - <&i32 as Add<&i32>> - > - + `&'a i32` implements `Add` + `&i32` implements `Add<&i32>` + `i32` implements `Add<&i32>` + `i32` implements `Add` error[E0308]: mismatched types --> $DIR/ufcs-qpath-self-mismatch.rs:7:28 -- cgit 1.4.1-3-g733a5 From 80408e0649b29915ad5258367b67c70a91e6b043 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 28 May 2024 13:21:28 -0400 Subject: port symlinked-extern to rmake --- src/tools/run-make-support/src/lib.rs | 23 +++++++++++++++++++-- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/symlinked-extern/rmake.rs | 25 +++++++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 tests/run-make/symlinked-extern/rmake.rs diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index b920f9a07db..d93a950d3e1 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -93,6 +93,17 @@ pub fn source_root() -> PathBuf { env_var("SOURCE_ROOT").into() } +/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. +pub fn create_symlink, Q: AsRef>(original: P, link: Q) { + if is_windows() { + use std::os::windows::fs; + fs::symlink_file(original, link).unwrap(); + } else { + use std::os::unix::fs; + fs::symlink(original, link).unwrap(); + } +} + /// Construct the static library name based on the platform. pub fn static_lib_name(name: &str) -> String { // See tools.mk (irrelevant lines omitted): @@ -114,7 +125,11 @@ pub fn static_lib_name(name: &str) -> String { // ``` assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace"); - if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") } + if is_msvc() { + format!("{name}.lib") + } else { + format!("lib{name}.a") + } } /// Construct the dynamic library name based on the platform. @@ -161,7 +176,11 @@ pub fn rust_lib_name(name: &str) -> String { /// Construct the binary name based on platform. pub fn bin_name(name: &str) -> String { - if is_windows() { format!("{name}.exe") } else { name.to_string() } + if is_windows() { + format!("{name}.exe") + } else { + name.to_string() + } } /// Return the current working directory. diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index ac89a30f353..4adfd52b2b3 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -228,7 +228,6 @@ run-make/std-core-cycle/Makefile run-make/symbol-mangling-hashed/Makefile run-make/symbol-visibility/Makefile run-make/symbols-include-type-name/Makefile -run-make/symlinked-extern/Makefile run-make/symlinked-libraries/Makefile run-make/symlinked-rlib/Makefile run-make/sysroot-crates-are-unstable/Makefile diff --git a/tests/run-make/symlinked-extern/rmake.rs b/tests/run-make/symlinked-extern/rmake.rs new file mode 100644 index 00000000000..124f1cef849 --- /dev/null +++ b/tests/run-make/symlinked-extern/rmake.rs @@ -0,0 +1,25 @@ +// Crates that are resolved normally have their path canonicalized and all +// symlinks resolved. This did not happen for paths specified +// using the --extern option to rustc, which could lead to rustc thinking +// that it encountered two different versions of a crate, when it's +// actually the same version found through different paths. + +// This test checks that --extern and symlinks together +// can result in successful compilation. + +//@ ignore-cross-compile + +use run_make_support::{create_symlink, rustc, tmp_dir}; +use std::fs; + +fn main() { + rustc().input("foo.rs").run(); + fs::create_dir_all(tmp_dir().join("other")).unwrap(); + create_symlink(tmp_dir().join("libfoo.rlib"), tmp_dir().join("other")); + rustc().input("bar.rs").library_search_path(tmp_dir()).run(); + rustc() + .input("baz.rs") + .extern_("foo", tmp_dir().join("other/libfoo.rlib")) + .library_search_path(tmp_dir()) + .run(); +} -- cgit 1.4.1-3-g733a5 From 59acd234575b0283a6e00ec2e9d8be5f1b2f782d Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 28 May 2024 13:33:14 -0400 Subject: port symlinked-rlib to rmake --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/symlinked-extern/Makefile | 12 ------------ tests/run-make/symlinked-extern/rmake.rs | 1 + tests/run-make/symlinked-rlib/Makefile | 10 ---------- tests/run-make/symlinked-rlib/rmake.rs | 16 ++++++++++++++++ 5 files changed, 17 insertions(+), 23 deletions(-) delete mode 100644 tests/run-make/symlinked-extern/Makefile delete mode 100644 tests/run-make/symlinked-rlib/Makefile create mode 100644 tests/run-make/symlinked-rlib/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 4adfd52b2b3..dc1310afde9 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -229,7 +229,6 @@ run-make/symbol-mangling-hashed/Makefile run-make/symbol-visibility/Makefile run-make/symbols-include-type-name/Makefile run-make/symlinked-libraries/Makefile -run-make/symlinked-rlib/Makefile run-make/sysroot-crates-are-unstable/Makefile run-make/target-cpu-native/Makefile run-make/target-specs/Makefile diff --git a/tests/run-make/symlinked-extern/Makefile b/tests/run-make/symlinked-extern/Makefile deleted file mode 100644 index 28c764b84e8..00000000000 --- a/tests/run-make/symlinked-extern/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# ignore-windows -# `ln` is actually `cp` on msys. - -all: - $(RUSTC) foo.rs - mkdir -p $(TMPDIR)/other - ln -nsf $(TMPDIR)/libfoo.rlib $(TMPDIR)/other - $(RUSTC) bar.rs -L $(TMPDIR) - $(RUSTC) baz.rs --extern foo=$(TMPDIR)/other/libfoo.rlib -L $(TMPDIR) diff --git a/tests/run-make/symlinked-extern/rmake.rs b/tests/run-make/symlinked-extern/rmake.rs index 124f1cef849..a54989661dc 100644 --- a/tests/run-make/symlinked-extern/rmake.rs +++ b/tests/run-make/symlinked-extern/rmake.rs @@ -3,6 +3,7 @@ // using the --extern option to rustc, which could lead to rustc thinking // that it encountered two different versions of a crate, when it's // actually the same version found through different paths. +// See https://github.com/rust-lang/rust/pull/16505 // This test checks that --extern and symlinks together // can result in successful compilation. diff --git a/tests/run-make/symlinked-rlib/Makefile b/tests/run-make/symlinked-rlib/Makefile deleted file mode 100644 index a8565f683c3..00000000000 --- a/tests/run-make/symlinked-rlib/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# ignore-windows -# `ln` is actually `cp` on msys. - -all: - $(RUSTC) foo.rs --crate-type=rlib -o $(TMPDIR)/foo.xxx - ln -nsf $(TMPDIR)/foo.xxx $(TMPDIR)/libfoo.rlib - $(RUSTC) bar.rs -L $(TMPDIR) diff --git a/tests/run-make/symlinked-rlib/rmake.rs b/tests/run-make/symlinked-rlib/rmake.rs new file mode 100644 index 00000000000..d451c62a2f3 --- /dev/null +++ b/tests/run-make/symlinked-rlib/rmake.rs @@ -0,0 +1,16 @@ +// Rustc did not recognize libraries which were symlinked +// to files having extension other than .rlib. This was fixed +// in #32828. This test creates a symlink to "foo.xxx", which has +// an unusual file extension, and checks that rustc can successfully +// use it as an rlib library. +// See https://github.com/rust-lang/rust/pull/32828 + +//@ ignore-cross-compile + +use run_make_support::{create_symlink, rustc, tmp_dir}; + +fn main() { + rustc().input("foo.rs").crate_type("rlib").output(tmp_dir().join("foo.xxx")).run(); + create_symlink(tmp_dir().join("foo.xxx"), tmp_dir().join("libfoo.rlib")); + rustc().input("bar.rs").library_search_path(tmp_dir()); +} -- cgit 1.4.1-3-g733a5 From 2ac5faa509e9511665986a5ac25ed7c4e427aac2 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 28 May 2024 13:57:09 -0400 Subject: port symlinked-libraries to rmake --- src/tools/run-make-support/src/lib.rs | 41 ++++++++++++++--------- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/symlinked-extern/rmake.rs | 15 +++------ tests/run-make/symlinked-libraries/Makefile | 11 ------ tests/run-make/symlinked-libraries/rmake.rs | 16 +++++++++ tests/run-make/symlinked-rlib/rmake.rs | 8 ++--- 6 files changed, 50 insertions(+), 42 deletions(-) delete mode 100644 tests/run-make/symlinked-libraries/Makefile create mode 100644 tests/run-make/symlinked-libraries/rmake.rs diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index d93a950d3e1..9ec20bf8fd4 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -94,14 +94,31 @@ pub fn source_root() -> PathBuf { } /// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. +#[cfg(target_family = "windows")] pub fn create_symlink, Q: AsRef>(original: P, link: Q) { - if is_windows() { - use std::os::windows::fs; - fs::symlink_file(original, link).unwrap(); - } else { - use std::os::unix::fs; - fs::symlink(original, link).unwrap(); + if link.as_ref().exists() { + std::fs::remove_dir(link.as_ref()).unwrap(); + } + use std::os::windows::fs; + fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!( + "failed to create symlink {:?} for {:?}", + link.as_ref().display(), + original.as_ref().display(), + )); +} + +/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. +#[cfg(target_family = "unix")] +pub fn create_symlink, Q: AsRef>(original: P, link: Q) { + if link.as_ref().exists() { + std::fs::remove_dir(link.as_ref()).unwrap(); } + use std::os::unix::fs; + fs::symlink(original.as_ref(), link.as_ref()).expect(&format!( + "failed to create symlink {:?} for {:?}", + link.as_ref().display(), + original.as_ref().display(), + )); } /// Construct the static library name based on the platform. @@ -125,11 +142,7 @@ pub fn static_lib_name(name: &str) -> String { // ``` assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace"); - if is_msvc() { - format!("{name}.lib") - } else { - format!("lib{name}.a") - } + if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") } } /// Construct the dynamic library name based on the platform. @@ -176,11 +189,7 @@ pub fn rust_lib_name(name: &str) -> String { /// Construct the binary name based on platform. pub fn bin_name(name: &str) -> String { - if is_windows() { - format!("{name}.exe") - } else { - name.to_string() - } + if is_windows() { format!("{name}.exe") } else { name.to_string() } } /// Return the current working directory. diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index dc1310afde9..33918473197 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -228,7 +228,6 @@ run-make/std-core-cycle/Makefile run-make/symbol-mangling-hashed/Makefile run-make/symbol-visibility/Makefile run-make/symbols-include-type-name/Makefile -run-make/symlinked-libraries/Makefile run-make/sysroot-crates-are-unstable/Makefile run-make/target-cpu-native/Makefile run-make/target-specs/Makefile diff --git a/tests/run-make/symlinked-extern/rmake.rs b/tests/run-make/symlinked-extern/rmake.rs index a54989661dc..98f69aefbe6 100644 --- a/tests/run-make/symlinked-extern/rmake.rs +++ b/tests/run-make/symlinked-extern/rmake.rs @@ -10,17 +10,12 @@ //@ ignore-cross-compile -use run_make_support::{create_symlink, rustc, tmp_dir}; -use std::fs; +use run_make_support::{create_symlink, cwd, fs_wrapper, rustc}; fn main() { rustc().input("foo.rs").run(); - fs::create_dir_all(tmp_dir().join("other")).unwrap(); - create_symlink(tmp_dir().join("libfoo.rlib"), tmp_dir().join("other")); - rustc().input("bar.rs").library_search_path(tmp_dir()).run(); - rustc() - .input("baz.rs") - .extern_("foo", tmp_dir().join("other/libfoo.rlib")) - .library_search_path(tmp_dir()) - .run(); + fs_wrapper::create_dir_all("other"); + create_symlink("libfoo.rlib", "other"); + rustc().input("bar.rs").library_search_path(cwd()).run(); + rustc().input("baz.rs").extern_("foo", "other").library_search_path(cwd()).run(); } diff --git a/tests/run-make/symlinked-libraries/Makefile b/tests/run-make/symlinked-libraries/Makefile deleted file mode 100644 index fb0b6127e6f..00000000000 --- a/tests/run-make/symlinked-libraries/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# ignore-windows -# `ln` is actually `cp` on msys. - -all: - $(RUSTC) foo.rs -C prefer-dynamic - mkdir -p $(TMPDIR)/other - ln -nsf $(TMPDIR)/$(call DYLIB_GLOB,foo) $(TMPDIR)/other - $(RUSTC) bar.rs -L $(TMPDIR)/other diff --git a/tests/run-make/symlinked-libraries/rmake.rs b/tests/run-make/symlinked-libraries/rmake.rs new file mode 100644 index 00000000000..eaf0c44206a --- /dev/null +++ b/tests/run-make/symlinked-libraries/rmake.rs @@ -0,0 +1,16 @@ +// When a directory and a symlink simultaneously exist with the same name, +// setting that name as the library search path should not cause rustc +// to avoid looking in the symlink and cause an error. This test creates +// a directory and a symlink named "other", and places the library in the symlink. +// If it succeeds, the library was successfully found. +// See https://github.com/rust-lang/rust/issues/12459 + +//@ ignore-cross-compile +use run_make_support::{create_symlink, dynamic_lib_name, fs_wrapper, rustc}; + +fn main() { + rustc().input("foo.rs").arg("-Cprefer-dynamic").run(); + fs_wrapper::create_dir_all("other"); + create_symlink(dynamic_lib_name("foo"), "other"); + rustc().input("bar.rs").library_search_path("other").run(); +} diff --git a/tests/run-make/symlinked-rlib/rmake.rs b/tests/run-make/symlinked-rlib/rmake.rs index d451c62a2f3..3759ca25928 100644 --- a/tests/run-make/symlinked-rlib/rmake.rs +++ b/tests/run-make/symlinked-rlib/rmake.rs @@ -7,10 +7,10 @@ //@ ignore-cross-compile -use run_make_support::{create_symlink, rustc, tmp_dir}; +use run_make_support::{create_symlink, cwd, rustc}; fn main() { - rustc().input("foo.rs").crate_type("rlib").output(tmp_dir().join("foo.xxx")).run(); - create_symlink(tmp_dir().join("foo.xxx"), tmp_dir().join("libfoo.rlib")); - rustc().input("bar.rs").library_search_path(tmp_dir()); + rustc().input("foo.rs").crate_type("rlib").output("foo.xxx").run(); + create_symlink("foo.xxx", "libfoo.rlib"); + rustc().input("bar.rs").library_search_path(cwd()).run(); } -- cgit 1.4.1-3-g733a5 From 63bdcaa2d92bf5dba4dab23abb4e2b811e565438 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Jun 2024 15:19:40 +0200 Subject: add is_none_or --- library/core/src/option.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index e253cfd2822..d90b9cdb4b5 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -654,6 +654,32 @@ impl Option { !self.is_some() } + /// Returns `true` if the option is a [`None`] or the value inside of it matches a predicate. + /// + /// # Examples + /// + /// ``` + /// #![feature(is_none_or)] + /// + /// let x: Option = Some(2); + /// assert_eq!(x.is_none_or(|x| x > 1), true); + /// + /// let x: Option = Some(0); + /// assert_eq!(x.is_none_or(|x| x > 1), false); + /// + /// let x: Option = None; + /// assert_eq!(x.is_none_or(|x| x > 1), true); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "is_none_or", issue = "none")] + pub fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool { + match self { + None => true, + Some(x) => f(x), + } + } + ///////////////////////////////////////////////////////////////////////// // Adapter for working with references ///////////////////////////////////////////////////////////////////////// -- cgit 1.4.1-3-g733a5 From 4c208ac233df3b57f48298d5a911354fe8189320 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Jun 2024 15:22:23 +0200 Subject: use is_none_or in some places in the compiler --- compiler/rustc_const_eval/src/interpret/eval_context.rs | 2 +- compiler/rustc_const_eval/src/interpret/memory.rs | 2 +- compiler/rustc_const_eval/src/interpret/projection.rs | 2 +- compiler/rustc_const_eval/src/lib.rs | 1 + compiler/rustc_hir_typeck/src/_match.rs | 2 +- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 4 ++-- compiler/rustc_hir_typeck/src/lib.rs | 1 + src/tools/miri/src/lib.rs | 1 + src/tools/miri/src/shims/foreign_items.rs | 4 ++-- src/tools/rust-analyzer/crates/hir-ty/src/display.rs | 1 + 13 files changed, 15 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 7c2100fcbe3..80dc23ce303 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1057,7 +1057,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false, - ty::Tuple(tys) => tys.last().iter().all(|ty| is_very_trivially_sized(**ty)), + ty::Tuple(tys) => tys.last().is_none_or(|ty| is_very_trivially_sized(*ty)), ty::Pat(ty, ..) => is_very_trivially_sized(*ty), diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 7eb73e9b52f..5d14e8fb5a4 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -446,7 +446,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (alloc_size, _alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?; // Test bounds. // It is sufficient to check this for the end pointer. Also check for overflow! - if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) { + if offset.checked_add(size, &self.tcx).is_none_or(|end| end > alloc_size) { throw_ub!(PointerOutOfBounds { alloc_id, alloc_size, diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 09e1a59dfa1..efa01b54342 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -300,7 +300,7 @@ where ) -> InterpResult<'tcx, P> { let len = base.len(self)?; // also asserts that we have a type where this makes sense let actual_to = if from_end { - if from.checked_add(to).map_or(true, |to| to > len) { + if from.checked_add(to).is_none_or(|to| to > len) { // This can only be reached in ConstProp and non-rustc-MIR. throw_ub!(BoundsCheckFailed { len: len, index: from.saturating_add(to) }); } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 45ea3ec08f8..50a4d0612cc 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -6,6 +6,7 @@ #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] +#![feature(is_none_or)] #![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index a599e8d05fd..281af80bff5 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -234,7 +234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ret_ty = ret_coercion.borrow().expected_ty(); let ret_ty = self.infcx.shallow_resolve(ret_ty); self.can_coerce(arm_ty, ret_ty) - && prior_arm.map_or(true, |(_, ty, _)| self.can_coerce(ty, ret_ty)) + && prior_arm.is_none_or(|(_, ty, _)| self.can_coerce(ty, ret_ty)) // The match arms need to unify for the case of `impl Trait`. && !matches!(ret_ty.kind(), ty::Alias(ty::Opaque, ..)) } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index e54a07786cd..fcd22b74676 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -913,7 +913,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { if self .tcx .upvars_mentioned(closure_def_id_a.expect_local()) - .map_or(true, |u| u.is_empty()) => + .is_none_or(|u| u.is_empty()) => { // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 5b27ebe3416..3a27fce8146 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1560,7 +1560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the length is 0, we don't create any elements, so we don't copy any. If the length is 1, we // don't copy that one element, we move it. Only check for Copy if the length is larger. - if count.try_eval_target_usize(tcx, self.param_env).map_or(true, |len| len > 1) { + if count.try_eval_target_usize(tcx, self.param_env).is_none_or(|len| len > 1) { let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); let code = traits::ObligationCauseCode::RepeatElementCopy { is_constable, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index b8333d47493..1cd5e784e19 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2240,7 +2240,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (idx, (generic_param, param)) in params_with_generics.iter().enumerate().filter(|(idx, _)| { check_for_matched_generics - || expected_idx.map_or(true, |expected_idx| expected_idx == *idx) + || expected_idx.is_none_or(|expected_idx| expected_idx == *idx) }) { let Some(generic_param) = generic_param else { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 9ab89f3444c..8a88e5a6ff4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -440,7 +440,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for // `as_ref` and `as_deref` compatibility. - let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| { + let error_tys_equate_as_ref = error_tys.is_none_or(|(found, expected)| { self.can_eq( self.param_env, Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, found), @@ -492,7 +492,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && Some(adt.did()) == self.tcx.lang_items().string() && peeled.is_str() // `Result::map`, conversely, does not take ref of the error type. - && error_tys.map_or(true, |(found, expected)| { + && error_tys.is_none_or(|(found, expected)| { self.can_eq(self.param_env, found, expected) }) { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index b0fd6de3496..a87ee7b4554 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -4,6 +4,7 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(if_let_guard)] +#![feature(is_none_or)] #![feature(let_chains)] #![feature(never_type)] #![feature(try_blocks)] diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 11cbbde06aa..f8410db4dd0 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -13,6 +13,7 @@ #![feature(lint_reasons)] #![feature(trait_upcasting)] #![feature(strict_overflow_ops)] +#![feature(is_none_or)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 898fc111fd4..911958e558c 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -396,12 +396,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // If the newly promised alignment is bigger than the native alignment of this // allocation, and bigger than the previously promised alignment, then set it. if align > alloc_align - && !this + && this .machine .symbolic_alignment .get_mut() .get(&alloc_id) - .is_some_and(|&(_, old_align)| align <= old_align) + .is_none_or(|&(_, old_align)| align > old_align) { this.machine.symbolic_alignment.get_mut().insert(alloc_id, (offset, align)); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 5a9621bb69a..241690d0089 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -1387,6 +1387,7 @@ fn generic_args_sans_defaults<'ga>( } // otherwise, if the arg is equal to the param default, hide it (unless the // default is an error which can happen for the trait Self type) + #[allow(unstable_name_collisions)] default_parameters.get(i).is_none_or(|default_parameter| { // !is_err(default_parameter.skip_binders()) // && -- cgit 1.4.1-3-g733a5 From ffe543933054a62d4aa8b292513bb1fb5d488188 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 12 Jun 2024 15:32:25 +0000 Subject: Add test for walking order dependent opaque type behaviour --- tests/ui/impl-trait/associated-type-undefine.rs | 28 ++++++++++++++++++++++ .../ui/impl-trait/associated-type-undefine.stderr | 20 ++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/ui/impl-trait/associated-type-undefine.rs create mode 100644 tests/ui/impl-trait/associated-type-undefine.stderr diff --git a/tests/ui/impl-trait/associated-type-undefine.rs b/tests/ui/impl-trait/associated-type-undefine.rs new file mode 100644 index 00000000000..c8f07021fbf --- /dev/null +++ b/tests/ui/impl-trait/associated-type-undefine.rs @@ -0,0 +1,28 @@ +#![feature(impl_trait_in_assoc_type)] + +trait Foo: Sized { + type Bar; + type Gat; + fn foo(self) -> (::Gat, ::Gat); +} + +impl Foo for u32 { + type Bar = (); + type Gat = (); + fn foo(self) -> (::Gat, ::Gat) { + ((), ()) + } +} + +impl Foo for () { + type Bar = impl Sized; + type Gat = ::Bar; + // Because we encounter `Gat` first, we never walk into another `Gat` + // again, thus missing the opaque type that we could be defining. + fn foo(self) -> (::Gat, ::Gat) { + ((), ()) + //~^ ERROR: mismatched types + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/associated-type-undefine.stderr b/tests/ui/impl-trait/associated-type-undefine.stderr new file mode 100644 index 00000000000..5d9d525eb93 --- /dev/null +++ b/tests/ui/impl-trait/associated-type-undefine.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/associated-type-undefine.rs:23:14 + | +LL | type Bar = impl Sized; + | ---------- the expected opaque type +... +LL | ((), ()) + | ^^ expected opaque type, found `()` + | + = note: expected opaque type `<() as Foo>::Bar` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/associated-type-undefine.rs:22:8 + | +LL | fn foo(self) -> (::Gat, ::Gat) { + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. -- cgit 1.4.1-3-g733a5 From 48d342536421b6806dcfe3c0c76718249dbea6bc Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 12 Jun 2024 17:33:52 +0000 Subject: Remove some msys2 utils --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 521f8ef0f5a..4cf0e5fba53 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,8 +95,6 @@ jobs: path-type: inherit install: > make - dos2unix - diffutils - name: disable git crlf conversion run: git config --global core.autocrlf false -- cgit 1.4.1-3-g733a5 From 9bba39c287a021c97a5b36fcced8dd34a32a3b87 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Wed, 12 Jun 2024 20:52:40 +0200 Subject: Improve error message if dependency installation in tidy fails --- src/tools/tidy/src/ext_tool_checks.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index 2c97a39f100..b54fa5c6b2c 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -274,13 +274,18 @@ fn create_venv_at_path(path: &Path) -> Result<(), Error> { if out.status.success() { return Ok(()); } - let err = if String::from_utf8_lossy(&out.stderr).contains("No module named virtualenv") { + + let stderr = String::from_utf8_lossy(&out.stderr); + let err = if stderr.contains("No module named virtualenv") { Error::Generic(format!( "virtualenv not found: you may need to install it \ (`python3 -m pip install venv`)" )) } else { - Error::Generic(format!("failed to create venv at '{}' using {sys_py}", path.display())) + Error::Generic(format!( + "failed to create venv at '{}' using {sys_py}: {stderr}", + path.display() + )) }; Err(err) } -- cgit 1.4.1-3-g733a5 From fac173392588bcf10c18288f791f2bb4c145d43b Mon Sep 17 00:00:00 2001 From: Slanterns Date: Thu, 13 Jun 2024 02:57:36 +0800 Subject: Simplify `try_*` on `Iterator` --- library/core/src/iter/traits/iterator.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index cee99e28b5a..733d414d444 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2080,8 +2080,7 @@ pub trait Iterator { fn try_collect(&mut self) -> ChangeOutputType where Self: Sized, - ::Item: Try, - <::Item as Try>::Residual: Residual, + Self::Item: Try>, B: FromIterator<::Output>, { try_process(ByRefSized(self), |i| i.collect()) @@ -2689,12 +2688,13 @@ pub trait Iterator { #[inline] #[unstable(feature = "iterator_try_reduce", reason = "new API", issue = "87053")] #[rustc_do_not_const_check] - fn try_reduce(&mut self, f: F) -> ChangeOutputType> + fn try_reduce( + &mut self, + f: impl FnMut(Self::Item, Self::Item) -> R, + ) -> ChangeOutputType> where Self: Sized, - F: FnMut(Self::Item, Self::Item) -> R, - R: Try, - R::Residual: Residual>, + R: Try>>, { let first = match self.next() { Some(i) => i, @@ -2956,12 +2956,13 @@ pub trait Iterator { #[inline] #[unstable(feature = "try_find", reason = "new API", issue = "63178")] #[rustc_do_not_const_check] - fn try_find(&mut self, f: F) -> ChangeOutputType> + fn try_find( + &mut self, + f: impl FnMut(&Self::Item) -> R, + ) -> ChangeOutputType> where Self: Sized, - F: FnMut(&Self::Item) -> R, - R: Try, - R::Residual: Residual>, + R: Try>>, { #[inline] fn check( -- cgit 1.4.1-3-g733a5 From 6d2493bf5d6c97bc52aa109944a7f27ee456192e Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 12 Jun 2024 12:48:35 -0700 Subject: ci: Update centos:7 to use vault repos CentOS 7 is going EOL on June 30, after which its package repos will no longer exist on the regular mirrors. We'll still be able to access packages from the vault server though, and can start doing so now. This affects `dist-i686-linux` and `dist-x86_64-linux`. I also removed `epel-release` because we were only using that for its `cmake3`, but we've been building our own version for a while. --- src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile | 6 +++++- src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile index 1704bef1e4e..414bcc52484 100644 --- a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile @@ -6,8 +6,12 @@ FROM centos:7 WORKDIR /build +# CentOS 7 EOL is June 30, 2024, but the repos remain in the vault. +RUN sed -i /etc/yum.repos.d/*.repo -e 's!^mirrorlist!#mirrorlist!' \ + -e 's!^#baseurl=http://mirror.centos.org/!baseurl=https://vault.centos.org/!' +RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf + RUN yum upgrade -y && \ - yum install -y epel-release && \ yum install -y \ automake \ bzip2 \ 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 4e1aae98221..4aa1a3ccc2a 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 @@ -6,8 +6,12 @@ FROM centos:7 WORKDIR /build +# CentOS 7 EOL is June 30, 2024, but the repos remain in the vault. +RUN sed -i /etc/yum.repos.d/*.repo -e 's!^mirrorlist!#mirrorlist!' \ + -e 's!^#baseurl=http://mirror.centos.org/!baseurl=https://vault.centos.org/!' +RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf + RUN yum upgrade -y && \ - yum install -y epel-release && \ yum install -y \ automake \ bzip2 \ -- cgit 1.4.1-3-g733a5 From 6d936263515ad4ca189553759f373abeae9bb548 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 12 Jun 2024 15:20:58 -0500 Subject: docs(rustc): Help users to check-cfg Cargo docs --- src/doc/rustc/src/check-cfg.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/rustc/src/check-cfg.md b/src/doc/rustc/src/check-cfg.md index 8e39adaa438..a1fc71307b3 100644 --- a/src/doc/rustc/src/check-cfg.md +++ b/src/doc/rustc/src/check-cfg.md @@ -14,6 +14,9 @@ whether to check conditions and how to check them. > **Note:** No implicit expectation is added when using `--cfg`. Users are expected to pass all expected names and values using the _check cfg specification_. +> **Note:** For interacting with this through Cargo, +see [Cargo Specifics](check-cfg/cargo-specifics.md) page. + [^reachable]: `rustc` promises to at least check reachable `#[cfg]`, and while non-reachable `#[cfg]` are not currently checked, they may well be checked in the future without it being a breaking change. -- cgit 1.4.1-3-g733a5 From 4b809b9438e891ce28dbf90059f1149a7a5f19a2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 16:22:49 -0400 Subject: Move MatchAgainstFreshVars to old solver --- compiler/rustc_infer/src/infer/relate/_match.rs | 121 --------------------- compiler/rustc_infer/src/infer/relate/mod.rs | 2 - .../src/traits/select/_match.rs | 121 +++++++++++++++++++++ .../rustc_trait_selection/src/traits/select/mod.rs | 4 +- 4 files changed, 123 insertions(+), 125 deletions(-) delete mode 100644 compiler/rustc_infer/src/infer/relate/_match.rs create mode 100644 compiler/rustc_trait_selection/src/traits/select/_match.rs diff --git a/compiler/rustc_infer/src/infer/relate/_match.rs b/compiler/rustc_infer/src/infer/relate/_match.rs deleted file mode 100644 index 30a066a265a..00000000000 --- a/compiler/rustc_infer/src/infer/relate/_match.rs +++ /dev/null @@ -1,121 +0,0 @@ -use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; -use tracing::{debug, instrument}; - -use super::{structurally_relate_tys, Relate, RelateResult, TypeRelation}; -use crate::infer::relate; - -/// A type "A" *matches* "B" if the fresh types in B could be -/// instantiated with values so as to make it equal to A. Matching is -/// intended to be used only on freshened types, and it basically -/// indicates if the non-freshened versions of A and B could have been -/// unified. -/// -/// It is only an approximation. If it yields false, unification would -/// definitely fail, but a true result doesn't mean unification would -/// succeed. This is because we don't track the "side-constraints" on -/// type variables, nor do we track if the same freshened type appears -/// more than once. To some extent these approximations could be -/// fixed, given effort. -/// -/// Like subtyping, matching is really a binary relation, so the only -/// important thing about the result is Ok/Err. Also, matching never -/// affects any type variables or unification state. -pub struct MatchAgainstFreshVars<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> MatchAgainstFreshVars<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>) -> MatchAgainstFreshVars<'tcx> { - MatchAgainstFreshVars { tcx } - } -} - -impl<'tcx> TypeRelation> for MatchAgainstFreshVars<'tcx> { - fn tag(&self) -> &'static str { - "MatchAgainstFreshVars" - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn relate_with_variance>>( - &mut self, - _: ty::Variance, - _: ty::VarianceDiagInfo>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - self.relate(a, b) - } - - #[instrument(skip(self), level = "debug")] - fn regions( - &mut self, - a: ty::Region<'tcx>, - _b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - Ok(a) - } - - #[instrument(skip(self), level = "debug")] - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - if a == b { - return Ok(a); - } - - match (a.kind(), b.kind()) { - ( - _, - &ty::Infer(ty::FreshTy(_)) - | &ty::Infer(ty::FreshIntTy(_)) - | &ty::Infer(ty::FreshFloatTy(_)), - ) => Ok(a), - - (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) - } - - (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)), - - _ => structurally_relate_tys(self, a, b), - } - } - - fn consts( - &mut self, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - debug!("{}.consts({:?}, {:?})", self.tag(), a, b); - if a == b { - return Ok(a); - } - - match (a.kind(), b.kind()) { - (_, ty::ConstKind::Infer(InferConst::Fresh(_))) => { - return Ok(a); - } - - (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { - return Err(TypeError::ConstMismatch(ExpectedFound::new(true, a, b))); - } - - _ => {} - } - - relate::structurally_relate_consts(self, a, b) - } - - fn binders( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate>, - { - Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) - } -} diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index e7b50479b85..41cc945492d 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -4,11 +4,9 @@ pub use rustc_middle::ty::relate::*; -pub use self::_match::MatchAgainstFreshVars; pub use self::combine::CombineFields; pub use self::combine::PredicateEmittingRelation; -pub mod _match; pub(super) mod combine; mod generalize; mod glb; diff --git a/compiler/rustc_trait_selection/src/traits/select/_match.rs b/compiler/rustc_trait_selection/src/traits/select/_match.rs new file mode 100644 index 00000000000..50d8e96aaf9 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/select/_match.rs @@ -0,0 +1,121 @@ +use rustc_infer::infer::relate::{ + self, structurally_relate_tys, Relate, RelateResult, TypeRelation, +}; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; +use tracing::{debug, instrument}; + +/// A type "A" *matches* "B" if the fresh types in B could be +/// instantiated with values so as to make it equal to A. Matching is +/// intended to be used only on freshened types, and it basically +/// indicates if the non-freshened versions of A and B could have been +/// unified. +/// +/// It is only an approximation. If it yields false, unification would +/// definitely fail, but a true result doesn't mean unification would +/// succeed. This is because we don't track the "side-constraints" on +/// type variables, nor do we track if the same freshened type appears +/// more than once. To some extent these approximations could be +/// fixed, given effort. +/// +/// Like subtyping, matching is really a binary relation, so the only +/// important thing about the result is Ok/Err. Also, matching never +/// affects any type variables or unification state. +pub struct MatchAgainstFreshVars<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MatchAgainstFreshVars<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> MatchAgainstFreshVars<'tcx> { + MatchAgainstFreshVars { tcx } + } +} + +impl<'tcx> TypeRelation> for MatchAgainstFreshVars<'tcx> { + fn tag(&self) -> &'static str { + "MatchAgainstFreshVars" + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn relate_with_variance>>( + &mut self, + _: ty::Variance, + _: ty::VarianceDiagInfo>, + a: T, + b: T, + ) -> RelateResult<'tcx, T> { + self.relate(a, b) + } + + #[instrument(skip(self), level = "debug")] + fn regions( + &mut self, + a: ty::Region<'tcx>, + _b: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + Ok(a) + } + + #[instrument(skip(self), level = "debug")] + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + if a == b { + return Ok(a); + } + + match (a.kind(), b.kind()) { + ( + _, + &ty::Infer(ty::FreshTy(_)) + | &ty::Infer(ty::FreshIntTy(_)) + | &ty::Infer(ty::FreshFloatTy(_)), + ) => Ok(a), + + (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { + Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) + } + + (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)), + + _ => structurally_relate_tys(self, a, b), + } + } + + fn consts( + &mut self, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { + debug!("{}.consts({:?}, {:?})", self.tag(), a, b); + if a == b { + return Ok(a); + } + + match (a.kind(), b.kind()) { + (_, ty::ConstKind::Infer(InferConst::Fresh(_))) => { + return Ok(a); + } + + (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { + return Err(TypeError::ConstMismatch(ExpectedFound::new(true, a, b))); + } + + _ => {} + } + + relate::structurally_relate_consts(self, a, b) + } + + fn binders( + &mut self, + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> + where + T: Relate>, + { + Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4306a803524..42998fbd862 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -32,7 +32,6 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_infer::infer::relate::MatchAgainstFreshVars; use rustc_infer::infer::relate::TypeRelation; use rustc_infer::infer::BoundRegionConversionTime; use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType; @@ -60,6 +59,7 @@ use std::ops::ControlFlow; pub use rustc_middle::traits::select::*; use rustc_middle::ty::print::with_no_trimmed_paths; +mod _match; mod candidate_assembly; mod confirmation; @@ -2719,7 +2719,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { previous: ty::PolyTraitPredicate<'tcx>, current: ty::PolyTraitPredicate<'tcx>, ) -> bool { - let mut matcher = MatchAgainstFreshVars::new(self.tcx()); + let mut matcher = _match::MatchAgainstFreshVars::new(self.tcx()); matcher.relate(previous, current).is_ok() } -- cgit 1.4.1-3-g733a5 From 54fa4b0b741cacb76b3014e96d974283ff81c5d0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 15:36:35 -0400 Subject: Use Variance glob import everywhere --- compiler/rustc_borrowck/src/type_check/mod.rs | 12 +++---- .../rustc_borrowck/src/type_check/relate_tys.rs | 40 ++++++++-------------- compiler/rustc_infer/src/infer/at.rs | 8 ++--- compiler/rustc_infer/src/infer/opaque_types/mod.rs | 4 +-- .../rustc_infer/src/infer/outlives/for_liveness.rs | 4 +-- .../rustc_infer/src/infer/relate/generalize.rs | 18 +++++----- compiler/rustc_infer/src/infer/relate/glb.rs | 7 +--- compiler/rustc_infer/src/infer/relate/lub.rs | 7 +--- .../rustc_infer/src/infer/relate/type_relating.rs | 10 +++--- compiler/rustc_middle/src/ty/mod.rs | 1 - compiler/rustc_middle/src/values.rs | 2 +- compiler/rustc_mir_build/src/build/matches/mod.rs | 2 +- compiler/rustc_mir_build/src/thir/cx/block.rs | 2 +- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 4 +-- compiler/rustc_mir_transform/src/inline.rs | 27 ++++----------- compiler/rustc_smir/src/rustc_smir/convert/ty.rs | 8 ++--- .../src/solve/alias_relate.rs | 6 ++-- .../src/solve/normalizes_to/mod.rs | 2 +- compiler/rustc_type_ir/src/lib.rs | 1 + compiler/rustc_type_ir/src/relate.rs | 20 +++++------ 20 files changed, 74 insertions(+), 111 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index fcfb297d50a..d62f87de61a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -328,7 +328,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { if let Some(annotation_index) = constant.user_ty { if let Err(terr) = self.cx.relate_type_and_user_type( constant.const_.ty(), - ty::Variance::Invariant, + ty::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![] }, locations, ConstraintCategory::Boring, @@ -451,7 +451,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { if let Err(terr) = self.cx.relate_type_and_user_type( ty, - ty::Variance::Invariant, + ty::Invariant, user_ty, Locations::All(*span), ConstraintCategory::TypeAnnotation, @@ -1095,7 +1095,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ) -> Result<(), NoSolution> { // Use this order of parameters because the sup type is usually the // "expected" type in diagnostics. - self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category) + self.relate_types(sup, ty::Contravariant, sub, locations, category) } #[instrument(skip(self, category), level = "debug")] @@ -1106,7 +1106,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory<'tcx>, ) -> Result<(), NoSolution> { - self.relate_types(expected, ty::Variance::Invariant, found, locations, category) + self.relate_types(expected, ty::Invariant, found, locations, category) } #[instrument(skip(self), level = "debug")] @@ -1146,7 +1146,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { trace!(?curr_projected_ty); let ty = curr_projected_ty.ty; - self.relate_types(ty, v.xform(ty::Variance::Contravariant), a, locations, category)?; + self.relate_types(ty, v.xform(ty::Contravariant), a, locations, category)?; Ok(()) } @@ -1248,7 +1248,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(annotation_index) = self.rvalue_user_ty(rv) { if let Err(terr) = self.relate_type_and_user_type( rv_ty, - ty::Variance::Invariant, + ty::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![] }, location.to_locations(), ConstraintCategory::Boring, diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index c531c9b209b..b9a82046e59 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -50,14 +50,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory<'tcx>, ) -> Result<(), NoSolution> { - NllTypeRelating::new( - self, - locations, - category, - UniverseInfo::other(), - ty::Variance::Invariant, - ) - .relate(a, b)?; + NllTypeRelating::new(self, locations, category, UniverseInfo::other(), ty::Invariant) + .relate(a, b)?; Ok(()) } } @@ -106,15 +100,15 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { fn ambient_covariance(&self) -> bool { match self.ambient_variance { - ty::Variance::Covariant | ty::Variance::Invariant => true, - ty::Variance::Contravariant | ty::Variance::Bivariant => false, + ty::Covariant | ty::Invariant => true, + ty::Contravariant | ty::Bivariant => false, } } fn ambient_contravariance(&self) -> bool { match self.ambient_variance { - ty::Variance::Contravariant | ty::Variance::Invariant => true, - ty::Variance::Covariant | ty::Variance::Bivariant => false, + ty::Contravariant | ty::Invariant => true, + ty::Covariant | ty::Bivariant => false, } } @@ -336,11 +330,7 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx debug!(?self.ambient_variance); // In a bivariant context this always succeeds. - let r = if self.ambient_variance == ty::Variance::Bivariant { - Ok(a) - } else { - self.relate(a, b) - }; + let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) }; self.ambient_variance = old_ambient_variance; @@ -474,7 +464,7 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx } match self.ambient_variance { - ty::Variance::Covariant => { + ty::Covariant => { // Covariance, so we want `for<..> A <: for<..> B` -- // therefore we compare any instantiation of A (i.e., A // instantiated with existentials) against every @@ -489,7 +479,7 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx })?; } - ty::Variance::Contravariant => { + ty::Contravariant => { // Contravariance, so we want `for<..> A :> for<..> B` -- // therefore we compare every instantiation of A (i.e., A // instantiated with universals) against any @@ -504,7 +494,7 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx })?; } - ty::Variance::Invariant => { + ty::Invariant => { // Invariant, so we want `for<..> A == for<..> B` -- // therefore we want `exists<..> A == for<..> B` and // `exists<..> B == for<..> A`. @@ -525,7 +515,7 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx })?; } - ty::Variance::Bivariant => {} + ty::Bivariant => {} } Ok(a) @@ -584,23 +574,23 @@ impl<'bccx, 'tcx> PredicateEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { self.register_predicates([ty::Binder::dummy(match self.ambient_variance { - ty::Variance::Covariant => ty::PredicateKind::AliasRelate( + ty::Covariant => ty::PredicateKind::AliasRelate( a.into(), b.into(), ty::AliasRelationDirection::Subtype, ), // a :> b is b <: a - ty::Variance::Contravariant => ty::PredicateKind::AliasRelate( + ty::Contravariant => ty::PredicateKind::AliasRelate( b.into(), a.into(), ty::AliasRelationDirection::Subtype, ), - ty::Variance::Invariant => ty::PredicateKind::AliasRelate( + ty::Invariant => ty::PredicateKind::AliasRelate( a.into(), b.into(), ty::AliasRelationDirection::Equate, ), - ty::Variance::Bivariant => { + ty::Bivariant => { unreachable!("cannot defer an alias-relate goal with Bivariant variance (yet?)") } })]); diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 01bd732a4cd..ed47c8ad991 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -212,16 +212,16 @@ impl<'a, 'tcx> At<'a, 'tcx> { T: ToTrace<'tcx>, { match variance { - ty::Variance::Covariant => self.sub(define_opaque_types, expected, actual), - ty::Variance::Invariant => self.eq(define_opaque_types, expected, actual), - ty::Variance::Contravariant => self.sup(define_opaque_types, expected, actual), + ty::Covariant => self.sub(define_opaque_types, expected, actual), + ty::Invariant => self.eq(define_opaque_types, expected, actual), + ty::Contravariant => self.sup(define_opaque_types, expected, actual), // We could make this make sense but it's not readily // exposed and I don't feel like dealing with it. Note // that bivariance in general does a bit more than just // *nothing*, it checks that the types are the same // "modulo variance" basically. - ty::Variance::Bivariant => panic!("Bivariant given to `relate()`"), + ty::Bivariant => panic!("Bivariant given to `relate()`"), } } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 7114b888718..b8dd501a721 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -345,7 +345,7 @@ impl<'tcx> InferCtxt<'tcx> { .args .iter() .enumerate() - .filter(|(i, _)| variances[*i] == ty::Variance::Invariant) + .filter(|(i, _)| variances[*i] == ty::Invariant) .filter_map(|(_, arg)| match arg.unpack() { GenericArgKind::Lifetime(r) => Some(r), GenericArgKind::Type(_) | GenericArgKind::Const(_) => None, @@ -441,7 +441,7 @@ where let variances = self.tcx.variances_of(*def_id); for (v, s) in std::iter::zip(variances, args.iter()) { - if *v != ty::Variance::Bivariant { + if *v != ty::Bivariant { s.visit_with(self); } } diff --git a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs index 488f435994d..c02ab98b2ba 100644 --- a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs +++ b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs @@ -102,9 +102,7 @@ where }; for (idx, s) in args.iter().enumerate() { - if variances.map(|variances| variances[idx]) - != Some(ty::Variance::Bivariant) - { + if variances.map(|variances| variances[idx]) != Some(ty::Bivariant) { s.visit_with(self); } } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 87a2f0b4580..d6e57d85387 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -83,16 +83,16 @@ impl<'tcx> InferCtxt<'tcx> { // mention `?0`. if self.next_trait_solver() { let (lhs, rhs, direction) = match instantiation_variance { - ty::Variance::Invariant => { + ty::Invariant => { (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Equate) } - ty::Variance::Covariant => { + ty::Covariant => { (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Subtype) } - ty::Variance::Contravariant => { + ty::Contravariant => { (source_ty.into(), generalized_ty.into(), AliasRelationDirection::Subtype) } - ty::Variance::Bivariant => unreachable!("bivariant generalization"), + ty::Bivariant => unreachable!("bivariant generalization"), }; relation.register_predicates([ty::PredicateKind::AliasRelate(lhs, rhs, direction)]); @@ -192,7 +192,7 @@ impl<'tcx> InferCtxt<'tcx> { relation.span(), relation.structurally_relate_aliases(), target_vid, - ty::Variance::Invariant, + ty::Invariant, source_ct, )?; @@ -210,14 +210,14 @@ impl<'tcx> InferCtxt<'tcx> { // generalized const and the source. if target_is_expected { relation.relate_with_variance( - ty::Variance::Invariant, + ty::Invariant, ty::VarianceDiagInfo::default(), generalized_ct, source_ct, )?; } else { relation.relate_with_variance( - ty::Variance::Invariant, + ty::Invariant, ty::VarianceDiagInfo::default(), source_ct, generalized_ct, @@ -411,7 +411,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { a_arg: ty::GenericArgsRef<'tcx>, b_arg: ty::GenericArgsRef<'tcx>, ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> { - if self.ambient_variance == ty::Variance::Invariant { + if self.ambient_variance == ty::Invariant { // Avoid fetching the variance if we are in an invariant // context; no need, and it can induce dependency cycles // (e.g., #41849). @@ -667,7 +667,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { // structural. ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => { let args = self.relate_with_variance( - ty::Variance::Invariant, + ty::Invariant, ty::VarianceDiagInfo::default(), args, args, diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index cc17e60a79b..067004ecaeb 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -94,12 +94,7 @@ impl<'tcx> TypeRelation> for Glb<'_, '_, 'tcx> { // When higher-ranked types are involved, computing the GLB is // very challenging, switch to invariance. This is obviously // overly conservative but works ok in practice. - self.relate_with_variance( - ty::Variance::Invariant, - ty::VarianceDiagInfo::default(), - a, - b, - )?; + self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?; Ok(a) } else { Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?)) diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index e9d300d349c..2184416b4cc 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -94,12 +94,7 @@ impl<'tcx> TypeRelation> for Lub<'_, '_, 'tcx> { // When higher-ranked types are involved, computing the LUB is // very challenging, switch to invariance. This is obviously // overly conservative but works ok in practice. - self.relate_with_variance( - ty::Variance::Invariant, - ty::VarianceDiagInfo::default(), - a, - b, - )?; + self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?; Ok(a) } else { Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?)) diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index f7b2f11e3d7..f2bec9392d5 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -42,7 +42,7 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { a_arg: ty::GenericArgsRef<'tcx>, b_arg: ty::GenericArgsRef<'tcx>, ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> { - if self.ambient_variance == ty::Variance::Invariant { + if self.ambient_variance == ty::Invariant { // Avoid fetching the variance if we are in an invariant // context; no need, and it can induce dependency cycles // (e.g., #41849). @@ -325,23 +325,23 @@ impl<'tcx> PredicateEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { self.register_predicates([ty::Binder::dummy(match self.ambient_variance { - ty::Variance::Covariant => ty::PredicateKind::AliasRelate( + ty::Covariant => ty::PredicateKind::AliasRelate( a.into(), b.into(), ty::AliasRelationDirection::Subtype, ), // a :> b is b <: a - ty::Variance::Contravariant => ty::PredicateKind::AliasRelate( + ty::Contravariant => ty::PredicateKind::AliasRelate( b.into(), a.into(), ty::AliasRelationDirection::Subtype, ), - ty::Variance::Invariant => ty::PredicateKind::AliasRelate( + ty::Invariant => ty::PredicateKind::AliasRelate( a.into(), b.into(), ty::AliasRelationDirection::Equate, ), - ty::Variance::Bivariant => { + ty::Bivariant => { unreachable!("Expected bivariance to be handled in relate_with_variance") } })]); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 83f8de6b6f9..d7804d444b0 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -16,7 +16,6 @@ pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeV pub use self::AssocItemContainer::*; pub use self::BorrowKind::*; pub use self::IntVarValue::*; -pub use self::Variance::*; use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; use crate::middle::privacy::EffectiveVisibilities; diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 4ae475d35d1..8c323188826 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -142,7 +142,7 @@ impl<'tcx> Value> for &[ty::Variance] { && let Some(def_id) = frame.query.def_id { let n = tcx.generics_of(def_id).own_params.len(); - vec![ty::Variance::Bivariant; n].leak() + vec![ty::Bivariant; n].leak() } else { span_bug!( cycle_error.usage.as_ref().unwrap().0, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 54138789369..544f27b84e9 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -699,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // exactly `T` (i.e., with invariance). The variance field, in // contrast, is intended to be used to relate `T` to the type of // ``. - ty::Variance::Invariant, + ty::Invariant, ), }, ); diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 54eafdd828a..95cd703dbb3 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -92,7 +92,7 @@ impl<'tcx> Cx<'tcx> { kind: PatKind::AscribeUserType { ascription: Ascription { annotation, - variance: ty::Variance::Covariant, + variance: ty::Covariant, }, subpattern: pattern, }, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 158ca91fcf1..93db1f61853 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -525,7 +525,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }; kind = PatKind::AscribeUserType { subpattern: Box::new(Pat { span, ty, kind }), - ascription: Ascription { annotation, variance: ty::Variance::Covariant }, + ascription: Ascription { annotation, variance: ty::Covariant }, }; } @@ -612,7 +612,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { annotation, // Note that use `Contravariant` here. See the // `variance` field documentation for details. - variance: ty::Variance::Contravariant, + variance: ty::Contravariant, }, }, ty: const_.ty(), diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index fe2237dd2e9..2cbe0a01e9e 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -225,13 +225,8 @@ impl<'tcx> Inliner<'tcx> { // Normally, this shouldn't be required, but trait normalization failure can create a // validation ICE. let output_type = callee_body.return_ty(); - if !util::relate_types( - self.tcx, - self.param_env, - ty::Variance::Covariant, - output_type, - destination_ty, - ) { + if !util::relate_types(self.tcx, self.param_env, ty::Covariant, output_type, destination_ty) + { trace!(?output_type, ?destination_ty); return Err("failed to normalize return type"); } @@ -261,13 +256,8 @@ impl<'tcx> Inliner<'tcx> { self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter()) { let input_type = callee_body.local_decls[input].ty; - if !util::relate_types( - self.tcx, - self.param_env, - ty::Variance::Covariant, - input_type, - arg_ty, - ) { + if !util::relate_types(self.tcx, self.param_env, ty::Covariant, input_type, arg_ty) + { trace!(?arg_ty, ?input_type); return Err("failed to normalize tuple argument type"); } @@ -276,13 +266,8 @@ impl<'tcx> Inliner<'tcx> { for (arg, input) in args.iter().zip(callee_body.args_iter()) { let input_type = callee_body.local_decls[input].ty; let arg_ty = arg.node.ty(&caller_body.local_decls, self.tcx); - if !util::relate_types( - self.tcx, - self.param_env, - ty::Variance::Covariant, - input_type, - arg_ty, - ) { + if !util::relate_types(self.tcx, self.param_env, ty::Covariant, input_type, arg_ty) + { trace!(?arg_ty, ?input_type); return Err("failed to normalize argument type"); } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 73bc87dc9ab..e3cd7187e77 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -866,10 +866,10 @@ impl<'tcx> Stable<'tcx> for ty::Variance { type T = stable_mir::mir::Variance; fn stable(&self, _: &mut Tables<'_>) -> Self::T { match self { - ty::Variance::Bivariant => stable_mir::mir::Variance::Bivariant, - ty::Variance::Contravariant => stable_mir::mir::Variance::Contravariant, - ty::Variance::Covariant => stable_mir::mir::Variance::Covariant, - ty::Variance::Invariant => stable_mir::mir::Variance::Invariant, + ty::Bivariant => stable_mir::mir::Variance::Bivariant, + ty::Contravariant => stable_mir::mir::Variance::Contravariant, + ty::Covariant => stable_mir::mir::Variance::Covariant, + ty::Invariant => stable_mir::mir::Variance::Invariant, } } } diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 4d7e2fc2cef..c521189d54a 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -55,8 +55,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { trace!(?lhs, ?rhs); let variance = match direction { - ty::AliasRelationDirection::Equate => ty::Variance::Invariant, - ty::AliasRelationDirection::Subtype => ty::Variance::Covariant, + ty::AliasRelationDirection::Equate => ty::Invariant, + ty::AliasRelationDirection::Subtype => ty::Covariant, }; match (lhs.to_alias_term(), rhs.to_alias_term()) { (None, None) => { @@ -72,7 +72,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.relate_rigid_alias_non_alias( param_env, alias, - variance.xform(ty::Variance::Contravariant), + variance.xform(ty::Contravariant), lhs, )?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 787f08a084e..38362a3032d 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -40,7 +40,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { Ok(res) => Ok(res), Err(NoSolution) => { let Goal { param_env, predicate: NormalizesTo { alias, term } } = goal; - self.relate_rigid_alias_non_alias(param_env, alias, ty::Variance::Invariant, term)?; + self.relate_rigid_alias_non_alias(param_env, alias, ty::Invariant, term)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index a76e278cc05..e92526b1d63 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -73,6 +73,7 @@ pub use DynKind::*; pub use InferTy::*; pub use RegionKind::*; pub use TyKind::*; +pub use Variance::*; rustc_index::newtype_index! { /// A [De Bruijn index][dbi] is a standard means of representing diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index cae1d13020d..8a6ba87b60e 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -128,7 +128,7 @@ pub fn relate_args_invariantly>( b_arg: I::GenericArgs, ) -> RelateResult { relation.tcx().mk_args_from_iter(iter::zip(a_arg, b_arg).map(|(a, b)| { - relation.relate_with_variance(ty::Variance::Invariant, VarianceDiagInfo::default(), a, b) + relation.relate_with_variance(ty::Invariant, VarianceDiagInfo::default(), a, b) })) } @@ -145,7 +145,7 @@ pub fn relate_args_with_variances>( let mut cached_ty = None; let params = iter::zip(a_arg, b_arg).enumerate().map(|(i, (a, b))| { let variance = variances[i]; - let variance_info = if variance == ty::Variance::Invariant && fetch_ty_for_diag { + let variance_info = if variance == ty::Invariant && fetch_ty_for_diag { let ty = *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).instantiate(tcx, &a_arg)); VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } @@ -191,7 +191,7 @@ impl Relate for ty::FnSig { relation.relate(a, b) } else { relation.relate_with_variance( - ty::Variance::Contravariant, + ty::Contravariant, VarianceDiagInfo::default(), a, b, @@ -311,13 +311,13 @@ impl Relate for ty::ExistentialProjection { })) } else { let term = relation.relate_with_variance( - ty::Variance::Invariant, + ty::Invariant, VarianceDiagInfo::default(), a.term, b.term, )?; let args = relation.relate_with_variance( - ty::Variance::Invariant, + ty::Invariant, VarianceDiagInfo::default(), a.args, b.args, @@ -466,9 +466,9 @@ pub fn structurally_relate_tys>( } let (variance, info) = match a_mutbl { - Mutability::Not => (ty::Variance::Covariant, VarianceDiagInfo::None), + Mutability::Not => (ty::Covariant, VarianceDiagInfo::None), Mutability::Mut => { - (ty::Variance::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) + (ty::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) } }; @@ -483,9 +483,9 @@ pub fn structurally_relate_tys>( } let (variance, info) = match a_mutbl { - Mutability::Not => (ty::Variance::Covariant, VarianceDiagInfo::None), + Mutability::Not => (ty::Covariant, VarianceDiagInfo::None), Mutability::Mut => { - (ty::Variance::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) + (ty::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) } }; @@ -612,7 +612,7 @@ pub fn structurally_relate_consts>( } let args = relation.relate_with_variance( - ty::Variance::Invariant, + ty::Invariant, VarianceDiagInfo::default(), au.args, bu.args, -- cgit 1.4.1-3-g733a5 From 9232bd2e83dcd14859131e978c96e8230c7b19a2 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 12 Jun 2024 15:27:27 -0500 Subject: docs(rustc): Link unexpected_cfgs to the Cargo.toml docs This is the first time we have a lint with configuration exposed in `Cargo.toml`. When this was done, interest was expressed in using this for other cases in the future. To this end, we need to make the documentation for the lint configuration discoverable from the documentation for that lint. --- compiler/rustc_lint_defs/src/builtin.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index d0d570db04f..e82e5d5bb65 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3256,7 +3256,11 @@ declare_lint! { /// See the [Checking Conditional Configurations][check-cfg] section for more /// details. /// + /// See the [Cargo Specifics][unexpected_cfgs_lint_config] section for configuring this lint in + /// `Cargo.toml`. + /// /// [check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html + /// [unexpected_cfgs_lint_config]: https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html#check-cfg-in-lintsrust-table pub UNEXPECTED_CFGS, Warn, "detects unexpected names and values in `#[cfg]` conditions", -- cgit 1.4.1-3-g733a5 From e171e648ea0dfd7af91c3cb8e66b53c516e910c5 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 12 Jun 2024 15:57:13 -0500 Subject: docs(rustc): De-emphasize --cfg/--check-cfg note At the suggestion of @Urgau --- src/doc/rustc/src/check-cfg.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc/src/check-cfg.md b/src/doc/rustc/src/check-cfg.md index a1fc71307b3..dfc4871b924 100644 --- a/src/doc/rustc/src/check-cfg.md +++ b/src/doc/rustc/src/check-cfg.md @@ -11,9 +11,6 @@ development process. In order to accomplish that goal, `rustc` accepts the `--check-cfg` flag, which specifies whether to check conditions and how to check them. -> **Note:** No implicit expectation is added when using `--cfg`. Users are expected to -pass all expected names and values using the _check cfg specification_. - > **Note:** For interacting with this through Cargo, see [Cargo Specifics](check-cfg/cargo-specifics.md) page. @@ -26,6 +23,9 @@ breaking change. To specify expected names and values, the _check cfg specification_ provides the `cfg(...)` option which enables specifying for an expected config name and it's expected values. +> **Note:** No implicit expectation is added when using `--cfg`. Users are expected to +pass all expected names and values using the _check cfg specification_. + It has this basic form: ```bash -- cgit 1.4.1-3-g733a5 From c8c6598f17128b3ac1ec3573dc54876d24cc7a77 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 12 Jun 2024 16:01:38 -0700 Subject: Unify intrinsics body handling in StableMIR rust-lang/rust#120675 introduced a new mechanism to declare intrinsics which will potentially replace the rust-intrinsic ABI. The new mechanism introduces a placeholder body and mark the intrinsic with #[rustc_intrinsic_must_be_overridden]. In practice, this means that backends should not generate code for the placeholder, and shim the intrinsic. The new annotation is an internal compiler implementation, and it doesn't need to be exposed to StableMIR users. In this PR, intrinsics marked with `rustc_intrinsic_must_be_overridden` are handled the same way as intrinsics that do not have a body. --- compiler/rustc_smir/src/rustc_smir/context.rs | 16 +++++----------- compiler/rustc_smir/src/rustc_smir/mod.rs | 21 +++++++++++++++++++-- compiler/stable_mir/src/compiler_interface.rs | 4 ---- compiler/stable_mir/src/ty.rs | 7 ++++++- tests/ui-fulldeps/stable-mir/check_intrinsics.rs | 19 ++++++++++++------- 5 files changed, 42 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index a8688c88601..64174981b79 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -63,9 +63,10 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } fn has_body(&self, def: DefId) -> bool { - let tables = self.0.borrow(); - let def_id = tables[def]; - tables.tcx.is_mir_available(def_id) + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let def_id = def.internal(&mut *tables, tcx); + tables.item_has_body(def_id) } fn foreign_modules(&self, crate_num: CrateNum) -> Vec { @@ -322,13 +323,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tcx.intrinsic(def_id).unwrap().name.to_string() } - fn intrinsic_must_be_overridden(&self, def: IntrinsicDef) -> bool { - let mut tables = self.0.borrow_mut(); - let tcx = tables.tcx; - let def_id = def.0.internal(&mut *tables, tcx); - tcx.intrinsic_raw(def_id).unwrap().must_be_overridden - } - fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; @@ -515,7 +509,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; tables - .has_body(instance) + .instance_has_body(instance) .then(|| BodyBuilder::new(tables.tcx, instance).build(&mut *tables)) } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index d13e7803326..89f9adfcfd6 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -51,9 +51,13 @@ impl<'tcx> Tables<'tcx> { self.mir_consts.create_or_fetch(constant) } - pub(crate) fn has_body(&self, instance: Instance<'tcx>) -> bool { + /// Return whether the instance as a body available. + /// + /// Items and intrinsics may have a body available from its definition. + /// Shims body may be generated depending on their type. + pub(crate) fn instance_has_body(&self, instance: Instance<'tcx>) -> bool { let def_id = instance.def_id(); - self.tcx.is_mir_available(def_id) + self.item_has_body(def_id) || !matches!( instance.def, ty::InstanceDef::Virtual(..) @@ -61,6 +65,19 @@ impl<'tcx> Tables<'tcx> { | ty::InstanceDef::Item(..) ) } + + /// Return whether the item has a body defined by the user. + /// + /// Note that intrinsics may have a placeholder body that shouldn't be used in practice. + /// In StableMIR, we handle this case as if the body is not available. + pub(crate) fn item_has_body(&self, def_id: DefId) -> bool { + let must_override = if let Some(intrinsic) = self.tcx.intrinsic(def_id) { + intrinsic.must_be_overridden + } else { + false + }; + !must_override && self.tcx.is_mir_available(def_id) + } } /// Build a stable mir crate from a given crate number. diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 085dfd9ea89..3e138e3c2e0 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -94,10 +94,6 @@ pub trait Context { /// Retrieve the plain function name of an intrinsic. fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol; - /// Returns whether the intrinsic has no meaningful body and all backends - /// need to shim all calls to it. - fn intrinsic_must_be_overridden(&self, def: IntrinsicDef) -> bool; - /// Retrieve the closure signature for the given generic arguments. fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig; diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index bcbe87f7303..cdf1b0641ff 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -658,6 +658,11 @@ impl FnDef { with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0))) } + // Check if the function body is available. + pub fn has_body(&self) -> bool { + with(|ctx| ctx.has_body(self.0)) + } + /// Get the information of the intrinsic if this function is a definition of one. pub fn as_intrinsic(&self) -> Option { with(|cx| cx.intrinsic(self.def_id())) @@ -684,7 +689,7 @@ impl IntrinsicDef { /// Returns whether the intrinsic has no meaningful body and all backends /// need to shim all calls to it. pub fn must_be_overridden(&self) -> bool { - with(|cx| cx.intrinsic_must_be_overridden(*self)) + with(|cx| !cx.has_body(self.0)) } } diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs index 7e247ce0c75..d7f37f36681 100644 --- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs +++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs @@ -55,16 +55,19 @@ fn test_intrinsics() -> ControlFlow<()> { /// /// If by any chance this test breaks because you changed how an intrinsic is implemented, please /// update the test to invoke a different intrinsic. +/// +/// In StableMIR, we only expose intrinsic body if they are not marked with +/// `rustc_intrinsic_must_be_overridden`. fn check_instance(instance: &Instance) { assert_eq!(instance.kind, InstanceKind::Intrinsic); let name = instance.intrinsic_name().unwrap(); if instance.has_body() { let Some(body) = instance.body() else { unreachable!("Expected a body") }; assert!(!body.blocks.is_empty()); - assert_matches!(name.as_str(), "likely" | "vtable_size"); + assert_eq!(&name, "likely"); } else { assert!(instance.body().is_none()); - assert_eq!(&name, "size_of_val"); + assert_matches!(name.as_str(), "size_of_val" | "vtable_size"); } } @@ -75,11 +78,13 @@ fn check_def(fn_def: FnDef) { let name = intrinsic.fn_name(); match name.as_str() { - "likely" | "size_of_val" => { + "likely" => { assert!(!intrinsic.must_be_overridden()); + assert!(fn_def.has_body()); } - "vtable_size" => { + "vtable_size" | "size_of_val" => { assert!(intrinsic.must_be_overridden()); + assert!(!fn_def.has_body()); } _ => unreachable!("Unexpected intrinsic: {}", name), } @@ -96,9 +101,9 @@ impl<'a> MirVisitor for CallsVisitor<'a> { TerminatorKind::Call { func, .. } => { let TyKind::RigidTy(RigidTy::FnDef(def, args)) = func.ty(self.locals).unwrap().kind() - else { - return; - }; + else { + return; + }; self.calls.push((def, args.clone())); } _ => {} -- cgit 1.4.1-3-g733a5 From 52b2c88bdfb27a2b5011ee76361e24b2cd31654b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 28 May 2024 14:50:22 -0400 Subject: Walk into alias-eq nested goals even if normalization fails --- .../src/solve/alias_relate.rs | 6 +++++ .../rustc_trait_selection/src/solve/fulfill.rs | 9 ++++---- .../src/solve/inspect/analyse.rs | 7 ++++-- ...direct-impl-for-trait-obj-coherence.next.stderr | 4 ++-- .../indirect-impl-for-trait-obj-coherence.rs | 2 +- .../occurs-check/associated-type.next.stderr | 4 ++-- .../do_not_recommend/as_expression.next.stderr | 2 +- .../opaque-type-unsatisfied-bound.rs | 1 + .../opaque-type-unsatisfied-bound.stderr | 11 ++++++++- .../const-region-infer-to-static-in-binder.stderr | 4 ++-- .../diagnostics/projection-trait-ref.rs | 17 ++++++++++++++ .../diagnostics/projection-trait-ref.stderr | 26 ++++++++++++++++++++++ .../next-solver/specialization-transmute.stderr | 8 +++---- .../issue-84660-unsoundness.next.stderr | 4 ++-- 14 files changed, 83 insertions(+), 22 deletions(-) create mode 100644 tests/ui/traits/next-solver/diagnostics/projection-trait-ref.rs create mode 100644 tests/ui/traits/next-solver/diagnostics/projection-trait-ref.stderr diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 4d7e2fc2cef..59a8de99b8f 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -48,6 +48,12 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { rhs }; + // Add a `make_canonical_response` probe step so that we treat this as + // a candidate, even if `try_evaluate_added_goals` bails due to an error. + // It's `Certainty::AMBIGUOUS` because this candidate is not "finished", + // since equating the normalized terms will lead to additional constraints. + self.inspect.make_canonical_response(Certainty::AMBIGUOUS); + // Apply the constraints. self.try_evaluate_added_goals()?; let lhs = self.resolve_vars_if_possible(lhs); diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index dc13941e5d7..0e9cbbc27b6 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -460,9 +460,8 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { polarity: ty::PredicatePolarity::Positive, })) } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => { - ChildMode::WellFormedObligation - } + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) + | ty::PredicateKind::AliasRelate(..) => ChildMode::PassThrough, _ => { return ControlFlow::Break(self.obligation.clone()); } @@ -496,7 +495,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { (_, GoalSource::InstantiateHigherRanked) => { obligation = self.obligation.clone(); } - (ChildMode::WellFormedObligation, _) => { + (ChildMode::PassThrough, _) => { obligation = make_obligation(self.obligation.cause.clone()); } } @@ -527,7 +526,7 @@ enum ChildMode<'tcx> { // Skip trying to derive an `ObligationCause` from this obligation, and // report *all* sub-obligations as if they came directly from the parent // obligation. - WellFormedObligation, + PassThrough, } fn derive_cause<'tcx>( diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 19c95dad48c..b9c98b6a2e9 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -15,7 +15,7 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_macros::extension; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{inspect, QueryResult}; -use rustc_middle::traits::solve::{Certainty, Goal}; +use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{TyCtxt, TypeFoldable}; use rustc_middle::{bug, ty}; @@ -291,7 +291,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { steps.push(step) } inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { - assert_eq!(shallow_certainty.replace(c), None); + assert!(matches!( + shallow_certainty.replace(c), + None | Some(Certainty::Maybe(MaybeCause::Ambiguity)) + )); } inspect::ProbeStep::NestedProbe(ref probe) => { match probe.kind { diff --git a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr index 6e41561f1a7..0e1e28ce982 100644 --- a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr +++ b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy ` as Object>::Output == T` +error[E0284]: type annotations needed: cannot satisfy ` as Object>::Output normalizes-to _` --> $DIR/indirect-impl-for-trait-obj-coherence.rs:25:41 | LL | foo::, U>(x) - | ^ cannot satisfy ` as Object>::Output == T` + | ^ cannot satisfy ` as Object>::Output normalizes-to _` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs index 0b66a6e7830..8ad9aab466a 100644 --- a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs +++ b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs @@ -23,7 +23,7 @@ fn foo(x: >::Output) -> U { #[allow(dead_code)] fn transmute(x: T) -> U { foo::, U>(x) - //[next]~^ ERROR type annotations needed: cannot satisfy ` as Object>::Output == T` + //[next]~^ ERROR type annotations needed: cannot satisfy ` as Object>::Output normalizes-to _` } fn main() {} diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index f32bb1301da..b38f7c1ef77 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -16,11 +16,11 @@ LL | | for<'a> *const T: ToUnit<'a>, | = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details -error[E0284]: type annotations needed: cannot satisfy ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc == usize` +error[E0284]: type annotations needed: cannot satisfy ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc normalizes-to _` --> $DIR/associated-type.rs:44:59 | LL | foo:: fn(&'a (), ()), for<'a> fn(&'a (), ())>(3usize); - | ^^^^^^ cannot satisfy ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc == usize` + | ^^^^^^ cannot satisfy ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc normalizes-to _` error: aborting due to 2 previous errors diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr index 568cb8931a1..d189d2dbded 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr @@ -25,7 +25,7 @@ LL | SelectInt.check("bar"); = help: the trait `AsExpression` is implemented for `&str` = help: for that trait implementation, expected `Text`, found `Integer` -error[E0271]: type mismatch resolving `<&str as AsExpression<::SqlType>>::Expression == _` +error[E0271]: type mismatch resolving `::SqlType == Text` --> $DIR/as_expression.rs:57:5 | LL | SelectInt.check("bar"); diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs index 2607f047024..35757f2339d 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs @@ -18,3 +18,4 @@ fn weird1() -> impl !Sized + Sized {} //~^ ERROR type mismatch resolving `impl !Sized + Sized == ()` fn weird2() -> impl !Sized {} //~^ ERROR type mismatch resolving `impl !Sized == ()` +//~| ERROR the size for values of type `impl !Sized` cannot be known at compilation time diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr index ceaf42431fe..3dd2b27b55b 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr @@ -16,6 +16,15 @@ error[E0271]: type mismatch resolving `impl !Sized == ()` LL | fn weird2() -> impl !Sized {} | ^^^^^^^^^^^ types differ +error[E0277]: the size for values of type `impl !Sized` cannot be known at compilation time + --> $DIR/opaque-type-unsatisfied-bound.rs:19:16 + | +LL | fn weird2() -> impl !Sized {} + | ^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `impl !Sized` + = note: the return type of a function must have a statically known size + error[E0277]: the trait bound `impl !Trait: Trait` is not satisfied --> $DIR/opaque-type-unsatisfied-bound.rs:12:13 | @@ -30,7 +39,7 @@ note: required by a bound in `consume` LL | fn consume(_: impl Trait) {} | ^^^^^ required by this bound in `consume` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0271, E0277. For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr index 9dde1963bd4..f533f899f26 100644 --- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr +++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `{ || {} } == _` +error[E0284]: type annotations needed: cannot satisfy `X::{constant#0} normalizes-to _` --> $DIR/const-region-infer-to-static-in-binder.rs:4:10 | LL | struct X; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `{ || {} } == _` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `X::{constant#0} normalizes-to _` error: using function pointers as const generic parameters is forbidden --> $DIR/const-region-infer-to-static-in-binder.rs:4:20 diff --git a/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.rs b/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.rs new file mode 100644 index 00000000000..a3ab7bf03e5 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Znext-solver + +trait Trait { + type Assoc; +} + +fn test_poly() { + let x: ::Assoc = (); + //~^ ERROR the trait bound `T: Trait` is not satisfied +} + +fn test() { + let x: ::Assoc = (); + //~^ ERROR the trait bound `i32: Trait` is not satisfied +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.stderr b/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.stderr new file mode 100644 index 00000000000..cd8d8b3ffcd --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.stderr @@ -0,0 +1,26 @@ +error[E0277]: the trait bound `T: Trait` is not satisfied + --> $DIR/projection-trait-ref.rs:8:12 + | +LL | let x: ::Assoc = (); + | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | fn test_poly() { + | +++++++ + +error[E0277]: the trait bound `i32: Trait` is not satisfied + --> $DIR/projection-trait-ref.rs:13:12 + | +LL | let x: ::Assoc = (); + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `i32` + | +help: this trait has no implementations, consider adding one + --> $DIR/projection-trait-ref.rs:3:1 + | +LL | trait Trait { + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr index 524522bef09..3230ceb69cb 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.stderr +++ b/tests/ui/traits/next-solver/specialization-transmute.stderr @@ -10,17 +10,17 @@ LL | #![feature(specialization)] error: cannot normalize `::Id: '_` -error[E0284]: type annotations needed: cannot satisfy `::Id == _` +error[E0284]: type annotations needed: cannot satisfy `::Id normalizes-to _` --> $DIR/specialization-transmute.rs:15:23 | LL | fn intu(&self) -> &Self::Id { - | ^^^^^^^^^ cannot satisfy `::Id == _` + | ^^^^^^^^^ cannot satisfy `::Id normalizes-to _` -error[E0284]: type annotations needed: cannot satisfy `T <: ::Id` +error[E0284]: type annotations needed: cannot satisfy `::Id normalizes-to T` --> $DIR/specialization-transmute.rs:17:9 | LL | self - | ^^^^ cannot satisfy `T <: ::Id` + | ^^^^ cannot satisfy `::Id normalizes-to T` error[E0284]: type annotations needed: cannot satisfy `::Id == Option>` --> $DIR/specialization-transmute.rs:28:13 diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr index 4c8a25edfed..5a728a00138 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr @@ -1,4 +1,4 @@ -error[E0284]: type annotations needed: cannot satisfy `>::Out == ()` +error[E0284]: type annotations needed: cannot satisfy `Bar == _` --> $DIR/issue-84660-unsoundness.rs:22:37 | LL | fn convert(_i: In) -> Self::Out { @@ -7,7 +7,7 @@ LL | | LL | | LL | | unreachable!(); LL | | } - | |_____^ cannot satisfy `>::Out == ()` + | |_____^ cannot satisfy `Bar == _` error[E0119]: conflicting implementations of trait `Trait` --> $DIR/issue-84660-unsoundness.rs:29:1 -- cgit 1.4.1-3-g733a5 From b0c14743811866a63aac3177e5f9f820af477458 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 4 Jun 2024 09:17:18 -0400 Subject: better error message for normalizes-to ambiguities --- .../src/traits/error_reporting/type_err_ctxt_ext.rs | 16 ++++++++++++++++ .../indirect-impl-for-trait-obj-coherence.next.stderr | 4 ++-- .../coherence/indirect-impl-for-trait-obj-coherence.rs | 2 +- .../coherence/occurs-check/associated-type.next.stderr | 4 ++-- tests/ui/coherence/occurs-check/associated-type.rs | 2 +- .../const-region-infer-to-static-in-binder.stderr | 4 ++-- .../traits/next-solver/specialization-transmute.stderr | 4 ++-- 7 files changed, 26 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 6b6438a7887..a3ed51f43c9 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -2705,6 +2705,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ), ); } + + ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) + if term.is_infer() => + { + if let Some(e) = self.tainted_by_errors() { + return e; + } + struct_span_code_err!( + self.dcx(), + span, + E0284, + "type annotations needed: cannot normalize `{alias}`", + ) + .with_span_label(span, format!("cannot normalize `{alias}`")) + } + _ => { if let Some(e) = self.tainted_by_errors() { return e; diff --git a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr index 0e1e28ce982..b6636d4de86 100644 --- a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr +++ b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy ` as Object>::Output normalizes-to _` +error[E0284]: type annotations needed: cannot normalize ` as Object>::Output` --> $DIR/indirect-impl-for-trait-obj-coherence.rs:25:41 | LL | foo::, U>(x) - | ^ cannot satisfy ` as Object>::Output normalizes-to _` + | ^ cannot normalize ` as Object>::Output` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs index 8ad9aab466a..abfd51c2008 100644 --- a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs +++ b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs @@ -23,7 +23,7 @@ fn foo(x: >::Output) -> U { #[allow(dead_code)] fn transmute(x: T) -> U { foo::, U>(x) - //[next]~^ ERROR type annotations needed: cannot satisfy ` as Object>::Output normalizes-to _` + //[next]~^ ERROR type annotations needed: cannot normalize ` as Object>::Output` } fn main() {} diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index b38f7c1ef77..bd65cee58d9 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -16,11 +16,11 @@ LL | | for<'a> *const T: ToUnit<'a>, | = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details -error[E0284]: type annotations needed: cannot satisfy ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc normalizes-to _` +error[E0284]: type annotations needed: cannot normalize ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc` --> $DIR/associated-type.rs:44:59 | LL | foo:: fn(&'a (), ()), for<'a> fn(&'a (), ())>(3usize); - | ^^^^^^ cannot satisfy ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc normalizes-to _` + | ^^^^^^ cannot normalize ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc` error: aborting due to 2 previous errors diff --git a/tests/ui/coherence/occurs-check/associated-type.rs b/tests/ui/coherence/occurs-check/associated-type.rs index ac1236c554a..df03d5f60a0 100644 --- a/tests/ui/coherence/occurs-check/associated-type.rs +++ b/tests/ui/coherence/occurs-check/associated-type.rs @@ -42,5 +42,5 @@ fn foo, U>(x: T::Assoc) -> T::Assoc { fn main() { foo:: fn(&'a (), ()), for<'a> fn(&'a (), ())>(3usize); - //[next]~^ ERROR: cannot satisfy + //[next]~^ ERROR: cannot normalize } diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr index f533f899f26..e0cbee88aa1 100644 --- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr +++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `X::{constant#0} normalizes-to _` +error[E0284]: type annotations needed: cannot normalize `X::{constant#0}` --> $DIR/const-region-infer-to-static-in-binder.rs:4:10 | LL | struct X; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `X::{constant#0} normalizes-to _` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `X::{constant#0}` error: using function pointers as const generic parameters is forbidden --> $DIR/const-region-infer-to-static-in-binder.rs:4:20 diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr index 3230ceb69cb..f463a90a59d 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.stderr +++ b/tests/ui/traits/next-solver/specialization-transmute.stderr @@ -10,11 +10,11 @@ LL | #![feature(specialization)] error: cannot normalize `::Id: '_` -error[E0284]: type annotations needed: cannot satisfy `::Id normalizes-to _` +error[E0284]: type annotations needed: cannot normalize `::Id` --> $DIR/specialization-transmute.rs:15:23 | LL | fn intu(&self) -> &Self::Id { - | ^^^^^^^^^ cannot satisfy `::Id normalizes-to _` + | ^^^^^^^^^ cannot normalize `::Id` error[E0284]: type annotations needed: cannot satisfy `::Id normalizes-to T` --> $DIR/specialization-transmute.rs:17:9 -- cgit 1.4.1-3-g733a5 From 44040a06703375bb01db0c549a71c3cafcae0dc8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 4 Jun 2024 09:43:49 -0400 Subject: Also passthrough for projection clauses --- compiler/rustc_trait_selection/src/solve/fulfill.rs | 4 +++- ...id-equate-projections-in-higher-ranked-fn-signature.next.stderr | 4 ++-- .../env-shadows-impls/param-candidate-shadows-project.stderr | 7 +------ .../normalize/two-projection-param-candidates-are-ambiguous.rs | 2 +- .../normalize/two-projection-param-candidates-are-ambiguous.stderr | 4 ++-- tests/ui/traits/next-solver/specialization-transmute.stderr | 4 ++-- tests/ui/traits/next-solver/specialization-unconstrained.rs | 2 +- tests/ui/traits/next-solver/specialization-unconstrained.stderr | 4 ++-- tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs | 2 +- 9 files changed, 15 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 0e9cbbc27b6..3c3d5dfe79c 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -460,7 +460,9 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { polarity: ty::PredicatePolarity::Positive, })) } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) + ty::PredicateKind::Clause( + ty::ClauseKind::WellFormed(_) | ty::ClauseKind::Projection(..), + ) | ty::PredicateKind::AliasRelate(..) => ChildMode::PassThrough, _ => { return ControlFlow::Break(self.obligation.clone()); diff --git a/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr index 14a3d5e178d..31d74d1c022 100644 --- a/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr +++ b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc <: >::Assoc` +error[E0284]: type annotations needed: cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc normalizes-to >::Assoc` --> $DIR/rigid-equate-projections-in-higher-ranked-fn-signature.rs:27:50 | LL | let _: for<'a> fn(<_ as Trait<'a>>::Assoc) = foo::(); - | ^^^^^^^^^^ cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc <: >::Assoc` + | ^^^^^^^^^^ cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc normalizes-to >::Assoc` error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/env-shadows-impls/param-candidate-shadows-project.stderr b/tests/ui/traits/next-solver/env-shadows-impls/param-candidate-shadows-project.stderr index 3ef0afa38bf..0c72fc25dca 100644 --- a/tests/ui/traits/next-solver/env-shadows-impls/param-candidate-shadows-project.stderr +++ b/tests/ui/traits/next-solver/env-shadows-impls/param-candidate-shadows-project.stderr @@ -2,13 +2,8 @@ error[E0271]: type mismatch resolving `::Assoc == i32` --> $DIR/param-candidate-shadows-project.rs:27:19 | LL | require_bar::(); - | ^ type mismatch resolving `::Assoc == i32` + | ^ types differ | -note: types differ - --> $DIR/param-candidate-shadows-project.rs:10:18 - | -LL | type Assoc = i32; - | ^^^ note: required for `T` to implement `Bar` --> $DIR/param-candidate-shadows-project.rs:13:9 | diff --git a/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.rs b/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.rs index 12ea1bf142a..5239474ff44 100644 --- a/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.rs +++ b/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.rs @@ -24,7 +24,7 @@ fn needs_bar() {} fn foo + Foo>() { needs_bar::(); - //~^ ERROR type annotations needed: cannot satisfy `::Assoc == i32` + //~^ ERROR type annotations needed: cannot normalize } fn main() {} diff --git a/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.stderr b/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.stderr index 21f3fbfeb87..270ad851717 100644 --- a/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.stderr +++ b/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `::Assoc == i32` +error[E0284]: type annotations needed: cannot normalize `::Assoc` --> $DIR/two-projection-param-candidates-are-ambiguous.rs:26:17 | LL | needs_bar::(); - | ^ cannot satisfy `::Assoc == i32` + | ^ cannot normalize `::Assoc` | note: required for `T` to implement `Bar` --> $DIR/two-projection-param-candidates-are-ambiguous.rs:21:9 diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr index f463a90a59d..b96bfab927d 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.stderr +++ b/tests/ui/traits/next-solver/specialization-transmute.stderr @@ -22,11 +22,11 @@ error[E0284]: type annotations needed: cannot satisfy `::Id normal LL | self | ^^^^ cannot satisfy `::Id normalizes-to T` -error[E0284]: type annotations needed: cannot satisfy `::Id == Option>` +error[E0284]: type annotations needed: cannot satisfy `::Id normalizes-to Option>` --> $DIR/specialization-transmute.rs:28:13 | LL | let s = transmute::>>(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `::Id == Option>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `::Id normalizes-to Option>` | note: required by a bound in `transmute` --> $DIR/specialization-transmute.rs:21:25 diff --git a/tests/ui/traits/next-solver/specialization-unconstrained.rs b/tests/ui/traits/next-solver/specialization-unconstrained.rs index e44246a1262..2bbe7840110 100644 --- a/tests/ui/traits/next-solver/specialization-unconstrained.rs +++ b/tests/ui/traits/next-solver/specialization-unconstrained.rs @@ -18,5 +18,5 @@ fn test, U>() {} fn main() { test::(); - //~^ ERROR cannot satisfy `::Id == ()` + //~^ ERROR cannot satisfy `::Id normalizes-to ()` } diff --git a/tests/ui/traits/next-solver/specialization-unconstrained.stderr b/tests/ui/traits/next-solver/specialization-unconstrained.stderr index a6f6a4f260d..e1d785b554b 100644 --- a/tests/ui/traits/next-solver/specialization-unconstrained.stderr +++ b/tests/ui/traits/next-solver/specialization-unconstrained.stderr @@ -8,11 +8,11 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete = note: `#[warn(incomplete_features)]` on by default -error[E0284]: type annotations needed: cannot satisfy `::Id == ()` +error[E0284]: type annotations needed: cannot satisfy `::Id normalizes-to ()` --> $DIR/specialization-unconstrained.rs:20:5 | LL | test::(); - | ^^^^^^^^^^^^^^^^^ cannot satisfy `::Id == ()` + | ^^^^^^^^^^^^^^^^^ cannot satisfy `::Id normalizes-to ()` | note: required by a bound in `test` --> $DIR/specialization-unconstrained.rs:17:20 diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs index 73c8deb3a4d..f3234bafd11 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs @@ -20,7 +20,7 @@ trait Trait { impl Trait for Out { type Out = Out; fn convert(_i: In) -> Self::Out { - //[next]~^ ERROR: cannot satisfy `>::Out == ()` + //[next]~^ ERROR: cannot satisfy `Bar == _` //[current]~^^ ERROR: item does not constrain `Bar::{opaque#0}`, but has it in its signature unreachable!(); } -- cgit 1.4.1-3-g733a5 From 46391b7dcd78062f247d515eb339e0a3b723da99 Mon Sep 17 00:00:00 2001 From: Artem Agvanian Date: Wed, 12 Jun 2024 16:15:02 -0700 Subject: Make `try_from_target_usize` method public There is now no way to create a TyConst from an integer, so I propose making this method public unless there was a reason for keeping it otherwise. --- compiler/stable_mir/src/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index bcbe87f7303..8c9824f8f8d 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -122,7 +122,7 @@ impl TyConst { } /// Creates an interned usize constant. - fn try_from_target_usize(val: u64) -> Result { + pub fn try_from_target_usize(val: u64) -> Result { with(|cx| cx.try_new_ty_const_uint(val.into(), UintTy::Usize)) } -- cgit 1.4.1-3-g733a5 From 5da1b4189e8b6820624ea548efe90c2cc35d576c Mon Sep 17 00:00:00 2001 From: Veera Date: Wed, 5 Jun 2024 20:12:16 -0400 Subject: E0229: Suggest Moving Type Constraints to Type Parameter Declaration --- compiler/rustc_hir/src/hir.rs | 24 ++++++++ .../src/hir_ty_lowering/errors.rs | 71 +++++++++++++++++++--- .../src/hir_ty_lowering/generics.rs | 17 +++++- tests/ui/associated-type-bounds/no-gat-position.rs | 2 +- .../associated-type-bounds/no-gat-position.stderr | 2 +- .../rtn-in-impl-signature.stderr | 2 +- 6 files changed, 105 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e971d0e3c14..a021847db26 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2456,6 +2456,15 @@ pub enum AssocItemConstraintKind<'hir> { Bound { bounds: &'hir [GenericBound<'hir>] }, } +impl<'hir> AssocItemConstraintKind<'hir> { + pub fn descr(&self) -> &'static str { + match self { + AssocItemConstraintKind::Equality { .. } => "binding", + AssocItemConstraintKind::Bound { .. } => "constraint", + } + } +} + #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Ty<'hir> { pub hir_id: HirId, @@ -3735,6 +3744,21 @@ impl<'hir> Node<'hir> { } } + /// Get a `hir::Impl` if the node is an impl block for the given `trait_def_id`. + pub fn impl_block_of_trait(self, trait_def_id: DefId) -> Option<&'hir Impl<'hir>> { + match self { + Node::Item(Item { kind: ItemKind::Impl(impl_block), .. }) + if impl_block + .of_trait + .and_then(|trait_ref| trait_ref.trait_def_id()) + .is_some_and(|trait_id| trait_id == trait_def_id) => + { + Some(impl_block) + } + _ => None, + } + } + pub fn fn_sig(self) -> Option<&'hir FnSig<'hir>> { match self { Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) 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 3a9ef244fd3..2d240699105 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -1217,7 +1217,6 @@ pub fn prohibit_assoc_item_constraint( // otherwise suggest the removal of the binding. if let Some((def_id, segment, _)) = segment && segment.args().parenthesized == hir::GenericArgsParentheses::No - && let hir::AssocItemConstraintKind::Equality { term } = constraint.kind { // Suggests removal of the offending binding let suggest_removal = |e: &mut Diag<'_>| { @@ -1263,7 +1262,7 @@ pub fn prohibit_assoc_item_constraint( if let Ok(suggestion) = tcx.sess.source_map().span_to_snippet(removal_span) { e.span_suggestion_verbose( removal_span, - "consider removing this associated item binding", + format!("consider removing this associated item {}", constraint.kind.descr()), suggestion, Applicability::MaybeIncorrect, ); @@ -1286,19 +1285,73 @@ pub fn prohibit_assoc_item_constraint( // Check if the type has a generic param with the same name // as the assoc type name in the associated item binding. let generics = tcx.generics_of(def_id); - let matching_param = - generics.own_params.iter().find(|p| p.name.as_str() == constraint.ident.as_str()); + let matching_param = generics.own_params.iter().find(|p| p.name == constraint.ident.name); // Now emit the appropriate suggestion if let Some(matching_param) = matching_param { - match (&matching_param.kind, term) { - (GenericParamDefKind::Type { .. }, hir::Term::Ty(ty)) => { - suggest_direct_use(&mut err, ty.span); - } - (GenericParamDefKind::Const { .. }, hir::Term::Const(c)) => { + match (constraint.kind, &matching_param.kind) { + ( + hir::AssocItemConstraintKind::Equality { term: hir::Term::Ty(ty) }, + GenericParamDefKind::Type { .. }, + ) => suggest_direct_use(&mut err, ty.span), + ( + hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) }, + GenericParamDefKind::Const { .. }, + ) => { let span = tcx.hir().span(c.hir_id); suggest_direct_use(&mut err, span); } + (hir::AssocItemConstraintKind::Bound { bounds }, _) => { + // Suggest `impl Trait for Foo` when finding + // `impl Trait for Foo` + + // Get the parent impl block based on the binding we have + // and the trait DefId + let impl_block = tcx + .hir() + .parent_iter(constraint.hir_id) + .find_map(|(_, node)| node.impl_block_of_trait(def_id)); + + let type_with_constraints = + tcx.sess.source_map().span_to_snippet(constraint.span); + + if let Some(impl_block) = impl_block + && let Ok(type_with_constraints) = type_with_constraints + { + // Filter out the lifetime parameters because + // they should be declared before the type parameter + let lifetimes: String = bounds + .iter() + .filter_map(|bound| { + if let hir::GenericBound::Outlives(lifetime) = bound { + Some(format!("{lifetime}, ")) + } else { + None + } + }) + .collect(); + // Figure out a span and suggestion string based on + // whether there are any existing parameters + let param_decl = if let Some(param_span) = + impl_block.generics.span_for_param_suggestion() + { + (param_span, format!(", {lifetimes}{type_with_constraints}")) + } else { + ( + impl_block.generics.span.shrink_to_lo(), + format!("<{lifetimes}{type_with_constraints}>"), + ) + }; + let suggestions = + vec![param_decl, (constraint.span, format!("{}", matching_param.name))]; + + err.multipart_suggestion_verbose( + format!("declare the type parameter right after the `impl` keyword"), + suggestions, + Applicability::MaybeIncorrect, + ); + } + } _ => suggest_removal(&mut err), } } else { 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 26cabb69d25..3f888c4e272 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -531,6 +531,7 @@ pub(crate) fn check_generic_arg_count( let num_default_params = expected_max - expected_min; + let mut all_params_are_binded = false; let gen_args_info = if provided > expected_max { invalid_args.extend((expected_max..provided).map(|i| i + args_offset)); let num_redundant_args = provided - expected_max; @@ -547,6 +548,20 @@ pub(crate) fn check_generic_arg_count( } else { let num_missing_args = expected_max - provided; + let constraint_names: Vec<_> = + gen_args.constraints.iter().map(|b| b.ident.name).collect(); + let param_names: Vec<_> = gen_params + .own_params + .iter() + .filter(|param| !has_self || param.index != 0) // Assumes `Self` will always be the first parameter + .map(|param| param.name) + .collect(); + if constraint_names == param_names { + // We set this to true and delay emitting `WrongNumberOfGenericArgs` + // to provide a succinct error for cases like issue #113073 + all_params_are_binded = true; + }; + GenericArgsInfo::MissingTypesOrConsts { num_missing_args, num_default_params, @@ -567,7 +582,7 @@ pub(crate) fn check_generic_arg_count( def_id, ) .diagnostic() - .emit() + .emit_unless(all_params_are_binded) }); Err(reported) diff --git a/tests/ui/associated-type-bounds/no-gat-position.rs b/tests/ui/associated-type-bounds/no-gat-position.rs index 249812ebbff..ec9214897fa 100644 --- a/tests/ui/associated-type-bounds/no-gat-position.rs +++ b/tests/ui/associated-type-bounds/no-gat-position.rs @@ -5,7 +5,7 @@ pub trait Iter { fn next<'a>(&'a mut self) -> Option>; //~^ ERROR associated item constraints are not allowed here - //~| HELP consider removing this associated item binding + //~| HELP consider removing this associated item constraint } impl Iter for () { diff --git a/tests/ui/associated-type-bounds/no-gat-position.stderr b/tests/ui/associated-type-bounds/no-gat-position.stderr index b8e466b8d84..39a2f89f9ac 100644 --- a/tests/ui/associated-type-bounds/no-gat-position.stderr +++ b/tests/ui/associated-type-bounds/no-gat-position.stderr @@ -4,7 +4,7 @@ error[E0229]: associated item constraints are not allowed here LL | fn next<'a>(&'a mut self) -> Option>; | ^^^^^^^^^ associated item constraint not allowed here | -help: consider removing this associated item binding +help: consider removing this associated item constraint | LL | fn next<'a>(&'a mut self) -> Option>; | ~~~~~~~~~~~ diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr index b0c89b05925..54960ae60bc 100644 --- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr @@ -13,7 +13,7 @@ error[E0229]: associated item constraints are not allowed here LL | impl Super1<'_, bar(): Send> for () {} | ^^^^^^^^^^^ associated item constraint not allowed here | -help: consider removing this associated item binding +help: consider removing this associated item constraint | LL | impl Super1<'_, bar(): Send> for () {} | ~~~~~~~~~~~~~ -- cgit 1.4.1-3-g733a5 From 9c25d4078463fea9a4b0ad6cab61b8f51b63bf6b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 13 Jun 2024 02:44:14 +0200 Subject: Honor collapse_debuginfo for statics. fixes #126363 --- compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index a543ccbde0e..8de4e0effad 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -36,7 +36,7 @@ use rustc_middle::ty::{ }; use rustc_session::config::{self, DebugInfo, Lto}; use rustc_span::symbol::Symbol; -use rustc_span::FileName; +use rustc_span::{hygiene, FileName, DUMMY_SP}; use rustc_span::{FileNameDisplayPreference, SourceFile}; use rustc_symbol_mangling::typeid_for_trait_ref; use rustc_target::abi::{Align, Size}; @@ -1306,7 +1306,7 @@ pub fn build_global_var_di_node<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, glo // We may want to remove the namespace scope if we're in an extern block (see // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952). let var_scope = get_namespace_for_item(cx, def_id); - let span = tcx.def_span(def_id); + let span = hygiene::walk_chain_collapsed(tcx.def_span(def_id), DUMMY_SP); let (file_metadata, line_number) = if !span.is_dummy() { let loc = cx.lookup_debug_loc(span.lo()); -- cgit 1.4.1-3-g733a5 From 6d4a8257149ab7fea438ee7ad52491c2985b4340 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 12 Jun 2024 17:47:49 -0700 Subject: Add a new trait to retrieve StableMir definition Ty We implement the trait only for definitions that should have a type. It's possible that I missed a few definitions, but we can add them later if needed. --- compiler/stable_mir/src/crate_def.rs | 37 ++++++++- compiler/stable_mir/src/lib.rs | 8 +- compiler/stable_mir/src/ty.rs | 28 +++++-- tests/ui-fulldeps/stable-mir/check_def_ty.rs | 114 +++++++++++++++++++++++++++ 4 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 tests/ui-fulldeps/stable-mir/check_def_ty.rs diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs index 70ca9e6825e..67752a5e629 100644 --- a/compiler/stable_mir/src/crate_def.rs +++ b/compiler/stable_mir/src/crate_def.rs @@ -1,7 +1,7 @@ //! Module that define a common trait for things that represent a crate definition, //! such as, a function, a trait, an enum, and any other definitions. -use crate::ty::Span; +use crate::ty::{GenericArgs, Span, Ty}; use crate::{with, Crate, Symbol}; /// A unique identification number for each item accessible for the current compilation unit. @@ -52,6 +52,23 @@ pub trait CrateDef { } } +/// A trait that can be used to retrieve a definition's type. +/// +/// Note that not every CrateDef has a type `Ty`. They should not implement this trait. +pub trait CrateDefType: CrateDef { + /// Returns the type of this crate item. + fn ty(&self) -> Ty { + with(|cx| cx.def_ty(self.def_id())) + } + + /// Retrieve the type of this definition by instantiating and normalizing it with `args`. + /// + /// This will panic if instantiation fails. + fn ty_with_args(&self, args: &GenericArgs) -> Ty { + with(|cx| cx.def_ty_with_args(self.def_id(), args)) + } +} + macro_rules! crate_def { ( $(#[$attr:meta])* $vis:vis $name:ident $(;)? @@ -67,3 +84,21 @@ macro_rules! crate_def { } }; } + +macro_rules! crate_def_with_ty { + ( $(#[$attr:meta])* + $vis:vis $name:ident $(;)? + ) => { + $(#[$attr])* + #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] + $vis struct $name(pub DefId); + + impl CrateDef for $name { + fn def_id(&self) -> DefId { + self.0 + } + } + + impl CrateDefType for $name {} + }; +} diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index d9f988935ab..8385856ae53 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -22,8 +22,7 @@ use std::fmt::Debug; use std::io; use crate::compiler_interface::with; -pub use crate::crate_def::CrateDef; -pub use crate::crate_def::DefId; +pub use crate::crate_def::{CrateDef, CrateDefType, DefId}; pub use crate::error::*; use crate::mir::Body; use crate::mir::Mutability; @@ -115,12 +114,15 @@ pub enum CtorKind { pub type Filename = String; -crate_def! { +crate_def_with_ty! { /// Holds information about an item in a crate. pub CrateItem; } impl CrateItem { + /// This will return the body of an item. + /// + /// This will panic if no body is available. pub fn body(&self) -> mir::Body { with(|cx| cx.mir_body(self.0)) } diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index bcbe87f7303..6fddd5f5cd1 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -3,9 +3,10 @@ use super::{ with, DefId, Error, Symbol, }; use crate::abi::Layout; +use crate::crate_def::{CrateDef, CrateDefType}; use crate::mir::alloc::{read_target_int, read_target_uint, AllocId}; +use crate::mir::mono::StaticDef; use crate::target::MachineInfo; -use crate::{crate_def::CrateDef, mir::mono::StaticDef}; use crate::{Filename, Opaque}; use std::fmt::{self, Debug, Display, Formatter}; use std::ops::Range; @@ -504,6 +505,15 @@ impl TyKind { pub fn discriminant_ty(&self) -> Option { self.rigid().map(|ty| with(|cx| cx.rigid_ty_discriminant_ty(ty))) } + + /// Deconstruct a function type if this is one. + pub fn fn_def(&self) -> Option<(FnDef, &GenericArgs)> { + if let TyKind::RigidTy(RigidTy::FnDef(def, args)) = self { + Some((*def, args)) + } else { + None + } + } } pub struct TypeAndMut { @@ -629,7 +639,7 @@ impl ForeignModule { } } -crate_def! { +crate_def_with_ty! { /// Hold information about a ForeignItem in a crate. pub ForeignDef; } @@ -647,7 +657,7 @@ pub enum ForeignItemKind { Type(Ty), } -crate_def! { +crate_def_with_ty! { /// Hold information about a function definition in a crate. pub FnDef; } @@ -668,9 +678,15 @@ impl FnDef { pub fn is_intrinsic(&self) -> bool { self.as_intrinsic().is_some() } + + /// Get the function signature for this function definition. + pub fn fn_sig(&self) -> PolyFnSig { + let kind = self.ty().kind(); + kind.fn_sig().unwrap() + } } -crate_def! { +crate_def_with_ty! { pub IntrinsicDef; } @@ -710,7 +726,7 @@ crate_def! { pub BrNamedDef; } -crate_def! { +crate_def_with_ty! { pub AdtDef; } @@ -866,7 +882,7 @@ crate_def! { pub GenericDef; } -crate_def! { +crate_def_with_ty! { pub ConstDef; } diff --git a/tests/ui-fulldeps/stable-mir/check_def_ty.rs b/tests/ui-fulldeps/stable-mir/check_def_ty.rs new file mode 100644 index 00000000000..9f45b62d343 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_def_ty.rs @@ -0,0 +1,114 @@ +//@ run-pass +//! Test that users are able to use stable mir APIs to retrieve type information from a crate item +//! definition. + +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote +//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 +//@ edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] + +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use rustc_smir::rustc_internal; +use stable_mir::ty::{Ty, ForeignItemKind}; +use stable_mir::*; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "crate_def_ty"; + +/// Test if we can retrieve type information from different definitions. +fn test_def_tys() -> ControlFlow<()> { + let items = stable_mir::all_local_items(); + for item in &items { + // Type from crate items. + let ty = item.ty(); + match item.name().as_str() { + "STATIC_STR" => assert!(ty.kind().is_ref()), + "CONST_U32" => assert!(ty.kind().is_integral()), + "main" => { check_fn_def(ty) } + _ => unreachable!("Unexpected item: `{item:?}`") + } + } + + let foreign_items = stable_mir::local_crate().foreign_modules(); + for item in foreign_items[0].module().items() { + // Type from foreign items. + let ty = item.ty(); + let item_kind = item.kind(); + let name = item.name(); + match item_kind { + ForeignItemKind::Fn(fn_def) => { + assert_eq!(&name, "extern_fn"); + assert_eq!(ty, fn_def.ty()); + check_fn_def(ty) + } + ForeignItemKind::Static(def) => { + assert_eq!(&name, "EXT_STATIC"); + assert_eq!(ty, def.ty()); + assert!(ty.kind().is_integral()) + } + _ => unreachable!("Unexpected kind: {item_kind:?}") + }; + } + + ControlFlow::Continue(()) +} + +fn check_fn_def(ty: Ty) { + let kind = ty.kind(); + let (def, args) = kind.fn_def().expect(&format!("Expected function type, but found: {ty}")); + assert!(def.ty().kind().is_fn()); + assert_eq!(def.ty_with_args(args), ty); +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "defs_ty_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "-Cpanic=abort".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, test_def_tys).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + // We would like to check intrinsic definition. + #![feature(core_intrinsics)] + static STATIC_STR: &str = "foo"; + const CONST_U32: u32 = 0u32; + + fn main() {{ + let _c = core::char::from_u32(99); + let _v = Vec::::new(); + let _i = std::intrinsics::size_of::(); + }} + + extern "C" {{ + fn extern_fn(x: i32) -> i32; + static EXT_STATIC: i32; + }} + "# + )?; + Ok(()) +} -- cgit 1.4.1-3-g733a5 From c453c82de4868aee46563ec908dab218153d46eb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 8 Jun 2024 14:02:01 -0400 Subject: Harmonize use of leaf and root obligation in trait error reporting --- .../traits/error_reporting/type_err_ctxt_ext.rs | 106 ++++++++++----------- .../typeck-default-trait-impl-precedence.stderr | 2 +- ...-gat-normalization-for-nested-goals.next.stderr | 2 +- tests/ui/kindck/kindck-send-object.stderr | 2 +- tests/ui/kindck/kindck-send-object1.stderr | 2 +- tests/ui/kindck/kindck-send-object2.stderr | 2 +- tests/ui/suggestions/suggest-remove-refs-5.stderr | 4 +- .../auto-with-drop_tracking_mir.fail.stderr | 2 +- .../diagnostics/point-at-failing-nested.stderr | 5 + .../diagnostics/where-clause-doesnt-apply.stderr | 5 + .../suggest-dereferences/root-obligation.stderr | 2 +- .../transmutability/references/unsafecell.stderr | 4 +- 12 files changed, 74 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 6b6438a7887..cdf162ca2eb 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -412,8 +412,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { - let trait_predicate = bound_predicate.rebind(trait_predicate); - let trait_predicate = self.resolve_vars_if_possible(trait_predicate); + let leaf_trait_predicate = + self.resolve_vars_if_possible(bound_predicate.rebind(trait_predicate)); // Let's use the root obligation as the main message, when we care about the // most general case ("X doesn't implement Pattern<'_>") over the case that @@ -424,7 +424,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let (main_trait_predicate, o) = if let ty::PredicateKind::Clause( ty::ClauseKind::Trait(root_pred) ) = root_obligation.predicate.kind().skip_binder() - && !trait_predicate.self_ty().skip_binder().has_escaping_bound_vars() + && !leaf_trait_predicate.self_ty().skip_binder().has_escaping_bound_vars() && !root_pred.self_ty().has_escaping_bound_vars() // The type of the leaf predicate is (roughly) the same as the type // from the root predicate, as a proxy for "we care about the root" @@ -434,20 +434,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // `T: Trait` && `&&T: OtherTrait`, we want `OtherTrait` self.can_eq( obligation.param_env, - trait_predicate.self_ty().skip_binder(), + leaf_trait_predicate.self_ty().skip_binder(), root_pred.self_ty().peel_refs(), ) // `&str: Iterator` && `&str: IntoIterator`, we want `IntoIterator` || self.can_eq( obligation.param_env, - trait_predicate.self_ty().skip_binder(), + leaf_trait_predicate.self_ty().skip_binder(), root_pred.self_ty(), ) ) // The leaf trait and the root trait are different, so as to avoid // talking about `&mut T: Trait` and instead remain talking about // `T: Trait` instead - && trait_predicate.def_id() != root_pred.def_id() + && leaf_trait_predicate.def_id() != root_pred.def_id() // The root trait is not `Unsize`, as to avoid talking about it in // `tests/ui/coercion/coerce-issue-49593-box-never.rs`. && Some(root_pred.def_id()) != self.tcx.lang_items().unsize_trait() @@ -459,13 +459,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { root_obligation, ) } else { - (trait_predicate, &obligation) + (leaf_trait_predicate, &obligation) }; - let trait_ref = main_trait_predicate.to_poly_trait_ref(); + let main_trait_ref = main_trait_predicate.to_poly_trait_ref(); + let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref(); if let Some(guar) = self.emit_specialized_closure_kind_error( &obligation, - trait_ref, + leaf_trait_ref, ) { return guar; } @@ -473,7 +474,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // FIXME(effects) let predicate_is_const = false; - if let Err(guar) = trait_predicate.error_reported() + if let Err(guar) = leaf_trait_predicate.error_reported() { return guar; } @@ -507,16 +508,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { notes, parent_label, append_const_msg, - } = self.on_unimplemented_note(trait_ref, o, &mut long_ty_file); + } = self.on_unimplemented_note(main_trait_ref, o, &mut long_ty_file); + let have_alt_message = message.is_some() || label.is_some(); - let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id()); + let is_try_conversion = self.is_try_conversion(span, main_trait_ref.def_id()); let is_unsize = - Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait(); + Some(leaf_trait_ref.def_id()) == self.tcx.lang_items().unsize_trait(); let (message, notes, append_const_msg) = if is_try_conversion { ( Some(format!( "`?` couldn't convert the error to `{}`", - trait_ref.skip_binder().self_ty(), + main_trait_ref.skip_binder().self_ty(), )), vec![ "the question mark operation (`?`) implicitly performs a \ @@ -537,13 +539,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { post_message, ); - let (err_msg, safe_transmute_explanation) = if Some(trait_ref.def_id()) + let (err_msg, safe_transmute_explanation) = if Some(main_trait_ref.def_id()) == self.tcx.lang_items().transmute_trait() { // Recompute the safe transmute reason and use that for the error reporting match self.get_safe_transmute_error_and_reason( obligation.clone(), - trait_ref, + main_trait_ref, span, ) { GetSafeTransmuteErrorAndReason::Silent => { @@ -571,7 +573,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } let mut suggested = false; if is_try_conversion { - suggested = self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err); + suggested = self.try_conversion_context(&obligation, main_trait_ref.skip_binder(), &mut err); } if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) { @@ -579,19 +581,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ret_span, format!( "expected `{}` because of this", - trait_ref.skip_binder().self_ty() + main_trait_ref.skip_binder().self_ty() ), ); } - if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() { + if Some(leaf_trait_ref.def_id()) == tcx.lang_items().tuple_trait() { self.add_tuple_trait_message( obligation.cause.code().peel_derives(), &mut err, ); } - if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait() + if Some(leaf_trait_ref.def_id()) == tcx.lang_items().drop_trait() && predicate_is_const { err.note("`~const Drop` was renamed to `~const Destruct`"); @@ -601,15 +603,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let explanation = get_explanation_based_on_obligation( self.tcx, &obligation, - trait_ref, - &trait_predicate, + leaf_trait_ref, + &leaf_trait_predicate, pre_message, ); self.check_for_binding_assigned_block_without_tail_expression( &obligation, &mut err, - trait_predicate, + leaf_trait_predicate, ); self.suggest_add_result_as_return_type(&obligation, &mut err, @@ -618,7 +620,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if self.suggest_add_reference_to_arg( &obligation, &mut err, - trait_predicate, + leaf_trait_predicate, have_alt_message, ) { self.note_obligation_cause(&mut err, &obligation); @@ -630,7 +632,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! err.span_label(span, s); - if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { + if !matches!(leaf_trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { // When the self type is a type param We don't need to "the trait // `std::marker::Sized` is not implemented for `T`" as we will point // at the type param with a label to suggest constraining it. @@ -645,7 +647,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if let ObligationCauseCode::Coercion { source, target } = *obligation.cause.code().peel_derives() { - if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { + if Some(leaf_trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { self.suggest_borrowing_for_object_cast( &mut err, root_obligation, @@ -657,7 +659,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let UnsatisfiedConst(unsatisfied_const) = self .maybe_add_note_for_unsatisfied_const( - &trait_predicate, + &leaf_trait_predicate, &mut err, span, ); @@ -674,15 +676,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err.span_label(tcx.def_span(body), s); } - self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref); - self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate); - suggested |= self.suggest_dereferences(&obligation, &mut err, trait_predicate); - suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate); - let impl_candidates = self.find_similar_impl_candidates(trait_predicate); + self.suggest_floating_point_literal(&obligation, &mut err, &leaf_trait_ref); + self.suggest_dereferencing_index(&obligation, &mut err, leaf_trait_predicate); + suggested |= self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate); + suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate); + let impl_candidates = self.find_similar_impl_candidates(leaf_trait_predicate); suggested = if let &[cand] = &impl_candidates[..] { let cand = cand.trait_ref; if let (ty::FnPtr(_), ty::FnDef(..)) = - (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) + (cand.self_ty().kind(), main_trait_ref.self_ty().skip_binder().kind()) { err.span_suggestion( span.shrink_to_hi(), @@ -702,31 +704,31 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { false } || suggested; suggested |= - self.suggest_remove_reference(&obligation, &mut err, trait_predicate); + self.suggest_remove_reference(&obligation, &mut err, leaf_trait_predicate); suggested |= self.suggest_semicolon_removal( &obligation, &mut err, span, - trait_predicate, + leaf_trait_predicate, ); - self.note_version_mismatch(&mut err, &trait_ref); + self.note_version_mismatch(&mut err, &leaf_trait_ref); self.suggest_remove_await(&obligation, &mut err); - self.suggest_derive(&obligation, &mut err, trait_predicate); + self.suggest_derive(&obligation, &mut err, leaf_trait_predicate); - if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() { + if Some(leaf_trait_ref.def_id()) == tcx.lang_items().try_trait() { self.suggest_await_before_try( &mut err, &obligation, - trait_predicate, + leaf_trait_predicate, span, ); } - if self.suggest_add_clone_to_arg(&obligation, &mut err, trait_predicate) { + if self.suggest_add_clone_to_arg(&obligation, &mut err, leaf_trait_predicate) { return err.emit(); } - if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) { + if self.suggest_impl_trait(&mut err, &obligation, leaf_trait_predicate) { return err.emit(); } @@ -741,9 +743,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); } - let is_fn_trait = tcx.is_fn_trait(trait_ref.def_id()); + let is_fn_trait = tcx.is_fn_trait(leaf_trait_ref.def_id()); let is_target_feature_fn = if let ty::FnDef(def_id, _) = - *trait_ref.skip_binder().self_ty().kind() + *leaf_trait_ref.skip_binder().self_ty().kind() { !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() } else { @@ -757,8 +759,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.try_to_add_help_message( &obligation, - trait_ref, - &trait_predicate, + leaf_trait_ref, + &leaf_trait_predicate, &mut err, span, is_fn_trait, @@ -769,17 +771,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Changing mutability doesn't make a difference to whether we have // an `Unsize` impl (Fixes ICE in #71036) if !is_unsize { - self.suggest_change_mut(&obligation, &mut err, trait_predicate); + self.suggest_change_mut(&obligation, &mut err, leaf_trait_predicate); } // If this error is due to `!: Trait` not implemented but `(): Trait` is // implemented, and fallback has occurred, then it could be due to a // variable that used to fallback to `()` now falling back to `!`. Issue a // note informing about the change in behaviour. - if trait_predicate.skip_binder().self_ty().is_never() + if leaf_trait_predicate.skip_binder().self_ty().is_never() && self.fallback_has_occurred { - let predicate = trait_predicate.map_bound(|trait_pred| { + let predicate = leaf_trait_predicate.map_bound(|trait_pred| { trait_pred.with_self_ty(self.tcx, tcx.types.unit) }); let unit_obligation = obligation.with(tcx, predicate); @@ -794,8 +796,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - self.explain_hrtb_projection(&mut err, trait_predicate, obligation.param_env, &obligation.cause); - self.suggest_desugaring_async_fn_in_trait(&mut err, trait_ref); + self.explain_hrtb_projection(&mut err, leaf_trait_predicate, obligation.param_env, &obligation.cause); + self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_ref); // Return early if the trait is Debug or Display and the invocation // originates within a standard library macro, because the output @@ -813,15 +815,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if in_std_macro && matches!( - self.tcx.get_diagnostic_name(trait_ref.def_id()), + self.tcx.get_diagnostic_name(leaf_trait_ref.def_id()), Some(sym::Debug | sym::Display) ) { return err.emit(); } - - err } diff --git a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr index 47bb1a059be..4773ac4ccf7 100644 --- a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr +++ b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&'static u32: Defaulted` is not satisfied --> $DIR/typeck-default-trait-impl-precedence.rs:19:20 | LL | is_defaulted::<&'static u32>(); - | ^^^^^^^^^^^^ the trait `Signed` is not implemented for `&'static u32`, which is required by `&'static u32: Defaulted` + | ^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`, which is required by `&'static u32: Defaulted` | note: required for `&'static u32` to implement `Defaulted` --> $DIR/typeck-default-trait-impl-precedence.rs:10:19 diff --git a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr index 2c372b6c3a7..9b5d84b5b09 100644 --- a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr +++ b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `i32: Baz` is not satisfied --> $DIR/assume-gat-normalization-for-nested-goals.rs:9:30 | LL | type Bar: Baz = i32; - | ^^^ the trait `Eq` is not implemented for `i32`, which is required by `i32: Baz` + | ^^^ the trait `Eq` is not implemented for `::Bar<()>`, which is required by `i32: Baz` | note: required for `i32` to implement `Baz` --> $DIR/assume-gat-normalization-for-nested-goals.rs:16:23 diff --git a/tests/ui/kindck/kindck-send-object.stderr b/tests/ui/kindck/kindck-send-object.stderr index 9f1ff4f3644..7d0c711abc4 100644 --- a/tests/ui/kindck/kindck-send-object.stderr +++ b/tests/ui/kindck/kindck-send-object.stderr @@ -4,7 +4,7 @@ error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads sa LL | assert_send::<&'static (dyn Dummy + 'static)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely | - = help: the trait `Sync` is not implemented for `&'static (dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send` = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` note: required by a bound in `assert_send` --> $DIR/kindck-send-object.rs:5:18 diff --git a/tests/ui/kindck/kindck-send-object1.stderr b/tests/ui/kindck/kindck-send-object1.stderr index f2aa814676f..7f39dab2086 100644 --- a/tests/ui/kindck/kindck-send-object1.stderr +++ b/tests/ui/kindck/kindck-send-object1.stderr @@ -4,7 +4,7 @@ error[E0277]: `&'a (dyn Dummy + 'a)` cannot be sent between threads safely LL | assert_send::<&'a dyn Dummy>(); | ^^^^^^^^^^^^^ `&'a (dyn Dummy + 'a)` cannot be sent between threads safely | - = help: the trait `Sync` is not implemented for `&'a (dyn Dummy + 'a)`, which is required by `&'a (dyn Dummy + 'a): Send` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)`, which is required by `&'a (dyn Dummy + 'a): Send` = note: required for `&'a (dyn Dummy + 'a)` to implement `Send` note: required by a bound in `assert_send` --> $DIR/kindck-send-object1.rs:5:18 diff --git a/tests/ui/kindck/kindck-send-object2.stderr b/tests/ui/kindck/kindck-send-object2.stderr index cd4d74360f8..a481a132cce 100644 --- a/tests/ui/kindck/kindck-send-object2.stderr +++ b/tests/ui/kindck/kindck-send-object2.stderr @@ -4,7 +4,7 @@ error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads sa LL | assert_send::<&'static dyn Dummy>(); | ^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely | - = help: the trait `Sync` is not implemented for `&'static (dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send` = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` note: required by a bound in `assert_send` --> $DIR/kindck-send-object2.rs:3:18 diff --git a/tests/ui/suggestions/suggest-remove-refs-5.stderr b/tests/ui/suggestions/suggest-remove-refs-5.stderr index 3b6994b45d1..b132c56473e 100644 --- a/tests/ui/suggestions/suggest-remove-refs-5.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-5.stderr @@ -4,7 +4,7 @@ error[E0277]: `&mut &mut &mut &mut Vec` is not an iterator LL | for _ in &mut &mut v {} | ^^^^^^^^^^^ `&mut &mut &mut &mut Vec` is not an iterator | - = help: the trait `Iterator` is not implemented for `&mut &mut &mut &mut Vec`, which is required by `&mut &mut &mut &mut Vec: IntoIterator` + = help: the trait `Iterator` is not implemented for `Vec`, which is required by `&mut &mut &mut &mut Vec: IntoIterator` = note: required for `&mut Vec` to implement `Iterator` = note: 3 redundant requirements hidden = note: required for `&mut &mut &mut &mut Vec` to implement `Iterator` @@ -21,7 +21,7 @@ error[E0277]: `&mut &mut &mut [u8; 1]` is not an iterator LL | for _ in &mut v {} | ^^^^^^ `&mut &mut &mut [u8; 1]` is not an iterator | - = help: the trait `Iterator` is not implemented for `&mut &mut &mut [u8; 1]`, which is required by `&mut &mut &mut [u8; 1]: IntoIterator` + = help: the trait `Iterator` is not implemented for `[u8; 1]`, which is required by `&mut &mut &mut [u8; 1]: IntoIterator` = note: required for `&mut [u8; 1]` to implement `Iterator` = note: 2 redundant requirements hidden = note: required for `&mut &mut &mut [u8; 1]` to implement `Iterator` diff --git a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr index 562d7ccf9fe..e0b23bd8110 100644 --- a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr +++ b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | is_send(foo()); | ^^^^^ future returned by `foo` is not `Send` | - = help: the trait `Sync` is not implemented for `impl Future`, which is required by `impl Future: Send` + = help: the trait `Sync` is not implemented for `NotSync`, which is required by `impl Future: Send` note: future is not `Send` as this value is used across an await --> $DIR/auto-with-drop_tracking_mir.rs:16:11 | diff --git a/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr b/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr index 6bf4e3cb534..9a18a58debd 100644 --- a/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr +++ b/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr @@ -4,6 +4,11 @@ error[E0277]: the trait bound `(): Foo` is not satisfied LL | needs_foo::<()>(); | ^^ the trait `Bar` is not implemented for `()`, which is required by `(): Foo` | +help: this trait has no implementations, consider adding one + --> $DIR/point-at-failing-nested.rs:4:1 + | +LL | trait Bar {} + | ^^^^^^^^^ note: required for `()` to implement `Foo` --> $DIR/point-at-failing-nested.rs:9:12 | diff --git a/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr index 77a0cc49754..ab1d4a56c02 100644 --- a/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr +++ b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr @@ -6,6 +6,11 @@ LL | needs_foo(()); | | | required by a bound introduced by this call | +help: this trait has no implementations, consider adding one + --> $DIR/where-clause-doesnt-apply.rs:2:1 + | +LL | trait Bar {} + | ^^^^^^^^^ note: required for `()` to implement `Foo` --> $DIR/where-clause-doesnt-apply.rs:4:9 | diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.stderr b/tests/ui/traits/suggest-dereferences/root-obligation.stderr index 14b2ecbb9f2..bbfbb98fba7 100644 --- a/tests/ui/traits/suggest-dereferences/root-obligation.stderr +++ b/tests/ui/traits/suggest-dereferences/root-obligation.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&char: Pattern<'_>` is not satisfied --> $DIR/root-obligation.rs:6:38 | LL | .filter(|c| "aeiou".contains(c)) - | -------- ^ the trait `Fn(char)` is not implemented for `&char`, which is required by `&char: Pattern<'_>` + | -------- ^ the trait `Fn(char)` is not implemented for `char`, which is required by `&char: Pattern<'_>` | | | required by a bound introduced by this call | diff --git a/tests/ui/transmutability/references/unsafecell.stderr b/tests/ui/transmutability/references/unsafecell.stderr index 651eb8ceb26..8bb32359355 100644 --- a/tests/ui/transmutability/references/unsafecell.stderr +++ b/tests/ui/transmutability/references/unsafecell.stderr @@ -2,7 +2,7 @@ error[E0277]: `&u8` cannot be safely transmuted into `&UnsafeCell` --> $DIR/unsafecell.rs:27:50 | LL | assert::is_maybe_transmutable::<&'static u8, &'static UnsafeCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `&'static UnsafeCell` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell` | note: required by a bound in `is_maybe_transmutable` --> $DIR/unsafecell.rs:12:14 @@ -17,7 +17,7 @@ error[E0277]: `&UnsafeCell` cannot be safely transmuted into `&UnsafeCell $DIR/unsafecell.rs:29:62 | LL | assert::is_maybe_transmutable::<&'static UnsafeCell, &'static UnsafeCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `&'static UnsafeCell` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell` | note: required by a bound in `is_maybe_transmutable` --> $DIR/unsafecell.rs:12:14 -- cgit 1.4.1-3-g733a5 From 93d83c8f6957e30e6985e9f133afac74423ea65a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 8 Jun 2024 14:02:14 -0400 Subject: Bless and add ICE regression test --- .../suggest-similar-impls-for-root-obligation.rs | 16 ++++++++++++++++ .../suggest-similar-impls-for-root-obligation.stderr | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs create mode 100644 tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr diff --git a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs new file mode 100644 index 00000000000..243a3218359 --- /dev/null +++ b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs @@ -0,0 +1,16 @@ +trait Foo<'s> {} + +impl<'s> Foo<'s> for () {} + +struct Bar; + +impl<'s, T: Foo<'s>> From for Bar { + fn from(_: T) -> Self { + Bar + } +} + +fn main() { + let _: Bar = ((),).into(); + //~^ ERROR he trait bound `((),): Into` is not satisfied +} \ No newline at end of file diff --git a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr new file mode 100644 index 00000000000..8410574e311 --- /dev/null +++ b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `((),): Into` is not satisfied + --> $DIR/suggest-similar-impls-for-root-obligation.rs:14:24 + | +LL | let _: Bar = ((),).into(); + | ^^^^ the trait `Foo<'_>` is not implemented for `((),)`, which is required by `((),): Into<_>` + | + = help: the trait `Foo<'_>` is implemented for `()` + = help: for that trait implementation, expected `()`, found `((),)` +note: required for `Bar` to implement `From<((),)>` + --> $DIR/suggest-similar-impls-for-root-obligation.rs:7:22 + | +LL | impl<'s, T: Foo<'s>> From for Bar { + | ------- ^^^^^^^ ^^^ + | | + | unsatisfied trait bound introduced here + = note: required for `((),)` to implement `Into` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. -- cgit 1.4.1-3-g733a5 From f8d12d9189a6806be81008d4a25717b261ff8eaf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 7 Jun 2024 17:01:55 -0400 Subject: Stop passing both trait pred and trait ref --- .../src/traits/error_reporting/suggestions.rs | 5 ++-- .../traits/error_reporting/type_err_ctxt_ext.rs | 29 ++++++++++++---------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 087f7fbea00..93dbde75d58 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -4863,14 +4863,13 @@ impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> { pub(super) fn get_explanation_based_on_obligation<'tcx>( tcx: TyCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, trait_predicate: &ty::PolyTraitPredicate<'tcx>, pre_message: String, ) -> String { if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { "consider using `()`, or a `Result`".to_owned() } else { - let ty_desc = match trait_ref.skip_binder().self_ty().kind() { + let ty_desc = match trait_predicate.self_ty().skip_binder().kind() { ty::FnDef(_, _) => Some("fn item"), ty::Closure(_, _) => Some("closure"), _ => None, @@ -4895,7 +4894,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( format!( "{pre_message}the trait `{}` is not implemented for{desc} `{}`{post}", trait_predicate.print_modifiers_and_trait_path(), - tcx.short_ty_string(trait_ref.skip_binder().self_ty(), &mut None), + tcx.short_ty_string(trait_predicate.self_ty().skip_binder(), &mut None), ) } else { // "the trait bound `T: !Send` is not satisfied" reads better than "`!Send` is diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index cdf162ca2eb..7796a69f376 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -603,7 +603,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let explanation = get_explanation_based_on_obligation( self.tcx, &obligation, - leaf_trait_ref, &leaf_trait_predicate, pre_message, ); @@ -759,7 +758,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.try_to_add_help_message( &obligation, - leaf_trait_ref, &leaf_trait_predicate, &mut err, span, @@ -3215,7 +3213,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn try_to_add_help_message( &self, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, trait_predicate: &ty::PolyTraitPredicate<'tcx>, err: &mut Diag<'_>, span: Span, @@ -3233,15 +3230,21 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; // Try to report a help message + let trait_def_id = trait_predicate.def_id(); if is_fn_trait && let Ok((implemented_kind, params)) = self.type_implements_fn_trait( obligation.param_env, - trait_ref.self_ty(), + trait_predicate.self_ty(), trait_predicate.skip_binder().polarity, ) { - self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params); - } else if !trait_ref.has_non_region_infer() + self.add_help_message_for_fn_trait( + trait_predicate.to_poly_trait_ref(), + err, + implemented_kind, + params, + ); + } else if !trait_predicate.has_non_region_infer() && self.predicate_can_apply(obligation.param_env, *trait_predicate) { // If a where-clause may be useful, remind the @@ -3257,13 +3260,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { None, obligation.cause.body_id, ); - } else if trait_ref.def_id().is_local() - && self.tcx.trait_impls_of(trait_ref.def_id()).is_empty() - && !self.tcx.trait_is_auto(trait_ref.def_id()) - && !self.tcx.trait_is_alias(trait_ref.def_id()) + } else if trait_def_id.is_local() + && self.tcx.trait_impls_of(trait_def_id).is_empty() + && !self.tcx.trait_is_auto(trait_def_id) + && !self.tcx.trait_is_alias(trait_def_id) { err.span_help( - self.tcx.def_span(trait_ref.def_id()), + self.tcx.def_span(trait_def_id), crate::fluent_generated::trait_selection_trait_has_no_impls, ); } else if !suggested && !unsatisfied_const { @@ -3271,7 +3274,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let impl_candidates = self.find_similar_impl_candidates(*trait_predicate); if !self.report_similar_impl_candidates( &impl_candidates, - trait_ref, + trait_predicate.to_poly_trait_ref(), body_def_id, err, true, @@ -3288,7 +3291,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.suggest_convert_to_slice( err, obligation, - trait_ref, + trait_predicate.to_poly_trait_ref(), impl_candidates.as_slice(), span, ); -- cgit 1.4.1-3-g733a5 From 2c0348a0d8ac511a63e92443f570147a97a6580d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 7 Jun 2024 17:05:30 -0400 Subject: Stop passing traitref/traitpredicate by ref --- .../src/infer/error_reporting/note_and_explain.rs | 6 ++-- compiler/rustc_infer/src/traits/util.rs | 3 +- compiler/rustc_middle/src/traits/util.rs | 2 +- compiler/rustc_middle/src/ty/predicate.rs | 2 +- .../src/traits/error_reporting/suggestions.rs | 4 +-- .../traits/error_reporting/type_err_ctxt_ext.rs | 32 ++++++++++------------ .../src/traits/object_safety.rs | 2 +- .../rustc_trait_selection/src/traits/select/mod.rs | 14 +++++----- compiler/rustc_trait_selection/src/traits/util.rs | 2 +- .../rustc_trait_selection/src/traits/vtable.rs | 2 +- .../suggest-similar-impls-for-root-obligation.rs | 2 +- 11 files changed, 33 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index effb4090692..bc59b5e033b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -546,7 +546,7 @@ impl Trait for X { for pred in hir_generics.bounds_for_param(def_id) { if self.constrain_generic_bound_associated_type_structured_suggestion( diag, - &trait_ref, + trait_ref, pred.bounds, assoc, assoc_args, @@ -715,7 +715,7 @@ fn foo(&self) -> Self::T { String::new() } self.constrain_generic_bound_associated_type_structured_suggestion( diag, - &trait_ref, + trait_ref, opaque_hir_ty.bounds, assoc, assoc_args, @@ -869,7 +869,7 @@ fn foo(&self) -> Self::T { String::new() } fn constrain_generic_bound_associated_type_structured_suggestion( &self, diag: &mut Diag<'_>, - trait_ref: &ty::TraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, assoc: ty::AssocItem, assoc_args: &[ty::GenericArg<'tcx>], diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index cc12a4bf091..ab4148faaab 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -285,8 +285,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { let obligations = predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| { elaboratable.child_with_derived_cause( - clause - .instantiate_supertrait(tcx, &bound_clause.rebind(data.trait_ref)), + clause.instantiate_supertrait(tcx, bound_clause.rebind(data.trait_ref)), span, bound_clause.rebind(data), index, diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs index 707e076921b..adbb6cf2ddc 100644 --- a/compiler/rustc_middle/src/traits/util.rs +++ b/compiler/rustc_middle/src/traits/util.rs @@ -37,7 +37,7 @@ impl<'tcx> Elaborator<'tcx> { let super_predicates = self.tcx.super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map( |&(pred, _)| { - let clause = pred.instantiate_supertrait(self.tcx, &trait_ref); + let clause = pred.instantiate_supertrait(self.tcx, trait_ref); self.visited.insert(clause).then_some(clause) }, ); diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index c730f5117c5..785aa8d456f 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -313,7 +313,7 @@ impl<'tcx> Clause<'tcx> { pub fn instantiate_supertrait( self, tcx: TyCtxt<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, ) -> Clause<'tcx> { // The interaction between HRTB and supertraits is not entirely // obvious. Let me walk you (and myself) through an example. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 93dbde75d58..bd85f34aa8e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3597,7 +3597,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, - trait_ref: &ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, ) { let rhs_span = match obligation.cause.code() { ObligationCauseCode::BinOp { rhs_span: Some(span), rhs_is_lit, .. } if *rhs_is_lit => { @@ -4863,7 +4863,7 @@ impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> { pub(super) fn get_explanation_based_on_obligation<'tcx>( tcx: TyCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, - trait_predicate: &ty::PolyTraitPredicate<'tcx>, + trait_predicate: ty::PolyTraitPredicate<'tcx>, pre_message: String, ) -> String { if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 7796a69f376..54f337310f5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -532,7 +532,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; let err_msg = self.get_standard_error_message( - &main_trait_predicate, + main_trait_predicate, message, predicate_is_const, append_const_msg, @@ -603,7 +603,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let explanation = get_explanation_based_on_obligation( self.tcx, &obligation, - &leaf_trait_predicate, + leaf_trait_predicate, pre_message, ); @@ -658,7 +658,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let UnsatisfiedConst(unsatisfied_const) = self .maybe_add_note_for_unsatisfied_const( - &leaf_trait_predicate, + leaf_trait_predicate, &mut err, span, ); @@ -675,7 +675,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err.span_label(tcx.def_span(body), s); } - self.suggest_floating_point_literal(&obligation, &mut err, &leaf_trait_ref); + self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_ref); self.suggest_dereferencing_index(&obligation, &mut err, leaf_trait_predicate); suggested |= self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate); suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate); @@ -710,7 +710,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span, leaf_trait_predicate, ); - self.note_version_mismatch(&mut err, &leaf_trait_ref); + self.note_version_mismatch(&mut err, leaf_trait_ref); self.suggest_remove_await(&obligation, &mut err); self.suggest_derive(&obligation, &mut err, leaf_trait_predicate); @@ -758,7 +758,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.try_to_add_help_message( &obligation, - &leaf_trait_predicate, + leaf_trait_predicate, &mut err, span, is_fn_trait, @@ -2234,11 +2234,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait /// with the same path as `trait_ref`, a help message about /// a probable version mismatch is added to `err` - fn note_version_mismatch( - &self, - err: &mut Diag<'_>, - trait_ref: &ty::PolyTraitRef<'tcx>, - ) -> bool { + fn note_version_mismatch(&self, err: &mut Diag<'_>, trait_ref: ty::PolyTraitRef<'tcx>) -> bool { let get_trait_impls = |trait_def_id| { let mut trait_impls = vec![]; self.tcx.for_each_relevant_impl( @@ -3042,7 +3038,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn get_standard_error_message( &self, - trait_predicate: &ty::PolyTraitPredicate<'tcx>, + trait_predicate: ty::PolyTraitPredicate<'tcx>, message: Option, predicate_is_const: bool, append_const_msg: Option, @@ -3213,7 +3209,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn try_to_add_help_message( &self, obligation: &PredicateObligation<'tcx>, - trait_predicate: &ty::PolyTraitPredicate<'tcx>, + trait_predicate: ty::PolyTraitPredicate<'tcx>, err: &mut Diag<'_>, span: Span, is_fn_trait: bool, @@ -3245,7 +3241,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { params, ); } else if !trait_predicate.has_non_region_infer() - && self.predicate_can_apply(obligation.param_env, *trait_predicate) + && self.predicate_can_apply(obligation.param_env, trait_predicate) { // If a where-clause may be useful, remind the // user that they can add it. @@ -3256,7 +3252,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // which is somewhat confusing. self.suggest_restricting_param_bound( err, - *trait_predicate, + trait_predicate, None, obligation.cause.body_id, ); @@ -3271,7 +3267,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); } else if !suggested && !unsatisfied_const { // Can't show anything else useful, try to find similar impls. - let impl_candidates = self.find_similar_impl_candidates(*trait_predicate); + let impl_candidates = self.find_similar_impl_candidates(trait_predicate); if !self.report_similar_impl_candidates( &impl_candidates, trait_predicate.to_poly_trait_ref(), @@ -3282,7 +3278,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) { self.report_similar_impl_candidates_for_root_obligation( obligation, - *trait_predicate, + trait_predicate, body_def_id, err, ); @@ -3356,7 +3352,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn maybe_add_note_for_unsatisfied_const( &self, - _trait_predicate: &ty::PolyTraitPredicate<'tcx>, + _trait_predicate: ty::PolyTraitPredicate<'tcx>, _err: &mut Diag<'_>, _span: Span, ) -> UnsatisfiedConst { diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 08355ef55c4..fc5a2875b67 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -194,7 +194,7 @@ fn predicates_reference_self( predicates .predicates .iter() - .map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, &trait_ref), sp)) + .map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, trait_ref), sp)) .filter_map(|predicate| predicate_references_self(tcx, predicate)) .collect() } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4306a803524..4487ba60faa 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1866,7 +1866,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // the param_env so that it can be given the lowest priority. See // #50825 for the motivation for this. let is_global = - |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars(); + |cand: ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars(); // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, // `DiscriminantKindCandidate`, `ConstDestructCandidate` @@ -1909,7 +1909,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ( - ParamCandidate(ref other_cand), + ParamCandidate(other_cand), ImplCandidate(..) | AutoImplCandidate | ClosureCandidate { .. } @@ -1934,12 +1934,12 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // // Global bounds from the where clause should be ignored // here (see issue #50825). - DropVictim::drop_if(!is_global(other_cand)) + DropVictim::drop_if(!is_global(*other_cand)) } - (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref victim_cand)) => { + (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(victim_cand)) => { // Prefer these to a global where-clause bound // (see issue #50825). - if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No } + if is_global(*victim_cand) { DropVictim::Yes } else { DropVictim::No } } ( ImplCandidate(_) @@ -1957,12 +1957,12 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | TraitUpcastingUnsizeCandidate(_) | BuiltinCandidate { has_nested: true } | TraitAliasCandidate, - ParamCandidate(ref victim_cand), + ParamCandidate(victim_cand), ) => { // Prefer these to a global where-clause bound // (see issue #50825). DropVictim::drop_if( - is_global(victim_cand) && other.evaluation.must_apply_modulo_regions(), + is_global(*victim_cand) && other.evaluation.must_apply_modulo_regions(), ) } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 960c27b636e..ce7245d93a4 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -132,7 +132,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { debug!(?predicates); let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { - pred.instantiate_supertrait(tcx, &trait_ref) + pred.instantiate_supertrait(tcx, trait_ref) .as_trait_clause() .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span)) }); diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index c93ec43944a..9bd4a9aab0a 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -125,7 +125,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( .predicates .into_iter() .filter_map(move |(pred, _)| { - pred.instantiate_supertrait(tcx, &inner_most_trait_ref).as_trait_clause() + pred.instantiate_supertrait(tcx, inner_most_trait_ref).as_trait_clause() }); // Find an unvisited supertrait diff --git a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs index 243a3218359..d00b4f33132 100644 --- a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs +++ b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs @@ -13,4 +13,4 @@ impl<'s, T: Foo<'s>> From for Bar { fn main() { let _: Bar = ((),).into(); //~^ ERROR he trait bound `((),): Into` is not satisfied -} \ No newline at end of file +} -- cgit 1.4.1-3-g733a5 From d1fa19ce93c9f79fdd123e785599a84ea8925c7c Mon Sep 17 00:00:00 2001 From: Aleksandr Pak <45790125+sancho20021@users.noreply.github.com> Date: Wed, 12 Jun 2024 16:05:45 +1000 Subject: Add urls to rust lang reference --- compiler/rustc_hir/src/hir.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 87ff39a8294..d948945bf42 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1632,6 +1632,13 @@ pub struct ConstBlock { } /// An expression. +/// +/// For more details, see the [rust lang reference]. +/// Note that the reference does not document nightly-only features. +/// There may be also slight differences in the names and representation of AST nodes between +/// the compiler and the reference. +/// +/// [rust lang reference]: https://doc.rust-lang.org/reference/expressions.html #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Expr<'hir> { pub hir_id: HirId, @@ -3146,6 +3153,13 @@ impl ItemId { /// An item /// /// The name might be a dummy name in case of anonymous items +/// +/// For more details, see the [rust lang reference]. +/// Note that the reference does not document nightly-only features. +/// There may be also slight differences in the names and representation of AST nodes between +/// the compiler and the reference. +/// +/// [rust lang reference]: https://doc.rust-lang.org/reference/items.html #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Item<'hir> { pub ident: Ident, -- cgit 1.4.1-3-g733a5 From ae24ebe7102d254959c0d7b8f7e9ec3dfdd1aaaa Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 21:17:33 -0400 Subject: Rebase fallout --- .../src/traits/error_reporting/suggestions.rs | 9 ++++----- .../src/traits/error_reporting/type_err_ctxt_ext.rs | 6 ++++-- tests/ui/impl-trait/nested_impl_trait.stderr | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index bd85f34aa8e..4604c132835 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -4592,7 +4592,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ) { if ObligationCauseCode::QuestionMark != *obligation.cause.code().peel_derives() { return; @@ -4602,10 +4602,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if let hir::Node::Item(item) = node && let hir::ItemKind::Fn(sig, _, body_id) = item.kind && let hir::FnRetTy::DefaultReturn(ret_span) = sig.decl.output - && self.tcx.is_diagnostic_item(sym::FromResidual, trait_ref.def_id()) - && let ty::Tuple(l) = trait_ref.skip_binder().args.type_at(0).kind() - && l.len() == 0 - && let ty::Adt(def, _) = trait_ref.skip_binder().args.type_at(1).kind() + && self.tcx.is_diagnostic_item(sym::FromResidual, trait_pred.def_id()) + && trait_pred.skip_binder().trait_ref.args.type_at(0).is_unit() + && let ty::Adt(def, _) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind() && self.tcx.is_diagnostic_item(sym::Result, def.did()) { let body = self.tcx.hir().body(body_id); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 54f337310f5..3377ab5764a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -612,9 +612,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &mut err, leaf_trait_predicate, ); - self.suggest_add_result_as_return_type(&obligation, + self.suggest_add_result_as_return_type( + &obligation, &mut err, - trait_ref); + leaf_trait_predicate, + ); if self.suggest_add_reference_to_arg( &obligation, diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr index 1f9a2a5e9d6..a53312e5c0b 100644 --- a/tests/ui/impl-trait/nested_impl_trait.stderr +++ b/tests/ui/impl-trait/nested_impl_trait.stderr @@ -46,7 +46,7 @@ error[E0277]: the trait bound `impl Into: Into` is not satisfie --> $DIR/nested_impl_trait.rs:6:46 | LL | fn bad_in_ret_position(x: impl Into) -> impl Into { x } - | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Into`, which is required by `impl Into: Into` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug`, which is required by `impl Into: Into` | = help: the trait `Into` is implemented for `T` = note: required for `impl Into` to implement `Into` @@ -55,7 +55,7 @@ error[E0277]: the trait bound `impl Into: Into` is not satisfie --> $DIR/nested_impl_trait.rs:19:34 | LL | fn bad(x: impl Into) -> impl Into { x } - | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Into`, which is required by `impl Into: Into` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug`, which is required by `impl Into: Into` | = help: the trait `Into` is implemented for `T` = note: required for `impl Into` to implement `Into` -- cgit 1.4.1-3-g733a5 From c9d880bf01dc0356120f159e9bd78c0567c51513 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 11 Jun 2024 15:37:43 +1000 Subject: compiletest: Move `static_regex!` into `compiletest::util` --- src/tools/compiletest/src/runtest.rs | 10 +--------- src/tools/compiletest/src/runtest/coverage.rs | 3 ++- src/tools/compiletest/src/util.rs | 8 ++++++++ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index dbe016b8305..a0e5fa4d10d 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -15,7 +15,7 @@ use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; use crate::json; use crate::read2::{read2_abbreviated, Truncated}; -use crate::util::{add_dylib_path, copy_dir_all, dylib_env_var, logv, PathBufExt}; +use crate::util::{add_dylib_path, copy_dir_all, dylib_env_var, logv, static_regex, PathBufExt}; use crate::ColorConfig; use colored::Colorize; use miropt_test_tools::{files_for_miropt_test, MiroptTest, MiroptTestFile}; @@ -48,14 +48,6 @@ use debugger::DebuggerCommands; #[cfg(test)] mod tests; -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()) - }}; -} -use static_regex; - const FAKE_SRC_BASE: &str = "fake-test-src-base"; #[cfg(windows)] diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs index 8bd7c7e808d..6ee147da5a9 100644 --- a/src/tools/compiletest/src/runtest/coverage.rs +++ b/src/tools/compiletest/src/runtest/coverage.rs @@ -7,7 +7,8 @@ use std::process::Command; use glob::glob; use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP}; -use crate::runtest::{static_regex, Emit, ProcRes, TestCx, WillExecute}; +use crate::runtest::{Emit, ProcRes, TestCx, WillExecute}; +use crate::util::static_regex; impl<'test> TestCx<'test> { fn coverage_dump_path(&self) -> &Path { diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index ec20bda8c18..cdec49a51d7 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -90,3 +90,11 @@ pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Re } Ok(()) } + +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()) + }}; +} +pub(crate) use static_regex; -- cgit 1.4.1-3-g733a5 From fb662f2126b026c91ddbc17ac3bdb8bd2bf575c5 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Wed, 12 Jun 2024 22:07:37 +0000 Subject: safe transmute: support `Variants::Single` enums Previously, the implementation of `Tree::from_enum` incorrectly treated enums with `Variants::Single` and `Variants::Multiple` identically. This is incorrect for `Variants::Single` enums, which delegate their layout to that of a variant with a particular index (or no variant at all if the enum is empty). This flaw manifested first as an ICE. `Tree::from_enum` attempted to compute the tag of variants other than the one at `Variants::Single`'s `index`, and fell afoul of a sanity-checking assertion in `compiler/rustc_const_eval/src/interpret/discriminant.rs`. This assertion is non-load-bearing, and can be removed; the routine its in is well-behaved even without it. With the assertion removed, the proximate issue becomes apparent: calling `Tree::from_variant` on a variant that does not exist is ill-defined. A sanity check the given variant has `FieldShapes::Arbitrary` fails, and the analysis is (correctly) aborted with `Err::NotYetSupported`. This commit corrects this chain of failures by ensuring that `Tree::from_variant` is not called on variants that are, as far as layout is concerned, nonexistent. Specifically, the implementation of `Tree::from_enum` is now partitioned into three cases: 1. enums that are uninhabited 2. enums for which all but one variant is uninhabited 3. enums with multiple inhabited variants `Tree::from_variant` is now only invoked in the third case. In the first case, `Tree::uninhabited()` is produced. In the second case, the layout is delegated to `Variants::Single`'s index. Fixes #125811 --- .../rustc_const_eval/src/interpret/discriminant.rs | 5 +- compiler/rustc_transmute/src/layout/tree.rs | 75 ++++++++++++++++------ tests/crashes/125811.rs | 34 ---------- .../enums/uninhabited_optimization.rs | 26 ++++++++ 4 files changed, 81 insertions(+), 59 deletions(-) delete mode 100644 tests/crashes/125811.rs create mode 100644 tests/ui/transmutability/enums/uninhabited_optimization.rs diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 0dbee8c1d94..a50b50d231d 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -241,10 +241,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { variant_index: VariantIdx, ) -> InterpResult<'tcx, Option<(ScalarInt, usize)>> { match self.layout_of(ty)?.variants { - abi::Variants::Single { index } => { - assert_eq!(index, variant_index); - Ok(None) - } + abi::Variants::Single { .. } => Ok(None), abi::Variants::Multiple { tag_encoding: TagEncoding::Direct, diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index eae1a9dfaa2..241381f5875 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -331,30 +331,63 @@ pub(crate) mod rustc { assert!(def.is_enum()); let layout = ty_and_layout.layout; - if let Variants::Multiple { tag_field, .. } = layout.variants() { - // For enums (but not coroutines), the tag field is - // currently always the first field of the layout. - assert_eq!(*tag_field, 0); - } + // Computes the variant of a given index. + let layout_of_variant = |index| { + let tag = cx.tcx.tag_for_variant((ty_and_layout.ty, index)); + let variant_def = Def::Variant(def.variant(index)); + let variant_ty_and_layout = ty_and_layout.for_variant(&cx, index); + Self::from_variant(variant_def, tag, variant_ty_and_layout, layout.size, cx) + }; - let variants = def.discriminants(cx.tcx()).try_fold( - Self::uninhabited(), - |variants, (idx, ref discriminant)| { - let tag = cx.tcx.tag_for_variant((ty_and_layout.ty, idx)); - let variant_def = Def::Variant(def.variant(idx)); - let variant_ty_and_layout = ty_and_layout.for_variant(&cx, idx); - let variant = Self::from_variant( - variant_def, - tag, - variant_ty_and_layout, - layout.size, - cx, + // We consider three kinds of enums, each demanding a different + // treatment of their layout computation: + // 1. enums that are uninhabited + // 2. enums for which all but one variant is uninhabited + // 3. enums with multiple inhabited variants + match layout.variants() { + _ if layout.abi.is_uninhabited() => { + // Uninhabited enums are usually (always?) zero-sized. In + // the (unlikely?) event that an uninhabited enum is + // non-zero-sized, this assert will trigger an ICE, and this + // code should be modified such that a `layout.size` amount + // of uninhabited bytes is returned instead. + // + // Uninhabited enums are currently implemented such that + // their layout is described with `Variants::Single`, even + // though they don't necessarily have a 'single' variant to + // defer to. That said, we don't bother specifically + // matching on `Variants::Single` in this arm because the + // behavioral principles here remain true even if, for + // whatever reason, the compiler describes an uninhabited + // enum with `Variants::Multiple`. + assert_eq!(layout.size, Size::ZERO); + Ok(Self::uninhabited()) + } + Variants::Single { index } => { + // `Variants::Single` on non-uninhabited enums denotes that + // the enum delegates its layout to the variant at `index`. + layout_of_variant(*index) + } + Variants::Multiple { tag_field, .. } => { + // `Variants::Multiple` denotes an enum with multiple + // inhabited variants. The layout of such an enum is the + // disjunction of the layouts of its tagged variants. + + // For enums (but not coroutines), the tag field is + // currently always the first field of the layout. + assert_eq!(*tag_field, 0); + + let variants = def.discriminants(cx.tcx()).try_fold( + Self::uninhabited(), + |variants, (idx, ref discriminant)| { + let variant = layout_of_variant(idx)?; + Result::::Ok(variants.or(variant)) + }, )?; - Result::::Ok(variants.or(variant)) - }, - )?; - return Ok(Self::def(Def::Adt(def)).then(variants)); + return Ok(Self::def(Def::Adt(def)).then(variants)); + } + } } /// Constructs a `Tree` from a 'variant-like' layout. diff --git a/tests/crashes/125811.rs b/tests/crashes/125811.rs deleted file mode 100644 index eb764e8d152..00000000000 --- a/tests/crashes/125811.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@ known-bug: rust-lang/rust#125811 -mod assert { - use std::mem::{Assume, BikeshedIntrinsicFrom}; - - pub fn is_transmutable() - where - Dst: BikeshedIntrinsicFrom, - { - } -} - -#[repr(C)] -struct Zst; - -enum V0 { - B(!), -} - -enum V2 { - V = 2, -} - -enum Lopsided { - Smol(Zst), - Lorg(V0), -} - -#[repr(C)] -#[repr(C)] -struct Dst(Lopsided, V2); - -fn should_pad_variants() { - assert::is_transmutable::(); -} diff --git a/tests/ui/transmutability/enums/uninhabited_optimization.rs b/tests/ui/transmutability/enums/uninhabited_optimization.rs new file mode 100644 index 00000000000..04a8eb40c8b --- /dev/null +++ b/tests/ui/transmutability/enums/uninhabited_optimization.rs @@ -0,0 +1,26 @@ +//@ check-pass +//! Tests that we do not regress rust-lang/rust#125811 +#![feature(transmutability)] + +fn assert_transmutable() +where + (): std::mem::BikeshedIntrinsicFrom +{} + +enum Uninhabited {} + +enum SingleInhabited { + X, + Y(Uninhabited) +} + +enum SingleUninhabited { + X(Uninhabited), + Y(Uninhabited), +} + +fn main() { + assert_transmutable::(); + assert_transmutable::(); + assert_transmutable::(); +} -- cgit 1.4.1-3-g733a5 From e09eedbe93bcf4bf44a11d7364e1ebcdc6e9b9d2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 13 Jun 2024 00:32:38 +1000 Subject: compiletest: Stricter parsing of `//@ normalize-*` headers --- src/tools/compiletest/src/header.rs | 48 ++++++++++++---------- src/tools/compiletest/src/header/tests.rs | 66 +++++++++++++++++-------------- 2 files changed, 63 insertions(+), 51 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index da0196dad2f..cc972223f6d 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -14,6 +14,7 @@ use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; use crate::header::cfg::parse_cfg_name_directive; use crate::header::cfg::MatchOutcome; use crate::header::needs::CachedNeedsConditions; +use crate::util::static_regex; use crate::{extract_cdb_version, extract_gdb_version}; mod cfg; @@ -1186,11 +1187,11 @@ impl Config { } } - fn parse_custom_normalization(&self, mut line: &str, prefix: &str) -> Option<(String, String)> { + fn parse_custom_normalization(&self, line: &str, prefix: &str) -> Option<(String, String)> { if parse_cfg_name_directive(self, line, prefix).outcome == MatchOutcome::Match { - let from = parse_normalization_string(&mut line)?; - let to = parse_normalization_string(&mut line)?; - Some((from, to)) + let (regex, replacement) = parse_normalize_rule(line) + .unwrap_or_else(|| panic!("couldn't parse custom normalization rule: `{line}`")); + Some((regex, replacement)) } else { None } @@ -1311,24 +1312,29 @@ fn expand_variables(mut value: String, config: &Config) -> String { value } -/// Finds the next quoted string `"..."` in `line`, and extract the content from it. Move the `line` -/// variable after the end of the quoted string. -/// -/// # Examples -/// -/// ``` -/// let mut s = "normalize-stderr-32bit: \"something (32 bits)\" -> \"something ($WORD bits)\"."; -/// let first = parse_normalization_string(&mut s); -/// assert_eq!(first, Some("something (32 bits)".to_owned())); -/// assert_eq!(s, " -> \"something ($WORD bits)\"."); +/// Parses the regex and replacement values of a `//@ normalize-*` header, +/// in the format: +/// ```text +/// normalize-*: "REGEX" -> "REPLACEMENT" /// ``` -fn parse_normalization_string(line: &mut &str) -> Option { - // FIXME support escapes in strings. - let begin = line.find('"')? + 1; - let end = line[begin..].find('"')? + begin; - let result = line[begin..end].to_owned(); - *line = &line[end + 1..]; - Some(result) +fn parse_normalize_rule(header: &str) -> Option<(String, String)> { + // FIXME(#126370): A colon after the header name should be mandatory, but + // currently is not, and there are many tests that lack the colon. + // FIXME: Support escaped double-quotes in strings. + let captures = static_regex!( + r#"(?x) # (verbose mode regex) + ^ + [^:\s]+:?\s* # (header name followed by optional colon) + "(?[^"]*)" # "REGEX" + \s+->\s+ # -> + "(?[^"]*)" # "REPLACEMENT" + $ + "# + ) + .captures(header)?; + let regex = captures["regex"].to_owned(); + let replacement = captures["replacement"].to_owned(); + Some((regex, replacement)) } pub fn extract_llvm_version(version: &str) -> Option { diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 8a37a4d6d31..61a85b84ad6 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -3,7 +3,7 @@ use std::path::Path; use std::str::FromStr; use crate::common::{Config, Debugger, Mode}; -use crate::header::{parse_normalization_string, EarlyProps, HeadersCache}; +use crate::header::{parse_normalize_rule, EarlyProps, HeadersCache}; use super::iter_header; @@ -32,35 +32,41 @@ fn make_test_description( } #[test] -fn test_parse_normalization_string() { - let mut s = "normalize-stderr-32bit: \"something (32 bits)\" -> \"something ($WORD bits)\"."; - let first = parse_normalization_string(&mut s); - assert_eq!(first, Some("something (32 bits)".to_owned())); - assert_eq!(s, " -> \"something ($WORD bits)\"."); - - // Nothing to normalize (No quotes) - let mut s = "normalize-stderr-32bit: something (32 bits) -> something ($WORD bits)."; - let first = parse_normalization_string(&mut s); - assert_eq!(first, None); - assert_eq!(s, r#"normalize-stderr-32bit: something (32 bits) -> something ($WORD bits)."#); - - // Nothing to normalize (Only a single quote) - let mut s = "normalize-stderr-32bit: \"something (32 bits) -> something ($WORD bits)."; - let first = parse_normalization_string(&mut s); - assert_eq!(first, None); - assert_eq!(s, "normalize-stderr-32bit: \"something (32 bits) -> something ($WORD bits)."); - - // Nothing to normalize (Three quotes) - let mut s = "normalize-stderr-32bit: \"something (32 bits)\" -> \"something ($WORD bits)."; - let first = parse_normalization_string(&mut s); - assert_eq!(first, Some("something (32 bits)".to_owned())); - assert_eq!(s, " -> \"something ($WORD bits)."); - - // Nothing to normalize (No quotes, 16-bit) - let mut s = "normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)."; - let first = parse_normalization_string(&mut s); - assert_eq!(first, None); - assert_eq!(s, r#"normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)."#); +fn test_parse_normalize_rule() { + let good_data = &[ + ( + r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)""#, + "something (32 bits)", + "something ($WORD bits)", + ), + // FIXME(#126370): A colon after the header name should be mandatory, + // but currently is not, and there are many tests that lack the colon. + ( + r#"normalize-stderr-32bit "something (32 bits)" -> "something ($WORD bits)""#, + "something (32 bits)", + "something ($WORD bits)", + ), + ]; + + for &(input, expected_regex, expected_replacement) in good_data { + let parsed = parse_normalize_rule(input); + let parsed = + parsed.as_ref().map(|(regex, replacement)| (regex.as_str(), replacement.as_str())); + assert_eq!(parsed, Some((expected_regex, expected_replacement))); + } + + let bad_data = &[ + r#"normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)"#, + r#"normalize-stderr-32bit: something (32 bits) -> something ($WORD bits)"#, + r#"normalize-stderr-32bit: "something (32 bits) -> something ($WORD bits)"#, + r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)"#, + r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)"."#, + ]; + + for &input in bad_data { + let parsed = parse_normalize_rule(input); + assert_eq!(parsed, None); + } } #[derive(Default)] -- cgit 1.4.1-3-g733a5 From c81ffab3ec66342d542ef7de39e1ec081027f43d Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 12 Jun 2024 20:49:20 +0000 Subject: std::unix::fs::link using direct linkat call for Solaris and macOs. Since we support solaris 11 and macOs Sierra as minimum, we can get rid of the runtime overhead. --- library/std/src/sys/pal/unix/fs.rs | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 56a0f8e39c4..035c92bc84b 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -22,16 +22,12 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; #[cfg(any(all(target_os = "linux", target_env = "gnu"), target_vendor = "apple"))] use crate::sys::weak::syscall; -#[cfg(any(target_os = "android", target_os = "macos", target_os = "solaris"))] +#[cfg(target_os = "android")] use crate::sys::weak::weak; use libc::{c_int, mode_t}; -#[cfg(any( - target_os = "solaris", - all(target_os = "linux", target_env = "gnu"), - target_vendor = "apple", -))] +#[cfg(any(all(target_os = "linux", target_env = "gnu"), target_vendor = "apple"))] use libc::c_char; #[cfg(any( all(target_os = "linux", not(target_env = "musl")), @@ -1753,19 +1749,6 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> { // Android has `linkat` on newer versions, but we happen to know `link` // always has the correct behavior, so it's here as well. cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; - } else if #[cfg(any(target_os = "macos", target_os = "solaris"))] { - // MacOS (<=10.9) and Solaris 10 lack support for linkat while newer - // versions have it. We want to use linkat if it is available, so we use weak! - // to check. `linkat` is preferable to `link` because it gives us a flag to - // specify how symlinks should be handled. We pass 0 as the flags argument, - // meaning it shouldn't follow symlinks. - weak!(fn linkat(c_int, *const c_char, c_int, *const c_char, c_int) -> c_int); - - if let Some(f) = linkat.get() { - cvt(unsafe { f(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?; - } else { - cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; - }; } else { // Where we can, use `linkat` instead of `link`; see the comment above // this one for details on why. -- cgit 1.4.1-3-g733a5 From 12432130a37e1637690df3dc70c31ecb866e3183 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 13 Jun 2024 11:42:52 +1000 Subject: Remove some unnecessary crate dependencies. --- Cargo.lock | 1 - compiler/rustc_data_structures/Cargo.toml | 6 +++++- compiler/rustc_infer/Cargo.toml | 1 - 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5ea9fee8a6..10ca6b0b4bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4205,7 +4205,6 @@ dependencies = [ "rustc_middle", "rustc_span", "rustc_target", - "rustc_type_ir", "smallvec", "tracing", ] diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 6876046a583..ff0a94f8e9b 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -12,7 +12,6 @@ elsa = "=1.7.1" ena = "0.14.3" indexmap = { version = "2.0.0" } jobserver_crate = { version = "0.1.28", package = "jobserver" } -libc = "0.2" measureme = "11" rustc-hash = "1.1.0" rustc-rayon = { version = "0.5.0", optional = true } @@ -41,6 +40,11 @@ features = [ "Win32_System_Threading", ] +[target.'cfg(unix)'.dependencies] +# tidy-alphabetical-start +libc = "0.2" +# tidy-alphabetical-end + [target.'cfg(not(target_arch = "wasm32"))'.dependencies] # tidy-alphabetical-start memmap2 = "0.2.1" diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 5136ab79a0f..c1565a7d40f 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -18,7 +18,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end -- cgit 1.4.1-3-g733a5 From 2733b8ab8d4407086eb41d615395a9a323a8fd77 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 11 Jun 2024 09:57:16 +0000 Subject: Avoid follow-up errors on erroneous patterns --- compiler/rustc_hir_typeck/src/pat.rs | 13 ++++++------- tests/crashes/109812.rs | 22 ---------------------- tests/crashes/125914.rs | 20 -------------------- tests/ui/pattern/missing_lifetime.rs | 25 +++++++++++++++++++++++++ tests/ui/pattern/missing_lifetime.stderr | 25 +++++++++++++++++++++++++ tests/ui/pattern/type_mismatch.rs | 30 ++++++++++++++++++++++++++++++ tests/ui/pattern/type_mismatch.stderr | 11 +++++++++++ 7 files changed, 97 insertions(+), 49 deletions(-) delete mode 100644 tests/crashes/109812.rs delete mode 100644 tests/crashes/125914.rs create mode 100644 tests/ui/pattern/missing_lifetime.rs create mode 100644 tests/ui/pattern/missing_lifetime.stderr create mode 100644 tests/ui/pattern/type_mismatch.rs create mode 100644 tests/ui/pattern/type_mismatch.stderr diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 9476dc70483..814bdc07637 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1223,12 +1223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type-check the tuple struct pattern against the expected type. let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, pat_info.top_info); - let had_err = if let Some(err) = diag { - err.emit(); - true - } else { - false - }; + let had_err = diag.map(|diag| diag.emit()); // Type-check subpatterns. if subpats.len() == variant.fields.len() @@ -1249,6 +1244,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, ); } + if let Some(e) = had_err { + on_error(e); + return Ty::new_error(tcx, e); + } } else { let e = self.emit_err_pat_wrong_number_of_fields( pat.span, @@ -1257,7 +1256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats, &variant.fields.raw, expected, - had_err, + had_err.is_some(), ); on_error(e); return Ty::new_error(tcx, e); diff --git a/tests/crashes/109812.rs b/tests/crashes/109812.rs deleted file mode 100644 index c29b8746521..00000000000 --- a/tests/crashes/109812.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ known-bug: #109812 - -#![warn(rust_2021_incompatible_closure_captures)] - -enum Either { - One(X), - Two(X), -} - -struct X(Y); - -struct Y; - -fn move_into_fnmut() { - let x = X(Y); - - consume_fnmut(|| { - let Either::Two(ref mut _t) = x; - - let X(mut _t) = x; - }); -} diff --git a/tests/crashes/125914.rs b/tests/crashes/125914.rs deleted file mode 100644 index 77ccb9fb097..00000000000 --- a/tests/crashes/125914.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: rust-lang/rust#125914 -enum AstKind<'ast> { - ExprInt, -} - -enum Foo { - Bar(isize), - Baz, -} - -enum Other { - Other1(Foo), - Other2(AstKind), -} - -fn main() { - match Other::Other1(Foo::Baz) { - ::Other::Other2(::Foo::Bar(..)) => {} - } -} diff --git a/tests/ui/pattern/missing_lifetime.rs b/tests/ui/pattern/missing_lifetime.rs new file mode 100644 index 00000000000..081f667d8f6 --- /dev/null +++ b/tests/ui/pattern/missing_lifetime.rs @@ -0,0 +1,25 @@ +//! This test used to ICE: rust-lang/rust#125914 +//! Instead of actually analyzing the erroneous patterns, +//! we instead stop after typeck where errors are already +//! reported. + +enum AstKind<'ast> { + //~^ ERROR: `'ast` is never used + ExprInt, +} + +enum Foo { + Bar(isize), + Baz, +} + +enum Other { + Other1(Foo), + Other2(AstKind), //~ ERROR: missing lifetime specifier +} + +fn main() { + match Other::Other1(Foo::Baz) { + ::Other::Other2(::Foo::Bar(..)) => {} + } +} diff --git a/tests/ui/pattern/missing_lifetime.stderr b/tests/ui/pattern/missing_lifetime.stderr new file mode 100644 index 00000000000..ec4063fd289 --- /dev/null +++ b/tests/ui/pattern/missing_lifetime.stderr @@ -0,0 +1,25 @@ +error[E0106]: missing lifetime specifier + --> $DIR/missing_lifetime.rs:18:12 + | +LL | Other2(AstKind), + | ^^^^^^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL ~ enum Other<'a> { +LL | Other1(Foo), +LL ~ Other2(AstKind<'a>), + | + +error[E0392]: lifetime parameter `'ast` is never used + --> $DIR/missing_lifetime.rs:6:14 + | +LL | enum AstKind<'ast> { + | ^^^^ unused lifetime parameter + | + = help: consider removing `'ast`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0106, E0392. +For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/pattern/type_mismatch.rs b/tests/ui/pattern/type_mismatch.rs new file mode 100644 index 00000000000..408ff758847 --- /dev/null +++ b/tests/ui/pattern/type_mismatch.rs @@ -0,0 +1,30 @@ +//! This test used to ICE: rust-lang/rust#109812 +//! Instead of actually analyzing the erroneous patterns, +//! we instead stop after typeck where errors are already +//! reported. + +#![warn(rust_2021_incompatible_closure_captures)] + +enum Either { + One(X), + Two(X), +} + +struct X(Y); + +struct Y; + +fn consume_fnmut(_: impl FnMut()) {} + +fn move_into_fnmut() { + let x = X(Y); + + consume_fnmut(|| { + let Either::Two(ref mut _t) = x; + //~^ ERROR: mismatched types + + let X(mut _t) = x; + }); +} + +fn main() {} diff --git a/tests/ui/pattern/type_mismatch.stderr b/tests/ui/pattern/type_mismatch.stderr new file mode 100644 index 00000000000..b0441b1fadc --- /dev/null +++ b/tests/ui/pattern/type_mismatch.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:23:13 + | +LL | let Either::Two(ref mut _t) = x; + | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `X` + | | + | expected `X`, found `Either` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. -- cgit 1.4.1-3-g733a5 From a6217011f6aefde02af1a19a7716a411dd7803ff Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 12 Jun 2024 14:59:32 +0000 Subject: Replace some `Option` with `Result<(), Diag>` --- .../src/diagnostics/conflict_errors.rs | 10 ++-- compiler/rustc_hir_typeck/src/demand.rs | 57 +++++++++--------- compiler/rustc_hir_typeck/src/expr.rs | 11 ++-- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 4 +- compiler/rustc_hir_typeck/src/pat.rs | 68 +++++++++++----------- tests/crashes/124004.rs | 18 ------ tests/ui/pattern/box-pattern-type-mismatch.rs | 19 ++++++ tests/ui/pattern/box-pattern-type-mismatch.stderr | 19 ++++++ 8 files changed, 112 insertions(+), 94 deletions(-) delete mode 100644 tests/crashes/124004.rs create mode 100644 tests/ui/pattern/box-pattern-type-mismatch.rs create mode 100644 tests/ui/pattern/box-pattern-type-mismatch.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 821a9036654..808d8b78d2d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2888,7 +2888,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .. } = explanation { - if let Some(diag) = self.try_report_cannot_return_reference_to_local( + if let Err(diag) = self.try_report_cannot_return_reference_to_local( borrow, borrow_span, span, @@ -3075,7 +3075,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = explanation { - if let Some(diag) = self.try_report_cannot_return_reference_to_local( + if let Err(diag) = self.try_report_cannot_return_reference_to_local( borrow, proper_span, span, @@ -3237,11 +3237,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return_span: Span, category: ConstraintCategory<'tcx>, opt_place_desc: Option<&String>, - ) -> Option> { + ) -> Result<(), Diag<'tcx>> { let return_kind = match category { ConstraintCategory::Return(_) => "return", ConstraintCategory::Yield => "yield", - _ => return None, + _ => return Ok(()), }; // FIXME use a better heuristic than Spans @@ -3317,7 +3317,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - Some(err) + Err(err) } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index d2a5924c8bb..f9720c9c307 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -4,7 +4,7 @@ use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit::Visitor; -use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; +use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::bug; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -166,7 +166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Requires that the two types unify, and prints an error message if /// they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - if let Some(e) = self.demand_suptype_diag(sp, expected, actual) { + if let Err(e) = self.demand_suptype_diag(sp, expected, actual) { e.emit(); } } @@ -176,7 +176,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option> { + ) -> Result<(), Diag<'tcx>> { self.demand_suptype_with_origin(&self.misc(sp), expected, actual) } @@ -186,18 +186,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option> { - match self.at(cause, self.param_env).sup(DefineOpaqueTypes::Yes, expected, actual) { - Ok(InferOk { obligations, value: () }) => { - self.register_predicates(obligations); - None - } - Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)), - } + ) -> Result<(), Diag<'tcx>> { + self.at(cause, self.param_env) + .sup(DefineOpaqueTypes::Yes, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + .map_err(|e| self.err_ctxt().report_mismatched_types(cause, expected, actual, e)) } pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - if let Some(err) = self.demand_eqtype_diag(sp, expected, actual) { + if let Err(err) = self.demand_eqtype_diag(sp, expected, actual) { err.emit(); } } @@ -207,7 +204,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option> { + ) -> Result<(), Diag<'tcx>> { self.demand_eqtype_with_origin(&self.misc(sp), expected, actual) } @@ -216,14 +213,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option> { - match self.at(cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, actual) { - Ok(InferOk { obligations, value: () }) => { - self.register_predicates(obligations); - None - } - Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)), - } + ) -> Result<(), Diag<'tcx>> { + self.at(cause, self.param_env) + .eq(DefineOpaqueTypes::Yes, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + .map_err(|e| self.err_ctxt().report_mismatched_types(cause, expected, actual, e)) } pub fn demand_coerce( @@ -234,12 +228,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, ) -> Ty<'tcx> { - let (ty, err) = - self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase); - if let Some(err) = err { - err.emit(); + match self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase) + { + Ok(ty) => ty, + Err(err) => { + err.emit(); + // Return the original type instead of an error type here, otherwise the type of `x` in + // `let x: u32 = ();` will be a type error, causing all subsequent usages of `x` to not + // report errors, even though `x` is definitely `u32`. + expected + } } - ty } /// Checks that the type of `expr` can be coerced to `expected`. @@ -254,11 +253,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, - ) -> (Ty<'tcx>, Option>) { + ) -> Result, Diag<'tcx>> { let expected = self.resolve_vars_with_obligations(expected); let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) { - Ok(ty) => return (ty, None), + Ok(ty) => return Ok(ty), Err(e) => e, }; @@ -275,7 +274,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, Some(e)); - (expected, Some(err)) + Err(err) } /// Notes the point at which a variable is constrained to some type incompatible diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 5b27ebe3416..1f185a35000 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -87,7 +87,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty = adj_ty; } - if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { + if let Err(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { let _ = self.emit_type_mismatch_suggestions( &mut err, expr.peel_drop_temps(), @@ -1132,7 +1132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // say that the user intended to write `lhs == rhs` instead of `lhs = rhs`. // The likely cause of this is `if foo = bar { .. }`. let actual_ty = self.tcx.types.unit; - let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap(); + let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap_err(); let lhs_ty = self.check_expr(lhs); let rhs_ty = self.check_expr(rhs); let refs_can_coerce = |lhs: Ty<'tcx>, rhs: Ty<'tcx>| { @@ -1236,7 +1236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This is (basically) inlined `check_expr_coercible_to_type`, but we want // to suggest an additional fixup here in `suggest_deref_binop`. let rhs_ty = self.check_expr_with_hint(rhs, lhs_ty); - if let (_, Some(mut diag)) = + if let Err(mut diag) = self.demand_coerce_diag(rhs, rhs_ty, lhs_ty, Some(lhs), AllowTwoPhase::No) { suggest_deref_binop(&mut diag, rhs_ty); @@ -1741,10 +1741,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Make sure to give a type to the field even if there's // an error, so we can continue type-checking. let ty = self.check_expr_with_hint(field.expr, field_type); - let (_, diag) = - self.demand_coerce_diag(field.expr, ty, field_type, None, AllowTwoPhase::No); + let diag = self.demand_coerce_diag(field.expr, ty, field_type, None, AllowTwoPhase::No); - if let Some(diag) = diag { + if let Err(diag) = diag { if idx == hir_fields.len() - 1 { if remaining_fields.is_empty() { self.suggest_fru_from_range_and_emit(field, variant, args, diag); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index b8333d47493..0428ec56c99 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1578,7 +1578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type of the place it is referencing, and not some // supertype thereof. let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m)); - if let Some(mut diag) = self.demand_eqtype_diag(init.span, local_ty, init_ty) { + if let Err(mut diag) = self.demand_eqtype_diag(init.span, local_ty, init_ty) { self.emit_type_mismatch_suggestions( &mut diag, init.peel_drop_temps(), @@ -1624,7 +1624,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let previous_diverges = self.diverges.get(); let else_ty = self.check_block_with_expected(blk, NoExpectation); let cause = self.cause(blk.span, ObligationCauseCode::LetElse); - if let Some(err) = self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) + if let Err(err) = self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) { err.emit(); } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 814bdc07637..9d4ba1eb489 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -105,15 +105,16 @@ impl<'tcx> FnCtxt<'_, 'tcx> { expected: Ty<'tcx>, actual: Ty<'tcx>, ti: &TopInfo<'tcx>, - ) -> Option> { - let mut diag = - self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?; - if let Some(expr) = ti.origin_expr { - self.suggest_fn_call(&mut diag, expr, expected, |output| { - self.can_eq(self.param_env, output, actual) - }); - } - Some(diag) + ) -> Result<(), Diag<'tcx>> { + self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual) + .map_err(|mut diag| { + if let Some(expr) = ti.origin_expr { + self.suggest_fn_call(&mut diag, expr, expected, |output| { + self.can_eq(self.param_env, output, actual) + }); + } + diag + }) } fn demand_eqtype_pat( @@ -122,10 +123,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> { expected: Ty<'tcx>, actual: Ty<'tcx>, ti: &TopInfo<'tcx>, - ) { - if let Some(err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) { - err.emit(); - } + ) -> Result<(), ErrorGuaranteed> { + self.demand_eqtype_pat_diag(cause_span, expected, actual, ti).map_err(|err| err.emit()) } } @@ -509,7 +508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // then that's equivalent to there existing a LUB. let cause = self.pattern_cause(ti, span); - if let Some(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) { + if let Err(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) { err.emit_unless( ti.span .filter(|&s| { @@ -562,7 +561,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Subtyping doesn't matter here, as the value is some kind of scalar. let demand_eqtype = |x: &mut _, y| { if let Some((ref mut fail, x_ty, x_span)) = *x - && let Some(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) + && let Err(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) { if let Some((_, y_ty, y_span)) = y { self.endpoint_has_type(&mut err, y_span, y_ty); @@ -736,7 +735,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Otherwise, the type of x is the expected type `T`. ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1). }; - self.demand_eqtype_pat(pat.span, eq_ty, local_ty, ti); + + // We have a concrete type for the local, so we do not need to taint it and hide follow up errors *using* the local. + let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, ti); // If there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be. @@ -763,7 +764,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ti: &TopInfo<'tcx>, ) { let var_ty = self.local_ty(span, var_id); - if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { + if let Err(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { let hir = self.tcx.hir(); let var_ty = self.resolve_vars_if_possible(var_ty); let msg = format!("first introduced with type `{var_ty}` here"); @@ -986,7 +987,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Type-check the path. - self.demand_eqtype_pat(pat.span, expected, pat_ty, pat_info.top_info); + let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, pat_info.top_info); // Type-check subpatterns. if self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) { @@ -1050,7 +1051,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type-check the path. let (pat_ty, pat_res) = self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id); - if let Some(err) = + if let Err(err) = self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty) { self.emit_bad_pat_path(err, pat, res, pat_res, pat_ty, segments); @@ -1223,7 +1224,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type-check the tuple struct pattern against the expected type. let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, pat_info.top_info); - let had_err = diag.map(|diag| diag.emit()); + let had_err = diag.map_err(|diag| diag.emit()); // Type-check subpatterns. if subpats.len() == variant.fields.len() @@ -1244,7 +1245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, ); } - if let Some(e) = had_err { + if let Err(e) = had_err { on_error(e); return Ty::new_error(tcx, e); } @@ -1256,7 +1257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats, &variant.fields.raw, expected, - had_err.is_some(), + had_err.is_err(), ); on_error(e); return Ty::new_error(tcx, e); @@ -1444,8 +1445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span)); let element_tys = tcx.mk_type_list_from_iter(element_tys_iter); let pat_ty = Ty::new_tup(tcx, element_tys); - if let Some(err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, pat_info.top_info) { - let reported = err.emit(); + if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, pat_info.top_info) { // Walk subpatterns with an expected type of `err` in this case to silence // further errors being emitted when using the bindings. #50333 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported)); @@ -2064,20 +2064,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { let tcx = self.tcx; - let (box_ty, inner_ty) = match self.check_dereferenceable(span, expected, inner) { - Ok(()) => { + let (box_ty, inner_ty) = self + .check_dereferenceable(span, expected, inner) + .and_then(|()| { // Here, `demand::subtype` is good enough, but I don't // think any errors can be introduced by using `demand::eqtype`. let inner_ty = self.next_ty_var(inner.span); let box_ty = Ty::new_box(tcx, inner_ty); - self.demand_eqtype_pat(span, expected, box_ty, pat_info.top_info); - (box_ty, inner_ty) - } - Err(guar) => { + self.demand_eqtype_pat(span, expected, box_ty, pat_info.top_info)?; + Ok((box_ty, inner_ty)) + }) + .unwrap_or_else(|guar| { let err = Ty::new_error(tcx, guar); (err, err) - } - }; + }); self.check_pat(inner, inner_ty, pat_info); box_ty } @@ -2221,7 +2221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Look for a case like `fn foo(&foo: u32)` and suggest // `fn foo(foo: &u32)` - if let Some(mut err) = err { + if let Err(mut err) = err { self.borrow_pat_suggestion(&mut err, pat); err.emit(); } @@ -2326,7 +2326,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.try_resolve_slice_ty_to_array_ty(before, slice, span) { debug!(?resolved_arr_ty); - self.demand_eqtype(span, expected, resolved_arr_ty); + let _ = self.demand_eqtype(span, expected, resolved_arr_ty); } } diff --git a/tests/crashes/124004.rs b/tests/crashes/124004.rs deleted file mode 100644 index 1fcf0785945..00000000000 --- a/tests/crashes/124004.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ known-bug: #124004 - -#![feature(box_patterns)] - -use std::ops::{ Deref }; - -struct X(dyn Iterator); - -impl Deref for X { - type Target = isize; - - fn deref(&self) -> &isize { - let &X(box ref x) = self; - x - } -} - -fn main() {} diff --git a/tests/ui/pattern/box-pattern-type-mismatch.rs b/tests/ui/pattern/box-pattern-type-mismatch.rs new file mode 100644 index 00000000000..6c980503256 --- /dev/null +++ b/tests/ui/pattern/box-pattern-type-mismatch.rs @@ -0,0 +1,19 @@ +//! This test used to ICE #124004 + +#![feature(box_patterns)] + +use std::ops::{ Deref }; + +struct X(dyn Iterator); +//~^ ERROR: use of undeclared lifetime name `'a` + +impl Deref for X { + type Target = isize; + + fn deref(&self) -> &isize { + let &X(box ref x) = self; + x + } +} + +fn main() {} diff --git a/tests/ui/pattern/box-pattern-type-mismatch.stderr b/tests/ui/pattern/box-pattern-type-mismatch.stderr new file mode 100644 index 00000000000..14f7dbbd839 --- /dev/null +++ b/tests/ui/pattern/box-pattern-type-mismatch.stderr @@ -0,0 +1,19 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/box-pattern-type-mismatch.rs:7:31 + | +LL | struct X(dyn Iterator); + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | struct X(dyn for<'a> Iterator); + | +++++++ +help: consider introducing lifetime `'a` here + | +LL | struct X<'a>(dyn Iterator); + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0261`. -- cgit 1.4.1-3-g733a5 From ece3e3e4c146a94996b4c0f6141caf0a0a877084 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 12 Jun 2024 15:09:03 +0000 Subject: Replace some `Option` with `Result<(), Diag>` --- compiler/rustc_hir_typeck/src/pat.rs | 42 +++++++++++++++--------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 9d4ba1eb489..a6f05e9b406 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -990,10 +990,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, pat_info.top_info); // Type-check subpatterns. - if self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) { - pat_ty - } else { - Ty::new_misc_error(self.tcx) + match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) { + Ok(()) => pat_ty, + Err(guar) => Ty::new_error(self.tcx, guar), } } @@ -1469,7 +1468,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, pat_info: PatInfo<'tcx, '_>, - ) -> bool { + ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx; let ty::Adt(adt, args) = adt_ty.kind() else { @@ -1485,7 +1484,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Keep track of which fields have already appeared in the pattern. let mut used_fields = FxHashMap::default(); - let mut no_field_errors = true; + let mut result = Ok(()); let mut inexistent_fields = vec![]; // Typecheck each field. @@ -1494,8 +1493,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ident = tcx.adjust_ident(field.ident, variant.def_id); let field_ty = match used_fields.entry(ident) { Occupied(occupied) => { - no_field_errors = false; let guar = self.error_field_already_bound(span, field.ident, *occupied.get()); + result = Err(guar); Ty::new_error(tcx, guar) } Vacant(vacant) => { @@ -1510,7 +1509,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .unwrap_or_else(|| { inexistent_fields.push(field); - no_field_errors = false; Ty::new_misc_error(tcx) }) } @@ -1589,32 +1587,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `Foo { a, b }` when it should have been `Foo(a, b)`. i.delay_as_bug(); u.delay_as_bug(); - e.emit(); + Err(e.emit()) } else { i.emit(); - u.emit(); + Err(u.emit()) } } (None, Some(u)) => { if let Some(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { u.delay_as_bug(); - e.emit(); + Err(e.emit()) } else { - u.emit(); + Err(u.emit()) } } - (Some(err), None) => { - err.emit(); + (Some(err), None) => Err(err.emit()), + (None, None) => { + self.error_tuple_variant_index_shorthand(variant, pat, fields)?; + result } - (None, None) - if let Some(err) = - self.error_tuple_variant_index_shorthand(variant, pat, fields) => - { - err.emit(); - } - (None, None) => {} } - no_field_errors } fn error_tuple_variant_index_shorthand( @@ -1622,7 +1614,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant: &VariantDef, pat: &'_ Pat<'_>, fields: &[hir::PatField<'_>], - ) -> Option> { + ) -> Result<(), ErrorGuaranteed> { // if this is a tuple struct, then all field names will be numbers // so if any fields in a struct pattern use shorthand syntax, they will // be invalid identifiers (for example, Foo { 0, 1 }). @@ -1644,10 +1636,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)), Applicability::MaybeIncorrect, ); - return Some(err); + return Err(err.emit()); } } - None + Ok(()) } fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) { -- cgit 1.4.1-3-g733a5 From e8d6170b8a6e70901b63ec967e37595949ecb66c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 12 Jun 2024 15:11:49 +0000 Subject: Replace some `Option` with `Result<(), Diag>` --- compiler/rustc_hir_typeck/src/pat.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index a6f05e9b406..898d90b9f45 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1582,21 +1582,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } match (inexistent_fields_err, unmentioned_err) { (Some(i), Some(u)) => { - if let Some(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { + if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { // We don't want to show the nonexistent fields error when this was // `Foo { a, b }` when it should have been `Foo(a, b)`. i.delay_as_bug(); u.delay_as_bug(); - Err(e.emit()) + Err(e) } else { i.emit(); Err(u.emit()) } } (None, Some(u)) => { - if let Some(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { + if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { u.delay_as_bug(); - Err(e.emit()) + Err(e) } else { Err(u.emit()) } @@ -1795,14 +1795,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &Pat<'_>, fields: &'tcx [hir::PatField<'tcx>], variant: &ty::VariantDef, - ) -> Option> { + ) -> Result<(), ErrorGuaranteed> { if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) = (variant.ctor_kind(), &pat.kind) { let is_tuple_struct_match = !pattern_fields.is_empty() && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number); if is_tuple_struct_match { - return None; + return Ok(()); } let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath); @@ -1830,9 +1830,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("({sugg})"), appl, ); - return Some(err); + return Err(err.emit()); } - None + Ok(()) } fn get_suggested_tuple_struct_pattern( -- cgit 1.4.1-3-g733a5 From 7566307edc3b1e08b5bf08a664243fc4889e55c3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 12 Jun 2024 15:19:57 +0000 Subject: Replace a `bool` with a `Result<(), ErrorGuaranteed>` --- compiler/rustc_hir_typeck/src/pat.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 898d90b9f45..220556fe256 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1256,7 +1256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats, &variant.fields.raw, expected, - had_err.is_err(), + had_err, ); on_error(e); return Ty::new_error(tcx, e); @@ -1272,7 +1272,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats: &'tcx [Pat<'tcx>], fields: &'tcx [ty::FieldDef], expected: Ty<'tcx>, - had_err: bool, + had_err: Result<(), ErrorGuaranteed>, ) -> ErrorGuaranteed { let subpats_ending = pluralize!(subpats.len()); let fields_ending = pluralize!(fields.len()); @@ -1329,7 +1329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // #67037: only do this if we could successfully type-check the expected type against // the tuple struct pattern. Otherwise the args could get out of range on e.g., // `let P() = U;` where `P != U` with `struct P(T);`. - (ty::Adt(_, args), [field], false) => { + (ty::Adt(_, args), [field], Ok(())) => { let field_ty = self.field_ty(pat_span, field, args); match field_ty.kind() { ty::Tuple(fields) => fields.len() == subpats.len(), -- cgit 1.4.1-3-g733a5 From d87ec03ed9798dd62d733e671128dae819cbfbd1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Jun 2024 08:59:08 +0200 Subject: interpret: update doc comment for find_closest_untracked_caller_location --- compiler/rustc_const_eval/src/interpret/eval_context.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index e28cc05cc2a..c0d069ac09f 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -250,7 +250,7 @@ impl<'tcx, Prov: Provenance> Frame<'tcx, Prov> { impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> { /// Get the current location within the Frame. /// - /// If this is `Left`, we are not currently executing any particular statement in + /// If this is `Right`, we are not currently executing any particular statement in /// this frame (can happen e.g. during frame initialization, and during unwinding on /// frames without cleanup code). /// @@ -500,6 +500,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } + /// Returns the span of the currently executed statement/terminator. + /// This is the span typically used for error reporting. #[inline(always)] pub fn cur_span(&self) -> Span { // This deliberately does *not* honor `requires_caller_location` since it is used for much @@ -507,8 +509,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.stack().last().map_or(self.tcx.span, |f| f.current_span()) } + /// Find the first stack frame that is within the current crate, if any; + /// otherwise return the crate's HirId. #[inline(always)] - /// Find the first stack frame that is within the current crate, if any, otherwise return the crate's HirId pub fn best_lint_scope(&self) -> hir::HirId { self.stack() .iter() @@ -632,7 +635,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a - /// frame which is not `#[track_caller]`. This is the fancy version of `cur_span`. + /// frame which is not `#[track_caller]`. This matches the `caller_location` intrinsic, + /// and is primarily intended for the panic machinery. pub(crate) fn find_closest_untracked_caller_location(&self) -> Span { for frame in self.stack().iter().rev() { debug!("find_closest_untracked_caller_location: checking frame {:?}", frame.instance); -- cgit 1.4.1-3-g733a5 From 898b541cb6b6dcac2f2a45fb5f24de596851deb7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Jun 2024 10:09:51 +0200 Subject: add tracking issue for is_none_or --- library/core/src/option.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 403fe4ff04c..4d6ba2fa3b3 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -672,7 +672,7 @@ impl Option { /// ``` #[must_use] #[inline] - #[unstable(feature = "is_none_or", issue = "none")] + #[unstable(feature = "is_none_or", issue = "126383")] pub fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool { match self { None => true, -- cgit 1.4.1-3-g733a5 From 523408e6613dfb2eb5926350cd377f2198c3d9b4 Mon Sep 17 00:00:00 2001 From: Christiaan Biesterbosch Date: Thu, 13 Jun 2024 11:46:42 +0200 Subject: Fix wording in {checked_}next_power_of_two --- library/core/src/num/nonzero.rs | 2 +- library/core/src/num/uint_macros.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 863f0d61df3..5956a08593a 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1059,7 +1059,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { unsafe { Self::new_unchecked(self.get().unchecked_add(other)) } } - /// Returns the smallest power of two greater than or equal to n. + /// Returns the smallest power of two greater than or equal to `self`. /// Checks for overflow and returns [`None`] /// if the next power of two is greater than the type’s maximum value. /// As a consequence, the result cannot wrap to zero. diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 1491c27372b..cdbd695008e 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2830,7 +2830,7 @@ macro_rules! uint_impl { /// /// When return value overflows (i.e., `self > (1 << (N-1))` for type /// `uN`), it panics in debug mode and the return value is wrapped to 0 in - /// release mode (the only situation in which method can return 0). + /// release mode (the only situation in which this method can return 0). /// /// # Examples /// @@ -2851,7 +2851,7 @@ macro_rules! uint_impl { self.one_less_than_next_power_of_two() + 1 } - /// Returns the smallest power of two greater than or equal to `n`. If + /// Returns the smallest power of two greater than or equal to `self`. If /// the next power of two is greater than the type's maximum value, /// `None` is returned, otherwise the power of two is wrapped in `Some`. /// -- cgit 1.4.1-3-g733a5 From b28221e74f5f05d0f7a6212f99c9d5af868c0ed3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 15 Apr 2024 11:10:50 +0000 Subject: Use diagnostic method for diagnostics --- compiler/rustc_hir_typeck/src/callee.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 9736c8b8920..93222c18686 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -628,7 +628,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; - let pick = self.confirm_method( + let pick = self.confirm_method_for_diagnostic( call_expr.span, callee_expr, call_expr, -- cgit 1.4.1-3-g733a5 From 10c76433e8b06878fffe77eb8864aecaf587c3b6 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Jun 2024 12:13:54 +0200 Subject: Small style improvement in `gvn.rs` --- compiler/rustc_mir_transform/src/gvn.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 121a3b99a39..0f8f28e3462 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -330,8 +330,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let is_sized = !self.feature_unsized_locals || self.local_decls[local].ty.is_sized(self.tcx, self.param_env); if is_sized { - self.rev_locals.ensure_contains_elem(value, SmallVec::new); - self.rev_locals[value].push(local); + self.rev_locals.ensure_contains_elem(value, SmallVec::new).push(local); } } -- cgit 1.4.1-3-g733a5 From 614966b0c3caf7558b7ea58c09c4cf17f2497b98 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 13 Jun 2024 12:24:14 +0200 Subject: Bump Clippy version -> 0.1.81 --- Cargo.toml | 2 +- clippy_config/Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- clippy_utils/Cargo.toml | 2 +- declare_clippy_lint/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b48f3ab3919..43788499055 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.80" +version = "0.1.81" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index 7f7dc9d6cfb..be0b048ac0c 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_config" -version = "0.1.80" +version = "0.1.81" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 5e3a119337c..5708ffba08f 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.80" +version = "0.1.81" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index ab883c25338..3a3aeb88216 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.80" +version = "0.1.81" edition = "2021" publish = false diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml index c8c734c3a7c..86d945c14a5 100644 --- a/declare_clippy_lint/Cargo.toml +++ b/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.80" +version = "0.1.81" edition = "2021" publish = false -- cgit 1.4.1-3-g733a5 From 89658ef8203328cf766bb34a6fa38a23143e4137 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 13 Jun 2024 12:24:17 +0200 Subject: Bump nightly version -> 2024-06-13 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index dd8b9ece773..842c2f3de0d 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-05-30" +channel = "nightly-2024-06-13" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] -- cgit 1.4.1-3-g733a5 From 83f8f9f85d6f16fde4ab0d181caa9e9f49d257a3 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sun, 19 May 2024 20:51:38 +0200 Subject: Implement lint for obligations broken by never type fallback change --- compiler/rustc_hir_typeck/messages.ftl | 3 ++ compiler/rustc_hir_typeck/src/errors.rs | 5 ++ compiler/rustc_hir_typeck/src/fallback.rs | 50 ++++++++++++++++++- compiler/rustc_lint_defs/src/builtin.rs | 57 ++++++++++++++++++++++ .../defaulted-never-note.fallback.stderr | 2 +- .../defaulted-never-note.nofallback.stderr | 13 +++++ tests/ui/never_type/defaulted-never-note.rs | 2 + .../never_type/dependency-on-fallback-to-unit.rs | 28 +++++++++++ .../dependency-on-fallback-to-unit.stderr | 23 +++++++++ ...verging-fallback-control-flow.nofallback.stderr | 23 +++++++++ .../never_type/diverging-fallback-control-flow.rs | 4 ++ .../diverging-fallback-no-leak.fallback.stderr | 2 +- .../diverging-fallback-no-leak.nofallback.stderr | 13 +++++ tests/ui/never_type/diverging-fallback-no-leak.rs | 3 ++ ...fallback-unconstrained-return.nofallback.stderr | 13 +++++ .../diverging-fallback-unconstrained-return.rs | 3 ++ .../fallback-closure-ret.nofallback.stderr | 13 +++++ tests/ui/never_type/fallback-closure-ret.rs | 8 +-- tests/ui/never_type/impl_trait_fallback.rs | 2 + tests/ui/never_type/impl_trait_fallback.stderr | 13 +++++ 20 files changed, 274 insertions(+), 6 deletions(-) create mode 100644 tests/ui/never_type/defaulted-never-note.nofallback.stderr create mode 100644 tests/ui/never_type/dependency-on-fallback-to-unit.rs create mode 100644 tests/ui/never_type/dependency-on-fallback-to-unit.stderr create mode 100644 tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr create mode 100644 tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr create mode 100644 tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr create mode 100644 tests/ui/never_type/fallback-closure-ret.nofallback.stderr create mode 100644 tests/ui/never_type/impl_trait_fallback.stderr diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 6f499947d5c..3ab319a037b 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -44,6 +44,9 @@ hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to ` hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private +hir_typeck_dependency_on_unit_never_type_fallback = this function depends on never type fallback being `()` + .help = specify the types explicitly + hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty` hir_typeck_expected_default_return_type = expected `()` because of default return type diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 3f12f252654..6dd34024fd1 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -183,6 +183,11 @@ pub enum NeverTypeFallbackFlowingIntoUnsafe { Deref, } +#[derive(LintDiagnostic)] +#[help] +#[diag(hir_typeck_dependency_on_unit_never_type_fallback)] +pub struct DependencyOnUnitNeverTypeFallback {} + #[derive(Subdiagnostic)] #[multipart_suggestion( hir_typeck_add_missing_parentheses_in_range, diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 5ba67c52ef2..06c5adae99e 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -8,12 +8,17 @@ use rustc_data_structures::{ use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_hir::HirId; -use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::bug; +use rustc_infer::{ + infer::{DefineOpaqueTypes, InferOk}, + traits::ObligationCause, +}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; use rustc_session::lint; use rustc_span::DUMMY_SP; use rustc_span::{def_id::LocalDefId, Span}; +use rustc_trait_selection::traits::ObligationCtxt; +use rustc_type_ir::TyVid; #[derive(Copy, Clone)] pub enum DivergingFallbackBehavior { @@ -344,6 +349,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // `!`. let mut diverging_fallback = UnordMap::with_capacity(diverging_vids.len()); let unsafe_infer_vars = OnceCell::new(); + + self.lint_obligations_broken_by_never_type_fallback_change(behavior, &diverging_vids); + for &diverging_vid in &diverging_vids { let diverging_ty = Ty::new_var(self.tcx, diverging_vid); let root_vid = self.root_var(diverging_vid); @@ -468,6 +476,46 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } } + fn lint_obligations_broken_by_never_type_fallback_change( + &self, + behavior: DivergingFallbackBehavior, + diverging_vids: &[TyVid], + ) { + let DivergingFallbackBehavior::FallbackToUnit = behavior else { return }; + + // Returns errors which happen if fallback is set to `fallback` + let try_out = |fallback| { + self.probe(|_| { + let obligations = self.fulfillment_cx.borrow().pending_obligations(); + let ocx = ObligationCtxt::new(&self.infcx); + ocx.register_obligations(obligations.iter().cloned()); + + for &diverging_vid in diverging_vids { + let diverging_ty = Ty::new_var(self.tcx, diverging_vid); + + _ = ocx.eq(&ObligationCause::dummy(), self.param_env, diverging_ty, fallback); + } + + ocx.select_where_possible() + }) + }; + + // If we have no errors with `fallback = ()`, but *do* have errors with `fallback = !`, + // then this code will be broken by the never type fallback change.qba + let unit_errors = try_out(self.tcx.types.unit); + if unit_errors.is_empty() + && let never_errors = try_out(self.tcx.types.never) + && !never_errors.is_empty() + { + self.tcx.emit_node_span_lint( + lint::builtin::DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, + self.tcx.local_def_id_to_hir_id(self.body_id), + self.tcx.def_span(self.body_id), + errors::DependencyOnUnitNeverTypeFallback {}, + ) + } + } + /// Returns a graph whose nodes are (unresolved) inference variables and where /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`. fn create_coercion_graph(&self) -> VecGraph { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 45051394ffc..e6895fbfd09 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -34,6 +34,7 @@ declare_lint_pass! { CONST_EVALUATABLE_UNCHECKED, CONST_ITEM_MUTATION, DEAD_CODE, + DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, DEPRECATED, DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DEPRECATED_IN_FUTURE, @@ -4199,6 +4200,62 @@ declare_lint! { report_in_external_macro } +declare_lint! { + /// The `dependency_on_unit_never_type_fallback` lint detects cases where code compiles with + /// [never type fallback] being [`()`], but will stop compiling with fallback being [`!`]. + /// + /// [never type fallback]: prim@never#never-type-fallback + /// [`()`]: prim@unit + /// [`!`]: + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(dependency_on_unit_never_type_fallback)] + /// fn main() { + /// if true { + /// // return has type `!` which, is some cases, causes never type fallback + /// return + /// } else { + /// // the type produced by this call is not specified explicitly, + /// // so it will be inferred from the previous branch + /// Default::default() + /// }; + /// // depending on the fallback, this may compile (because `()` implements `Default`), + /// // or it may not (because `!` does not implement `Default`) + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Due to historic reasons never type fallback was `()`, meaning that `!` got spontaneously + /// coerced to `()`. There are plans to change that, but they may make the code such as above + /// not compile. Instead of depending on the fallback, you should specify the type explicitly: + /// ``` + /// if true { + /// return + /// } else { + /// // type is explicitly specified, fallback can't hurt us no more + /// <() as Default>::default() + /// }; + /// ``` + /// + /// See [Tracking Issue for making `!` fall back to `!`](https://github.com/rust-lang/rust/issues/123748). + /// + /// [`!`]: https://doc.rust-lang.org/core/primitive.never.html + /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html + pub DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, + Warn, + "never type fallback affecting unsafe function calls", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reference: "issue #123748 ", + }; + report_in_external_macro +} + declare_lint! { /// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field /// (`[u8]`) or string slice field (`str`) is used in a `packed` struct that derives one or diff --git a/tests/ui/never_type/defaulted-never-note.fallback.stderr b/tests/ui/never_type/defaulted-never-note.fallback.stderr index 92fa9068cfd..fe9a924f64a 100644 --- a/tests/ui/never_type/defaulted-never-note.fallback.stderr +++ b/tests/ui/never_type/defaulted-never-note.fallback.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `!: ImplementedForUnitButNotNever` is not satisfied - --> $DIR/defaulted-never-note.rs:30:9 + --> $DIR/defaulted-never-note.rs:32:9 | LL | foo(_x); | --- ^^ the trait `ImplementedForUnitButNotNever` is not implemented for `!` diff --git a/tests/ui/never_type/defaulted-never-note.nofallback.stderr b/tests/ui/never_type/defaulted-never-note.nofallback.stderr new file mode 100644 index 00000000000..b69b8dda8f1 --- /dev/null +++ b/tests/ui/never_type/defaulted-never-note.nofallback.stderr @@ -0,0 +1,13 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/defaulted-never-note.rs:28:1 + | +LL | fn smeg() { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/never_type/defaulted-never-note.rs b/tests/ui/never_type/defaulted-never-note.rs index f4e5273b33a..40861e73b39 100644 --- a/tests/ui/never_type/defaulted-never-note.rs +++ b/tests/ui/never_type/defaulted-never-note.rs @@ -26,6 +26,8 @@ fn foo(_t: T) {} //[fallback]~^ NOTE required by this bound in `foo` //[fallback]~| NOTE required by a bound in `foo` fn smeg() { + //[nofallback]~^ warn: this function depends on never type fallback being `()` + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! let _x = return; foo(_x); //[fallback]~^ ERROR the trait bound diff --git a/tests/ui/never_type/dependency-on-fallback-to-unit.rs b/tests/ui/never_type/dependency-on-fallback-to-unit.rs new file mode 100644 index 00000000000..5448d0be2c6 --- /dev/null +++ b/tests/ui/never_type/dependency-on-fallback-to-unit.rs @@ -0,0 +1,28 @@ +//@ check-pass + +fn main() { + def(); + _ = question_mark(); +} + +fn def() { + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + match true { + false => <_>::default(), + true => return, + }; +} + +// +// +fn question_mark() -> Result<(), ()> { + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + deserialize()?; + Ok(()) +} + +fn deserialize() -> Result { + Ok(T::default()) +} diff --git a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr new file mode 100644 index 00000000000..36c82b6d1bf --- /dev/null +++ b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr @@ -0,0 +1,23 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/dependency-on-fallback-to-unit.rs:8:1 + | +LL | fn def() { + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: this function depends on never type fallback being `()` + --> $DIR/dependency-on-fallback-to-unit.rs:19:1 + | +LL | fn question_mark() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly + +warning: 2 warnings emitted + diff --git a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr new file mode 100644 index 00000000000..5fbdc04ed3b --- /dev/null +++ b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr @@ -0,0 +1,23 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-control-flow.rs:30:1 + | +LL | fn assignment() { + | ^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-control-flow.rs:42:1 + | +LL | fn assignment_rev() { + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly + +warning: 2 warnings emitted + diff --git a/tests/ui/never_type/diverging-fallback-control-flow.rs b/tests/ui/never_type/diverging-fallback-control-flow.rs index e209a990885..575e2e9273c 100644 --- a/tests/ui/never_type/diverging-fallback-control-flow.rs +++ b/tests/ui/never_type/diverging-fallback-control-flow.rs @@ -28,6 +28,8 @@ impl UnitDefault for () { } fn assignment() { + //[nofallback]~^ warn: this function depends on never type fallback being `()` + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! let x; if true { @@ -38,6 +40,8 @@ fn assignment() { } fn assignment_rev() { + //[nofallback]~^ warn: this function depends on never type fallback being `()` + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! let x; if true { diff --git a/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr index 01abf2e17f1..c5463814475 100644 --- a/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr +++ b/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `!: Test` is not satisfied - --> $DIR/diverging-fallback-no-leak.rs:17:23 + --> $DIR/diverging-fallback-no-leak.rs:20:23 | LL | unconstrained_arg(return); | ----------------- ^^^^^^ the trait `Test` is not implemented for `!` diff --git a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr new file mode 100644 index 00000000000..d11097323b3 --- /dev/null +++ b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr @@ -0,0 +1,13 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-no-leak.rs:14:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/never_type/diverging-fallback-no-leak.rs b/tests/ui/never_type/diverging-fallback-no-leak.rs index 425437da207..c6d59c7f273 100644 --- a/tests/ui/never_type/diverging-fallback-no-leak.rs +++ b/tests/ui/never_type/diverging-fallback-no-leak.rs @@ -12,6 +12,9 @@ impl Test for () {} fn unconstrained_arg(_: T) {} fn main() { + //[nofallback]~^ warn: this function depends on never type fallback being `()` + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + // Here the type variable falls back to `!`, // and hence we get a type error. unconstrained_arg(return); diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr new file mode 100644 index 00000000000..750bcfb7f89 --- /dev/null +++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr @@ -0,0 +1,13 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-unconstrained-return.rs:28:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.rs b/tests/ui/never_type/diverging-fallback-unconstrained-return.rs index aeb6ee6e26e..927991db513 100644 --- a/tests/ui/never_type/diverging-fallback-unconstrained-return.rs +++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.rs @@ -26,6 +26,9 @@ fn unconstrained_return() -> T { } fn main() { + //[nofallback]~^ warn: this function depends on never type fallback being `()` + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + // In Ye Olde Days, the `T` parameter of `unconstrained_return` // winds up "entangled" with the `!` type that results from // `panic!`, and hence falls back to `()`. This is kind of unfortunate diff --git a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr new file mode 100644 index 00000000000..9f0b9f6daea --- /dev/null +++ b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr @@ -0,0 +1,13 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/fallback-closure-ret.rs:21:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/never_type/fallback-closure-ret.rs b/tests/ui/never_type/fallback-closure-ret.rs index dcf38e03a13..30f9ac54d0b 100644 --- a/tests/ui/never_type/fallback-closure-ret.rs +++ b/tests/ui/never_type/fallback-closure-ret.rs @@ -12,12 +12,14 @@ #![cfg_attr(fallback, feature(never_type_fallback))] -trait Bar { } -impl Bar for () { } -impl Bar for u32 { } +trait Bar {} +impl Bar for () {} +impl Bar for u32 {} fn foo(_: impl Fn() -> R) {} fn main() { + //[nofallback]~^ warn: this function depends on never type fallback being `()` + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! foo(|| panic!()); } diff --git a/tests/ui/never_type/impl_trait_fallback.rs b/tests/ui/never_type/impl_trait_fallback.rs index ce06f8f7817..fbe13dbe2ac 100644 --- a/tests/ui/never_type/impl_trait_fallback.rs +++ b/tests/ui/never_type/impl_trait_fallback.rs @@ -6,5 +6,7 @@ trait T {} impl T for () {} fn should_ret_unit() -> impl T { + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! panic!() } diff --git a/tests/ui/never_type/impl_trait_fallback.stderr b/tests/ui/never_type/impl_trait_fallback.stderr new file mode 100644 index 00000000000..87638940332 --- /dev/null +++ b/tests/ui/never_type/impl_trait_fallback.stderr @@ -0,0 +1,13 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/impl_trait_fallback.rs:8:1 + | +LL | fn should_ret_unit() -> impl T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: 1 warning emitted + -- cgit 1.4.1-3-g733a5 From b88d03b05966ed49a8da5bd26c7fa0a9af35459d Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 20 May 2024 04:07:38 +0200 Subject: Add a fast exit to `lint_obligations_broken_by_never_type_fallback_change` --- compiler/rustc_hir_typeck/src/fallback.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 06c5adae99e..56c962fb681 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -8,11 +8,11 @@ use rustc_data_structures::{ use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_hir::HirId; -use rustc_middle::bug; use rustc_infer::{ infer::{DefineOpaqueTypes, InferOk}, traits::ObligationCause, }; +use rustc_middle::bug; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; use rustc_session::lint; use rustc_span::DUMMY_SP; @@ -483,6 +483,11 @@ impl<'tcx> FnCtxt<'_, 'tcx> { ) { let DivergingFallbackBehavior::FallbackToUnit = behavior else { return }; + // Fallback happens if and only if there are diverging variables + if diverging_vids.is_empty() { + return; + } + // Returns errors which happen if fallback is set to `fallback` let try_out = |fallback| { self.probe(|_| { -- cgit 1.4.1-3-g733a5 From 0f41d26f419dc7cdaa01941604faf188123d3ea0 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 20 May 2024 04:19:22 +0200 Subject: Apply review nits --- compiler/rustc_hir_typeck/src/fallback.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 56c962fb681..dbc329a12bf 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -8,17 +8,13 @@ use rustc_data_structures::{ use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_hir::HirId; -use rustc_infer::{ - infer::{DefineOpaqueTypes, InferOk}, - traits::ObligationCause, -}; +use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::bug; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; use rustc_session::lint; use rustc_span::DUMMY_SP; use rustc_span::{def_id::LocalDefId, Span}; -use rustc_trait_selection::traits::ObligationCtxt; -use rustc_type_ir::TyVid; +use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; #[derive(Copy, Clone)] pub enum DivergingFallbackBehavior { @@ -479,7 +475,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { fn lint_obligations_broken_by_never_type_fallback_change( &self, behavior: DivergingFallbackBehavior, - diverging_vids: &[TyVid], + diverging_vids: &[ty::TyVid], ) { let DivergingFallbackBehavior::FallbackToUnit = behavior else { return }; @@ -489,7 +485,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } // Returns errors which happen if fallback is set to `fallback` - let try_out = |fallback| { + let remaining_errors_if_fallback_to = |fallback| { self.probe(|_| { let obligations = self.fulfillment_cx.borrow().pending_obligations(); let ocx = ObligationCtxt::new(&self.infcx); @@ -498,7 +494,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> { for &diverging_vid in diverging_vids { let diverging_ty = Ty::new_var(self.tcx, diverging_vid); - _ = ocx.eq(&ObligationCause::dummy(), self.param_env, diverging_ty, fallback); + ocx.eq(&ObligationCause::dummy(), self.param_env, diverging_ty, fallback) + .expect("expected diverging var to be unconstrained"); } ocx.select_where_possible() @@ -507,9 +504,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // If we have no errors with `fallback = ()`, but *do* have errors with `fallback = !`, // then this code will be broken by the never type fallback change.qba - let unit_errors = try_out(self.tcx.types.unit); + let unit_errors = remaining_errors_if_fallback_to(self.tcx.types.unit); if unit_errors.is_empty() - && let never_errors = try_out(self.tcx.types.never) + && let never_errors = remaining_errors_if_fallback_to(self.tcx.types.never) && !never_errors.is_empty() { self.tcx.emit_node_span_lint( -- cgit 1.4.1-3-g733a5 From 268b55639344f783c722cc6e605a3d04cddaab2d Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 20 May 2024 04:24:23 +0200 Subject: Bless a test --- tests/ui/delegation/not-supported.rs | 4 +++ tests/ui/delegation/not-supported.stderr | 51 ++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs index 5f78de97638..25d7a4cb895 100644 --- a/tests/ui/delegation/not-supported.rs +++ b/tests/ui/delegation/not-supported.rs @@ -70,12 +70,16 @@ mod opaque { pub fn opaque_arg(_: impl Trait) -> i32 { 0 } pub fn opaque_ret() -> impl Trait { unimplemented!() } + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } reuse to_reuse::opaque_arg; //~^ ERROR delegation with early bound generics is not supported yet trait ToReuse { fn opaque_ret() -> impl Trait { unimplemented!() } + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls. diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr index e2cb04f977b..339a8418b33 100644 --- a/tests/ui/delegation/not-supported.stderr +++ b/tests/ui/delegation/not-supported.stderr @@ -107,7 +107,7 @@ LL | reuse Trait::foo2 { &self.0 } | ^^^^ error: delegation with early bound generics is not supported yet - --> $DIR/not-supported.rs:74:21 + --> $DIR/not-supported.rs:76:21 | LL | pub fn opaque_arg(_: impl Trait) -> i32 { 0 } | --------------------------------------- callee defined here @@ -115,46 +115,67 @@ LL | pub fn opaque_arg(_: impl Trait) -> i32 { 0 } LL | reuse to_reuse::opaque_arg; | ^^^^^^^^^^ -error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` - --> $DIR/not-supported.rs:83:25 +warning: this function depends on never type fallback being `()` + --> $DIR/not-supported.rs:80:9 + | +LL | fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/not-supported.rs:87:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/not-supported.rs:83:25 + --> $DIR/not-supported.rs:87:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle -note: cycle used when checking that `opaque::` is well-formed - --> $DIR/not-supported.rs:82:5 + = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::` is well-formed + --> $DIR/not-supported.rs:86:5 | LL | impl ToReuse for u8 { | ^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` - --> $DIR/not-supported.rs:86:24 +warning: this function depends on never type fallback being `()` + --> $DIR/not-supported.rs:72:9 + | +LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly + +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/not-supported.rs:90:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/not-supported.rs:86:24 + --> $DIR/not-supported.rs:90:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle -note: cycle used when checking that `opaque::` is well-formed - --> $DIR/not-supported.rs:85:5 + = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::` is well-formed + --> $DIR/not-supported.rs:89:5 | LL | impl ToReuse for u16 { | ^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: recursive delegation is not supported yet - --> $DIR/not-supported.rs:99:22 + --> $DIR/not-supported.rs:103:22 | LL | pub reuse to_reuse2::foo; | --- callee defined here @@ -162,7 +183,7 @@ LL | pub reuse to_reuse2::foo; LL | reuse to_reuse1::foo; | ^^^ -error: aborting due to 16 previous errors +error: aborting due to 16 previous errors; 2 warnings emitted Some errors have detailed explanations: E0049, E0195, E0391. For more information about an error, try `rustc --explain E0049`. -- cgit 1.4.1-3-g733a5 From a22f8aa17abcd2f0dfb83aa8ee41509f922be6ab Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 23 May 2024 18:02:13 +0200 Subject: Fixup clippy tests Don't depend on the fact that `!` falls back to `()` and so panic-ish things can be used in `-> impl ImplementedForUnit` functions --- src/tools/clippy/tests/ui/new_ret_no_self.rs | 5 +---- src/tools/clippy/tests/ui/new_ret_no_self.stderr | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.rs b/src/tools/clippy/tests/ui/new_ret_no_self.rs index b944f531ef6..175b14d815a 100644 --- a/src/tools/clippy/tests/ui/new_ret_no_self.rs +++ b/src/tools/clippy/tests/ui/new_ret_no_self.rs @@ -390,9 +390,7 @@ mod issue7344 { impl RetImplTraitSelf2 { // should not trigger lint - fn new(t: T) -> impl Trait2<(), Self> { - unimplemented!() - } + fn new(t: T) -> impl Trait2<(), Self> {} } struct RetImplTraitNoSelf2(T); @@ -401,7 +399,6 @@ mod issue7344 { // should trigger lint fn new(t: T) -> impl Trait2<(), i32> { //~^ ERROR: methods called `new` usually return `Self` - unimplemented!() } } diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.stderr b/src/tools/clippy/tests/ui/new_ret_no_self.stderr index d440a9f45fc..3597ad65838 100644 --- a/src/tools/clippy/tests/ui/new_ret_no_self.stderr +++ b/src/tools/clippy/tests/ui/new_ret_no_self.stderr @@ -96,11 +96,10 @@ LL | | } | |_________^ error: methods called `new` usually return `Self` - --> tests/ui/new_ret_no_self.rs:402:9 + --> tests/ui/new_ret_no_self.rs:400:9 | LL | / fn new(t: T) -> impl Trait2<(), i32> { LL | | -LL | | unimplemented!() LL | | } | |_________^ -- cgit 1.4.1-3-g733a5 From 8400cd0b34bff8f013cd00064fc650fef652fc1d Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 23 May 2024 01:02:37 +0200 Subject: Fixup links in lint docs looks like prim@ stuff does not work here (is it possibly not handled by rustdoc at all?) --- compiler/rustc_lint_defs/src/builtin.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index e6895fbfd09..a12c76037e7 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4204,9 +4204,9 @@ declare_lint! { /// The `dependency_on_unit_never_type_fallback` lint detects cases where code compiles with /// [never type fallback] being [`()`], but will stop compiling with fallback being [`!`]. /// - /// [never type fallback]: prim@never#never-type-fallback - /// [`()`]: prim@unit - /// [`!`]: + /// [never type fallback]: https://doc.rust-lang.org/nightly/core/primitive.never.html#never-type-fallback + /// [`!`]: https://doc.rust-lang.org/core/primitive.never.html + /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html /// /// ### Example /// @@ -4243,9 +4243,6 @@ declare_lint! { /// ``` /// /// See [Tracking Issue for making `!` fall back to `!`](https://github.com/rust-lang/rust/issues/123748). - /// - /// [`!`]: https://doc.rust-lang.org/core/primitive.never.html - /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html pub DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, Warn, "never type fallback affecting unsafe function calls", -- cgit 1.4.1-3-g733a5 From 17d28564a8308ed71dee23f0694c0e5dc41d9ce9 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 13 Jun 2024 12:31:02 +0200 Subject: Update Cargo.lock --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5ea9fee8a6..10d42d290c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -628,7 +628,7 @@ checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "clippy" -version = "0.1.80" +version = "0.1.81" dependencies = [ "anstream", "clippy_config", @@ -655,7 +655,7 @@ dependencies = [ [[package]] name = "clippy_config" -version = "0.1.80" +version = "0.1.81" dependencies = [ "rustc-semver", "serde", @@ -678,7 +678,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.80" +version = "0.1.81" dependencies = [ "arrayvec", "cargo_metadata 0.18.1", @@ -703,7 +703,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.80" +version = "0.1.81" dependencies = [ "arrayvec", "clippy_config", @@ -1023,7 +1023,7 @@ dependencies = [ [[package]] name = "declare_clippy_lint" -version = "0.1.80" +version = "0.1.81" dependencies = [ "itertools 0.12.1", "quote", -- cgit 1.4.1-3-g733a5 From c75f7283bf52c6e2ec6a178f2b7717a4daddacf4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 15 Apr 2024 11:20:33 +0000 Subject: Add some tests --- .../impl-trait/call_method_ambiguous.next.stderr | 17 +++++++++ tests/ui/impl-trait/call_method_ambiguous.rs | 39 ++++++++++++++++++++ .../call_method_on_inherent_impl.next.stderr | 17 +++++++++ .../ui/impl-trait/call_method_on_inherent_impl.rs | 25 +++++++++++++ ...d_on_inherent_impl_on_rigid_type.current.stderr | 16 +++++++++ ...thod_on_inherent_impl_on_rigid_type.next.stderr | 17 +++++++++ .../call_method_on_inherent_impl_on_rigid_type.rs | 22 ++++++++++++ ...call_method_on_inherent_impl_ref.current.stderr | 40 +++++++++++++++++++++ .../call_method_on_inherent_impl_ref.next.stderr | 31 ++++++++++++++++ .../impl-trait/call_method_on_inherent_impl_ref.rs | 35 ++++++++++++++++++ .../call_method_without_import.no_import.stderr | 37 +++++++++++++++++++ tests/ui/impl-trait/call_method_without_import.rs | 42 ++++++++++++++++++++++ .../ui/impl-trait/method-resolution.current.stderr | 36 +++++++++++++++++++ tests/ui/impl-trait/method-resolution.rs | 29 +++++++++++++++ tests/ui/impl-trait/method-resolution2.next.stderr | 20 +++++++++++ tests/ui/impl-trait/method-resolution2.rs | 31 ++++++++++++++++ .../impl-trait/method-resolution3.current.stderr | 37 +++++++++++++++++++ tests/ui/impl-trait/method-resolution3.next.stderr | 20 +++++++++++ tests/ui/impl-trait/method-resolution3.rs | 29 +++++++++++++++ tests/ui/impl-trait/method-resolution4.next.stderr | 22 ++++++++++++ tests/ui/impl-trait/method-resolution4.rs | 20 +++++++++++ .../recursive-parent-trait-method-call.rs | 42 ++++++++++++++++++++++ .../method_resolution.current.stderr | 15 ++++++++ .../method_resolution.next.stderr | 12 +++++++ .../ui/type-alias-impl-trait/method_resolution.rs | 30 ++++++++++++++++ .../method_resolution2.current.stderr | 36 +++++++++++++++++++ .../ui/type-alias-impl-trait/method_resolution2.rs | 30 ++++++++++++++++ .../method_resolution3.current.stderr | 21 +++++++++++ .../method_resolution3.next.stderr | 15 ++++++++ .../ui/type-alias-impl-trait/method_resolution3.rs | 36 +++++++++++++++++++ .../method_resolution4.current.stderr | 21 +++++++++++ .../method_resolution4.next.stderr | 15 ++++++++ .../ui/type-alias-impl-trait/method_resolution4.rs | 39 ++++++++++++++++++++ .../method_resolution5.current.stderr | 15 ++++++++ .../ui/type-alias-impl-trait/method_resolution5.rs | 34 ++++++++++++++++++ ...olution_trait_method_from_opaque.current.stderr | 15 ++++++++ ...resolution_trait_method_from_opaque.next.stderr | 9 +++++ .../method_resolution_trait_method_from_opaque.rs | 31 ++++++++++++++++ 38 files changed, 998 insertions(+) create mode 100644 tests/ui/impl-trait/call_method_ambiguous.next.stderr create mode 100644 tests/ui/impl-trait/call_method_ambiguous.rs create mode 100644 tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr create mode 100644 tests/ui/impl-trait/call_method_on_inherent_impl.rs create mode 100644 tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr create mode 100644 tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr create mode 100644 tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs create mode 100644 tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr create mode 100644 tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr create mode 100644 tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs create mode 100644 tests/ui/impl-trait/call_method_without_import.no_import.stderr create mode 100644 tests/ui/impl-trait/call_method_without_import.rs create mode 100644 tests/ui/impl-trait/method-resolution.current.stderr create mode 100644 tests/ui/impl-trait/method-resolution.rs create mode 100644 tests/ui/impl-trait/method-resolution2.next.stderr create mode 100644 tests/ui/impl-trait/method-resolution2.rs create mode 100644 tests/ui/impl-trait/method-resolution3.current.stderr create mode 100644 tests/ui/impl-trait/method-resolution3.next.stderr create mode 100644 tests/ui/impl-trait/method-resolution3.rs create mode 100644 tests/ui/impl-trait/method-resolution4.next.stderr create mode 100644 tests/ui/impl-trait/method-resolution4.rs create mode 100644 tests/ui/impl-trait/recursive-parent-trait-method-call.rs create mode 100644 tests/ui/type-alias-impl-trait/method_resolution.current.stderr create mode 100644 tests/ui/type-alias-impl-trait/method_resolution.next.stderr create mode 100644 tests/ui/type-alias-impl-trait/method_resolution.rs create mode 100644 tests/ui/type-alias-impl-trait/method_resolution2.current.stderr create mode 100644 tests/ui/type-alias-impl-trait/method_resolution2.rs create mode 100644 tests/ui/type-alias-impl-trait/method_resolution3.current.stderr create mode 100644 tests/ui/type-alias-impl-trait/method_resolution3.next.stderr create mode 100644 tests/ui/type-alias-impl-trait/method_resolution3.rs create mode 100644 tests/ui/type-alias-impl-trait/method_resolution4.current.stderr create mode 100644 tests/ui/type-alias-impl-trait/method_resolution4.next.stderr create mode 100644 tests/ui/type-alias-impl-trait/method_resolution4.rs create mode 100644 tests/ui/type-alias-impl-trait/method_resolution5.current.stderr create mode 100644 tests/ui/type-alias-impl-trait/method_resolution5.rs create mode 100644 tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.current.stderr create mode 100644 tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr create mode 100644 tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.rs diff --git a/tests/ui/impl-trait/call_method_ambiguous.next.stderr b/tests/ui/impl-trait/call_method_ambiguous.next.stderr new file mode 100644 index 00000000000..cd222aa7ae9 --- /dev/null +++ b/tests/ui/impl-trait/call_method_ambiguous.next.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed + --> $DIR/call_method_ambiguous.rs:29:13 + | +LL | let mut iter = foo(n - 1, m); + | ^^^^^^^^ +LL | +LL | assert_eq!(iter.get(), 1); + | ---- type must be known at this point + | +help: consider giving `iter` an explicit type + | +LL | let mut iter: /* Type */ = foo(n - 1, m); + | ++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/call_method_ambiguous.rs b/tests/ui/impl-trait/call_method_ambiguous.rs new file mode 100644 index 00000000000..c26c01e002d --- /dev/null +++ b/tests/ui/impl-trait/call_method_ambiguous.rs @@ -0,0 +1,39 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[current] run-pass + +#![feature(precise_capturing)] +#![allow(incomplete_features)] + +trait Get { + fn get(&mut self) -> u32; +} + +impl Get for () { + fn get(&mut self) -> u32 { + 0 + } +} + +impl Get for &mut T +where + T: Get, +{ + fn get(&mut self) -> u32 { + T::get(self) + 1 + } +} + +fn foo(n: usize, m: &mut ()) -> impl use<'_> Get { + if n > 0 { + let mut iter = foo(n - 1, m); + //[next]~^ type annotations needed + assert_eq!(iter.get(), 1); + } + m +} + +fn main() { + let g = foo(1, &mut ()).get(); + assert_eq!(g, 1); +} diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr new file mode 100644 index 00000000000..271051f120a --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed + --> $DIR/call_method_on_inherent_impl.rs:18:13 + | +LL | let x = my_foo(); + | ^ +LL | +LL | x.my_debug(); + | - type must be known at this point + | +help: consider giving `x` an explicit type + | +LL | let x: /* Type */ = my_foo(); + | ++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl.rs b/tests/ui/impl-trait/call_method_on_inherent_impl.rs new file mode 100644 index 00000000000..17f7cad660d --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl.rs @@ -0,0 +1,25 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[current] check-pass + +trait MyDebug { + fn my_debug(&self); +} + +impl MyDebug for T +where + T: std::fmt::Debug, +{ + fn my_debug(&self) {} +} + +fn my_foo() -> impl std::fmt::Debug { + if false { + let x = my_foo(); + //[next]~^ type annotations needed + x.my_debug(); + } + () +} + +fn main() {} diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr new file mode 100644 index 00000000000..6ecb2b05fc5 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr @@ -0,0 +1,16 @@ +error[E0599]: no method named `my_debug` found for reference `&impl Debug` in the current scope + --> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:16:11 + | +LL | x.my_debug(); + | ^^^^^^^^ method not found in `&impl Debug` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it + --> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:4:1 + | +LL | trait MyDebug { + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr new file mode 100644 index 00000000000..5fb0b8f1d14 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed for `&_` + --> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:14:13 + | +LL | let x = &my_foo(); + | ^ +LL | +LL | x.my_debug(); + | -------- type must be known at this point + | +help: consider giving `x` an explicit type, where the placeholders `_` are specified + | +LL | let x: &_ = &my_foo(); + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs new file mode 100644 index 00000000000..7fb2ff3b2bc --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs @@ -0,0 +1,22 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +trait MyDebug { + fn my_debug(&self); +} + +impl MyDebug for &() { + fn my_debug(&self) {} +} + +fn my_foo() -> impl std::fmt::Debug { + if false { + let x = &my_foo(); + //[next]~^ ERROR: type annotations needed + x.my_debug(); + //[current]~^ ERROR: no method named `my_debug` + } + () +} + +fn main() {} diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr new file mode 100644 index 00000000000..fe6e166cb4f --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr @@ -0,0 +1,40 @@ +error[E0599]: no method named `my_debug` found for opaque type `impl Debug` in the current scope + --> $DIR/call_method_on_inherent_impl_ref.rs:20:11 + | +LL | fn my_debug(&self); + | -------- the method is available for `&impl Debug` here +... +LL | x.my_debug(); + | ^^^^^^^^ method not found in `impl Debug` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it + --> $DIR/call_method_on_inherent_impl_ref.rs:4:1 + | +LL | trait MyDebug { + | ^^^^^^^^^^^^^ + +error[E0391]: cycle detected when computing type of opaque `my_foo::{opaque#0}` + --> $DIR/call_method_on_inherent_impl_ref.rs:15:16 + | +LL | fn my_foo() -> impl std::fmt::Debug { + | ^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires type-checking `my_foo`... + --> $DIR/call_method_on_inherent_impl_ref.rs:20:9 + | +LL | x.my_debug(); + | ^ + = note: ...which requires evaluating trait selection obligation `my_foo::{opaque#0}: core::marker::Unpin`... + = note: ...which again requires computing type of opaque `my_foo::{opaque#0}`, completing the cycle +note: cycle used when computing type of `my_foo::{opaque#0}` + --> $DIR/call_method_on_inherent_impl_ref.rs:15:16 + | +LL | fn my_foo() -> impl std::fmt::Debug { + | ^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0391, E0599. +For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr new file mode 100644 index 00000000000..327f6ca3450 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr @@ -0,0 +1,31 @@ +error[E0282]: type annotations needed + --> $DIR/call_method_on_inherent_impl_ref.rs:18:13 + | +LL | let x = my_foo(); + | ^ +LL | +LL | x.my_debug(); + | - type must be known at this point + | +help: consider giving `x` an explicit type + | +LL | let x: /* Type */ = my_foo(); + | ++++++++++++ + +error[E0282]: type annotations needed for `&_` + --> $DIR/call_method_on_inherent_impl_ref.rs:28:13 + | +LL | let x = &my_bar(); + | ^ +LL | +LL | x.my_debug(); + | -------- type must be known at this point + | +help: consider giving `x` an explicit type, where the placeholders `_` are specified + | +LL | let x: &_ = &my_bar(); + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs new file mode 100644 index 00000000000..40ad21532a4 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs @@ -0,0 +1,35 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +trait MyDebug { + fn my_debug(&self); +} + +impl MyDebug for &T +where + T: std::fmt::Debug, +{ + fn my_debug(&self) {} +} + +fn my_foo() -> impl std::fmt::Debug { + //[current]~^ cycle + if false { + let x = my_foo(); + //[next]~^ type annotations needed + x.my_debug(); + //[current]~^ no method named `my_debug` found + } + () +} + +fn my_bar() -> impl std::fmt::Debug { + if false { + let x = &my_bar(); + //[next]~^ type annotations needed + x.my_debug(); + } + () +} + +fn main() {} 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 new file mode 100644 index 00000000000..72982b695bb --- /dev/null +++ b/tests/ui/impl-trait/call_method_without_import.no_import.stderr @@ -0,0 +1,37 @@ +error[E0599]: no method named `fmt` found for opaque type `impl Debug` in the current scope + --> $DIR/call_method_without_import.rs:17:11 + | +LL | x.fmt(f); + | ^^^ method not found in `impl Debug` + --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL + | + = note: the method is available for `impl Debug` here + | + = help: items from traits can only be used if the trait is in scope +help: trait `Debug` which provides `fmt` is implemented but not in scope; perhaps you want to import it + | +LL + use std::fmt::Debug; + | + +error[E0599]: no method named `fmt` found for mutable reference `&mut impl Debug` in the current scope + --> $DIR/call_method_without_import.rs:26:11 + | +LL | x.fmt(f); + | ^^^ method not found in `&mut impl Debug` + | + = 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::LowerExp; + | + and 5 other candidates + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/call_method_without_import.rs b/tests/ui/impl-trait/call_method_without_import.rs new file mode 100644 index 00000000000..d62777ea283 --- /dev/null +++ b/tests/ui/impl-trait/call_method_without_import.rs @@ -0,0 +1,42 @@ +//! Test that opaque types only pick up methods from traits in their bounds +//! if the trait is imported. +//! +//! FIXME: always look through the bounds of an opaque type to see if there are +//! methods that could be called on any of the bound traits, irrespective of +//! imported traits. + +//@ revisions: import no_import +//@[import] check-pass + +#[cfg(import)] +use std::fmt::Debug as _; + +fn foo(f: &mut std::fmt::Formatter<'_>) -> impl std::fmt::Debug { + if false { + let x = foo(f); + x.fmt(f); + //[no_import]~^ ERROR: no method named `fmt` found + } + () +} + +fn foo1(f: &mut std::fmt::Formatter<'_>) -> impl std::fmt::Debug { + if false { + let x = &mut foo(f); + x.fmt(f); + //[no_import]~^ ERROR: no method named `fmt` found + } + () +} + +// inconsistent with this +fn bar(t: impl std::fmt::Debug, f: &mut std::fmt::Formatter<'_>) { + t.fmt(f); +} + +// and the desugared version, of course +fn baz(t: T, f: &mut std::fmt::Formatter<'_>) { + t.fmt(f); +} + +fn main() {} diff --git a/tests/ui/impl-trait/method-resolution.current.stderr b/tests/ui/impl-trait/method-resolution.current.stderr new file mode 100644 index 00000000000..6d10693c893 --- /dev/null +++ b/tests/ui/impl-trait/method-resolution.current.stderr @@ -0,0 +1,36 @@ +error[E0599]: no method named `bar` found for struct `Bar` in the current scope + --> $DIR/method-resolution.rs:23:11 + | +LL | struct Bar(T); + | ------------- method `bar` not found for this struct +... +LL | x.bar(); + | ^^^ method not found in `Bar` + | + = note: the method was found for + - `Bar` + +error[E0391]: cycle detected when computing type of opaque `foo::{opaque#0}` + --> $DIR/method-resolution.rs:19:24 + | +LL | fn foo(x: bool) -> Bar { + | ^^^^^^^^^^ + | +note: ...which requires type-checking `foo`... + --> $DIR/method-resolution.rs:23:9 + | +LL | x.bar(); + | ^ + = note: ...which requires evaluating trait selection obligation `Bar: core::marker::Unpin`... + = note: ...which again requires computing type of opaque `foo::{opaque#0}`, completing the cycle +note: cycle used when computing type of `foo::{opaque#0}` + --> $DIR/method-resolution.rs:19:24 + | +LL | fn foo(x: bool) -> Bar { + | ^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0391, E0599. +For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/method-resolution.rs b/tests/ui/impl-trait/method-resolution.rs new file mode 100644 index 00000000000..07618aa6408 --- /dev/null +++ b/tests/ui/impl-trait/method-resolution.rs @@ -0,0 +1,29 @@ +//! Check that we do not constrain hidden types during method resolution. +//! Otherwise we'd pick up that calling `bar` can be satisfied iff `u32` +//! is the hidden type of the RPIT. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +trait Trait {} + +impl Trait for u32 {} + +struct Bar(T); + +impl Bar { + fn bar(self) {} +} + +fn foo(x: bool) -> Bar { + //[current]~^ ERROR: cycle detected + if x { + let x = foo(false); + x.bar(); + //[current]~^ ERROR: no method named `bar` found + } + todo!() +} + +fn main() {} diff --git a/tests/ui/impl-trait/method-resolution2.next.stderr b/tests/ui/impl-trait/method-resolution2.next.stderr new file mode 100644 index 00000000000..223430e1658 --- /dev/null +++ b/tests/ui/impl-trait/method-resolution2.next.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/method-resolution2.rs:25:11 + | +LL | x.bar(); + | ^^^ multiple `bar` found + | +note: candidate #1 is defined in an impl for the type `Bar` + --> $DIR/method-resolution2.rs:19:5 + | +LL | fn bar(self) {} + | ^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Bar` + --> $DIR/method-resolution2.rs:15:5 + | +LL | fn bar(self) {} + | ^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/impl-trait/method-resolution2.rs b/tests/ui/impl-trait/method-resolution2.rs new file mode 100644 index 00000000000..2930b42b8bc --- /dev/null +++ b/tests/ui/impl-trait/method-resolution2.rs @@ -0,0 +1,31 @@ +//! Check that the method call does not constrain the RPIT to `i32`, even though +//! `i32` is the only trait that satisfies the RPIT's trait bounds. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[current] check-pass + +trait Trait {} + +impl Trait for i32 {} + +struct Bar(T); + +impl Bar { + fn bar(self) {} +} + +impl Bar { + fn bar(self) {} +} + +fn foo(x: bool) -> Bar { + if x { + let x = foo(false); + x.bar(); + //[next]~^ ERROR: multiple applicable items in scope + } + Bar(42_i32) +} + +fn main() {} diff --git a/tests/ui/impl-trait/method-resolution3.current.stderr b/tests/ui/impl-trait/method-resolution3.current.stderr new file mode 100644 index 00000000000..7407b489e32 --- /dev/null +++ b/tests/ui/impl-trait/method-resolution3.current.stderr @@ -0,0 +1,37 @@ +error[E0599]: no method named `bar` found for struct `Bar` in the current scope + --> $DIR/method-resolution3.rs:22:11 + | +LL | struct Bar(T); + | ------------- method `bar` not found for this struct +... +LL | x.bar(); + | ^^^ method not found in `Bar` + | + = note: the method was found for + - `Bar` + - `Bar` + +error[E0391]: cycle detected when computing type of opaque `foo::{opaque#0}` + --> $DIR/method-resolution3.rs:18:24 + | +LL | fn foo(x: bool) -> Bar { + | ^^^^^^^^^^ + | +note: ...which requires type-checking `foo`... + --> $DIR/method-resolution3.rs:22:9 + | +LL | x.bar(); + | ^ + = note: ...which requires evaluating trait selection obligation `Bar: core::marker::Unpin`... + = note: ...which again requires computing type of opaque `foo::{opaque#0}`, completing the cycle +note: cycle used when computing type of `foo::{opaque#0}` + --> $DIR/method-resolution3.rs:18:24 + | +LL | fn foo(x: bool) -> Bar { + | ^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0391, E0599. +For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/method-resolution3.next.stderr b/tests/ui/impl-trait/method-resolution3.next.stderr new file mode 100644 index 00000000000..53b77c620ba --- /dev/null +++ b/tests/ui/impl-trait/method-resolution3.next.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/method-resolution3.rs:22:11 + | +LL | x.bar(); + | ^^^ multiple `bar` found + | +note: candidate #1 is defined in an impl for the type `Bar` + --> $DIR/method-resolution3.rs:15:5 + | +LL | fn bar(self) {} + | ^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Bar` + --> $DIR/method-resolution3.rs:11:5 + | +LL | fn bar(self) {} + | ^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/impl-trait/method-resolution3.rs b/tests/ui/impl-trait/method-resolution3.rs new file mode 100644 index 00000000000..8474e2da7db --- /dev/null +++ b/tests/ui/impl-trait/method-resolution3.rs @@ -0,0 +1,29 @@ +//! Check that we consider `Bar` to successfully unify +//! with both `Bar` and `Bar` (in isolation), so we bail +//! out with ambiguity. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +struct Bar(T); + +impl Bar { + fn bar(self) {} +} + +impl Bar { + fn bar(self) {} +} + +fn foo(x: bool) -> Bar { + //[current]~^ ERROR: cycle + if x { + let x = foo(false); + x.bar(); + //[current]~^ ERROR: no method named `bar` + //[next]~^^ ERROR: multiple applicable items in scope + } + todo!() +} + +fn main() {} diff --git a/tests/ui/impl-trait/method-resolution4.next.stderr b/tests/ui/impl-trait/method-resolution4.next.stderr new file mode 100644 index 00000000000..b48de0af357 --- /dev/null +++ b/tests/ui/impl-trait/method-resolution4.next.stderr @@ -0,0 +1,22 @@ +error[E0282]: type annotations needed + --> $DIR/method-resolution4.rs:13:9 + | +LL | foo(false).next().unwrap(); + | ^^^^^^^^^^ cannot infer type + +error[E0308]: mismatched types + --> $DIR/method-resolution4.rs:16:5 + | +LL | fn foo(b: bool) -> impl Iterator { + | ------------------------ the expected opaque type +... +LL | std::iter::empty() + | ^^^^^^^^^^^^^^^^^^ types differ + | + = note: expected opaque type `impl Iterator` + found struct `std::iter::Empty<_>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/method-resolution4.rs b/tests/ui/impl-trait/method-resolution4.rs new file mode 100644 index 00000000000..3578db7cb55 --- /dev/null +++ b/tests/ui/impl-trait/method-resolution4.rs @@ -0,0 +1,20 @@ +//! The recursive method call yields the opaque type. The +//! `next` method call then constrains the hidden type to `&mut _` +//! because `next` takes `&mut self`. We never resolve the inference +//! variable, but get a type mismatch when comparing `&mut _` with +//! `std::iter::Empty`. + +//@[current] check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +fn foo(b: bool) -> impl Iterator { + if b { + foo(false).next().unwrap(); + //[next]~^ type annotations needed + } + std::iter::empty() + //[next]~^ mismatched types +} + +fn main() {} diff --git a/tests/ui/impl-trait/recursive-parent-trait-method-call.rs b/tests/ui/impl-trait/recursive-parent-trait-method-call.rs new file mode 100644 index 00000000000..4da9a06a465 --- /dev/null +++ b/tests/ui/impl-trait/recursive-parent-trait-method-call.rs @@ -0,0 +1,42 @@ +//! This test checks that we can resolve the `boxed` method call to `FutureExt`, +//! because we know that the anonymous future does not implement `StreamExt`. + +//@ edition: 2021 +//@ check-pass + +use std::future::Future; +use std::pin::Pin; + +trait FutureExt: Future + Sized + Send + 'static { + fn boxed(self) -> Pin + Send + 'static>> { + Box::pin(self) + } +} + +trait StreamExt: Future + Sized + Send + 'static { + fn boxed(self) -> Pin + Send + 'static>> { + Box::pin(self) + } +} + +impl FutureExt for T {} + +fn go(i: usize) -> impl Future + Send + 'static { + async move { + if i != 0 { + spawn(async move { + let fut = go(i - 1).boxed(); + fut.await; + }) + .await; + } + } +} + +pub fn spawn( + _: impl Future + Send + 'static, +) -> impl Future + Send + 'static { + async move { todo!() } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/method_resolution.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution.current.stderr new file mode 100644 index 00000000000..a9c05ad3342 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution.current.stderr @@ -0,0 +1,15 @@ +error[E0599]: no method named `bar` found for struct `Bar` in the current scope + --> $DIR/method_resolution.rs:21:14 + | +LL | struct Bar(T); + | ------------- method `bar` not found for this struct +... +LL | self.bar() + | ^^^ method not found in `Bar` + | + = note: the method was found for + - `Bar` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution.next.stderr new file mode 100644 index 00000000000..6b34358a56e --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution.next.stderr @@ -0,0 +1,12 @@ +error[E0599]: no method named `bar` found for struct `Bar` in the current scope + --> $DIR/method_resolution.rs:21:14 + | +LL | struct Bar(T); + | ------------- method `bar` not found for this struct +... +LL | self.bar() + | ^^^ method cannot be called on `Bar` due to unsatisfied trait bounds + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution.rs b/tests/ui/type-alias-impl-trait/method_resolution.rs new file mode 100644 index 00000000000..f636aba15c0 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution.rs @@ -0,0 +1,30 @@ +//! `Bar::foo` is not defining `Foo`, so it cannot rely on the fact that +//! `u32` is the hidden type of `Foo` to call `bar` + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +#![feature(type_alias_impl_trait)] + +type Foo = impl Sized; + +struct Bar(T); + +impl Bar { + fn bar(mut self) { + self.0 = 42_u32; + } +} + +impl Bar { + fn foo(self) { + self.bar() + //~^ ERROR: no method named `bar` + } +} + +fn foo() -> Foo { + 42_u32 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/method_resolution2.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution2.current.stderr new file mode 100644 index 00000000000..e68ea70a8ef --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution2.current.stderr @@ -0,0 +1,36 @@ +error[E0599]: no method named `foo` found for struct `Bar` in the current scope + --> $DIR/method_resolution2.rs:17:14 + | +LL | struct Bar(T); + | ------------- method `foo` not found for this struct +... +LL | self.foo() + | ^^^ method not found in `Bar` + | + = note: the method was found for + - `Bar` + +error[E0391]: cycle detected when computing type of opaque `Foo::{opaque#0}` + --> $DIR/method_resolution2.rs:10:12 + | +LL | type Foo = impl Sized; + | ^^^^^^^^^^ + | +note: ...which requires type-checking `::bar`... + --> $DIR/method_resolution2.rs:17:9 + | +LL | self.foo() + | ^^^^ + = note: ...which requires evaluating trait selection obligation `Bar: core::marker::Unpin`... + = note: ...which again requires computing type of opaque `Foo::{opaque#0}`, completing the cycle +note: cycle used when computing type of `Foo::{opaque#0}` + --> $DIR/method_resolution2.rs:10:12 + | +LL | type Foo = impl Sized; + | ^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0391, E0599. +For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution2.rs b/tests/ui/type-alias-impl-trait/method_resolution2.rs new file mode 100644 index 00000000000..d252f8640d4 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution2.rs @@ -0,0 +1,30 @@ +//! Check that we do not unify `Bar` with `Bar`, even though the +//! `foo` method call can be resolved unambiguously by doing so. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +#![feature(type_alias_impl_trait)] + +type Foo = impl Sized; +//[current]~^ ERROR: cycle + +struct Bar(T); + +impl Bar { + fn bar(self) { + self.foo() + //[current]~^ ERROR: no method named `foo` + } +} + +impl Bar { + fn foo(self) {} +} + +fn foo() -> Foo { + 42_u32 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr new file mode 100644 index 00000000000..e992d059daf --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr @@ -0,0 +1,21 @@ +error[E0307]: invalid `self` parameter type: `Bar` + --> $DIR/method_resolution3.rs:16:18 + | +LL | fn bar(self: Bar) { + | ^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0307]: invalid `self` parameter type: `&Bar` + --> $DIR/method_resolution3.rs:21:18 + | +LL | fn baz(self: &Bar) { + | ^^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0307`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr new file mode 100644 index 00000000000..9272017cdf5 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr @@ -0,0 +1,15 @@ +error[E0271]: type mismatch resolving `Foo == u32` + --> $DIR/method_resolution3.rs:16:18 + | +LL | fn bar(self: Bar) { + | ^^^^^^^^ types differ + +error[E0271]: type mismatch resolving `Foo == u32` + --> $DIR/method_resolution3.rs:21:18 + | +LL | fn baz(self: &Bar) { + | ^^^^^^^^^ types differ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.rs b/tests/ui/type-alias-impl-trait/method_resolution3.rs new file mode 100644 index 00000000000..447f3144b82 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution3.rs @@ -0,0 +1,36 @@ +//! Check that one cannot use arbitrary self types where a generic parameter +//! mismatches with an opaque type. In theory this could unify with the opaque +//! type, registering the generic parameter as the hidden type of the opaque type. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +#![feature(type_alias_impl_trait, arbitrary_self_types)] + +type Foo = impl Copy; + +#[derive(Copy, Clone)] +struct Bar(T); + +impl Bar { + fn bar(self: Bar) { + //[current]~^ ERROR: invalid `self` parameter + //[next]~^^ ERROR: type mismatch resolving `Foo == u32` + self.foo() + } + fn baz(self: &Bar) { + //[current]~^ ERROR: invalid `self` parameter + //[next]~^^ ERROR: type mismatch resolving `Foo == u32` + self.foo() + } +} + +impl Bar { + fn foo(self) {} +} + +fn foo() -> Foo { + 42_u32 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr new file mode 100644 index 00000000000..3a2ca18f890 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr @@ -0,0 +1,21 @@ +error[E0307]: invalid `self` parameter type: `Bar` + --> $DIR/method_resolution4.rs:27:18 + | +LL | fn foo(self: Bar) { + | ^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0307]: invalid `self` parameter type: `&Bar` + --> $DIR/method_resolution4.rs:32:20 + | +LL | fn foomp(self: &Bar) { + | ^^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0307`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr new file mode 100644 index 00000000000..33ed2800ebe --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr @@ -0,0 +1,15 @@ +error[E0271]: type mismatch resolving `u32 == Foo` + --> $DIR/method_resolution4.rs:27:18 + | +LL | fn foo(self: Bar) { + | ^^^^^^^^ types differ + +error[E0271]: type mismatch resolving `u32 == Foo` + --> $DIR/method_resolution4.rs:32:20 + | +LL | fn foomp(self: &Bar) { + | ^^^^^^^^^ types differ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.rs b/tests/ui/type-alias-impl-trait/method_resolution4.rs new file mode 100644 index 00000000000..42ed04b3c30 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution4.rs @@ -0,0 +1,39 @@ +//! Check that one cannot use arbitrary self types where a generic parameter +//! mismatches with an opaque type. In theory this could unify with the opaque +//! type, registering the generic parameter as the hidden type of the opaque type. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +#![feature(type_alias_impl_trait, arbitrary_self_types)] + +mod foo { + pub type Foo = impl Copy; + + fn foo() -> Foo { + 42_u32 + } +} +use foo::Foo; + +#[derive(Copy, Clone)] +struct Bar(T); + +impl Bar { + fn bar(self) {} +} + +impl Bar { + fn foo(self: Bar) { + //[current]~^ ERROR: invalid `self` parameter + //[next]~^^ ERROR: type mismatch resolving `u32 == Foo` + self.bar() + } + fn foomp(self: &Bar) { + //[current]~^ ERROR: invalid `self` parameter + //[next]~^^ ERROR: type mismatch resolving `u32 == Foo` + self.bar() + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/method_resolution5.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution5.current.stderr new file mode 100644 index 00000000000..193e6e14709 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution5.current.stderr @@ -0,0 +1,15 @@ +error[E0599]: no method named `bar` found for struct `Bar` in the current scope + --> $DIR/method_resolution5.rs:25:14 + | +LL | struct Bar(T); + | ------------- method `bar` not found for this struct +... +LL | self.bar() + | ^^^ method not found in `Bar` + | + = note: the method was found for + - `Bar` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution5.rs b/tests/ui/type-alias-impl-trait/method_resolution5.rs new file mode 100644 index 00000000000..69335c9dede --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution5.rs @@ -0,0 +1,34 @@ +//! Even though `Bar::foo` is defining `Foo`, the old solver does +//! not figure out that `u32` is the hidden type of `Foo` to call `bar`. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +#![feature(type_alias_impl_trait)] + +type Foo = impl Sized; + +struct Bar(T); + +impl Bar { + fn bar(mut self) { + self.0 = 42_u32; + } +} + +impl Bar { + fn foo(self) + where + Foo:, + { + self.bar() + //[current]~^ ERROR: no method named `bar` + } +} + +fn foo() -> Foo { + 42_u32 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.current.stderr new file mode 100644 index 00000000000..f331da1af87 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.current.stderr @@ -0,0 +1,15 @@ +error: item does not constrain `Tait::{opaque#0}`, but has it in its signature + --> $DIR/method_resolution_trait_method_from_opaque.rs:24:8 + | +LL | fn foo(&mut self) { + | ^^^ + | + = note: consider moving the opaque type's declaration and defining uses into a separate module +note: this opaque type is in the signature + --> $DIR/method_resolution_trait_method_from_opaque.rs:17:13 + | +LL | type Tait = impl Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr new file mode 100644 index 00000000000..2617ce124c1 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/method_resolution_trait_method_from_opaque.rs:26:9 + | +LL | self.bar.next().unwrap(); + | ^^^^^^^^ cannot infer type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.rs b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.rs new file mode 100644 index 00000000000..b6adf08853f --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.rs @@ -0,0 +1,31 @@ +//! This test demonstrates how method calls will attempt to unify an opaque type with a reference +//! if the method takes `&self` as its argument. This is almost never what is desired, as the user +//! would like to have method resolution happen on the opaque type instead of inferring the hidden +//! type. Once type-alias-impl-trait requires annotating which functions should constrain the hidden +//! type, this won't be as much of a problem, as most functions that do method calls on opaque types +//! won't also be the ones defining the hidden type. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +#![feature(type_alias_impl_trait)] + +pub struct Foo { + bar: Tait, +} + +type Tait = impl Iterator; + +impl Foo { + pub fn new() -> Foo { + Foo { bar: std::iter::empty() } + } + + fn foo(&mut self) { + //[current]~^ ERROR: item does not constrain + self.bar.next().unwrap(); + //[next]~^ ERROR: type annotations needed + } +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From 9cf60ee9d33fadff387d83d09aef1ce43589e233 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 15 Apr 2024 11:37:09 +0000 Subject: Method resolution constrains hidden types instead of rejecting method candidates --- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- compiler/rustc_hir_typeck/src/method/confirm.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 65 ++++++++++------------ compiler/rustc_middle/src/traits/query.rs | 2 +- .../ui/impl-trait/method-resolution.current.stderr | 36 ------------ tests/ui/impl-trait/method-resolution.rs | 9 +-- tests/ui/impl-trait/method-resolution2.rs | 2 +- .../impl-trait/method-resolution3.current.stderr | 43 +++++--------- tests/ui/impl-trait/method-resolution3.next.stderr | 2 +- tests/ui/impl-trait/method-resolution3.rs | 4 +- tests/ui/impl-trait/method-resolution4.rs | 2 +- tests/ui/methods/opaque_param_in_ufc.rs | 6 +- tests/ui/methods/opaque_param_in_ufc.stderr | 36 ------------ .../method_resolution2.current.stderr | 36 ------------ .../ui/type-alias-impl-trait/method_resolution2.rs | 6 +- .../method_resolution5.current.stderr | 15 ----- .../ui/type-alias-impl-trait/method_resolution5.rs | 3 +- 17 files changed, 58 insertions(+), 213 deletions(-) delete mode 100644 tests/ui/impl-trait/method-resolution.current.stderr delete mode 100644 tests/ui/methods/opaque_param_in_ufc.stderr delete mode 100644 tests/ui/type-alias-impl-trait/method_resolution2.current.stderr delete mode 100644 tests/ui/type-alias-impl-trait/method_resolution5.current.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 94e879ae9c3..9531c002829 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1418,7 +1418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).instantiate(tcx, args)); let self_ty = self.normalize(span, self_ty); match self.at(&self.misc(span), self.param_env).eq( - DefineOpaqueTypes::No, + DefineOpaqueTypes::Yes, impl_ty, self_ty, ) { diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 3c9a49e91a3..120e3239d1f 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { args, })), ); - match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::No, method_self_ty, self_ty) { + match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::Yes, method_self_ty, self_ty) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index e842bba34bf..3986374a343 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -634,8 +634,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn assemble_probe(&mut self, self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>) { - debug!("assemble_probe: self_ty={:?}", self_ty); let raw_self_ty = self_ty.value.value; match *raw_self_ty.kind() { ty::Dynamic(data, ..) if let Some(p) = data.principal() => { @@ -713,13 +713,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) { if !self.impl_dups.insert(impl_def_id) { return; // already visited } - debug!("assemble_inherent_impl_probe {:?}", impl_def_id); - for item in self.impl_or_trait_item(impl_def_id) { if !self.has_applicable_self(&item) { // No receiver declared. Not a candidate. @@ -737,9 +736,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>) { - debug!("assemble_inherent_candidates_from_object(self_ty={:?})", self_ty); - let principal = match self_ty.kind() { ty::Dynamic(ref data, ..) => Some(data), _ => None, @@ -768,9 +766,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }); } + #[instrument(level = "debug", skip(self))] fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) { // FIXME: do we want to commit to this behavior for param bounds? - debug!("assemble_inherent_candidates_from_param(param_ty={:?})", param_ty); let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| { let bound_predicate = predicate.kind(); @@ -826,6 +824,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn assemble_extension_candidates_for_traits_in_scope(&mut self) { let mut duplicates = FxHashSet::default(); let opt_applicable_traits = self.tcx.in_scope_traits(self.scope_expr_id); @@ -842,6 +841,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn assemble_extension_candidates_for_all_traits(&mut self) { let mut duplicates = FxHashSet::default(); for trait_info in suggest::all_traits(self.tcx) { @@ -863,12 +863,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn assemble_extension_candidates_for_trait( &mut self, import_ids: &SmallVec<[LocalDefId; 1]>, trait_def_id: DefId, ) { - debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id); let trait_args = self.fresh_args_for_item(self.span, trait_def_id); let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_args); @@ -958,6 +958,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /////////////////////////////////////////////////////////////////////////// // THE ACTUAL SEARCH + #[instrument(level = "debug", skip(self))] fn pick(mut self) -> PickResult<'tcx> { assert!(self.method_name.is_some()); @@ -1386,6 +1387,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "trace", skip(self, possibly_unsatisfied_predicates), ret)] fn consider_probe( &self, self_ty: Ty<'tcx>, @@ -1415,15 +1417,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, impl_ty, impl_args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - // FIXME: Make this `ocx.sup` once we define opaques more eagerly. - match self.at(cause, self.param_env).sup( - DefineOpaqueTypes::No, - xform_self_ty, - self_ty, - ) { - Ok(infer_ok) => { - ocx.register_infer_ok_obligations(infer_ok); - } + match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) { + Ok(()) => {} Err(err) => { debug!("--> cannot relate self-types {:?}", err); return ProbeResult::NoMatch; @@ -1484,19 +1479,23 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - // FIXME: Make this `ocx.sup` once we define opaques more eagerly. - match self.at(cause, self.param_env).sup( - DefineOpaqueTypes::No, - xform_self_ty, - self_ty, - ) { - Ok(infer_ok) => { - ocx.register_infer_ok_obligations(infer_ok); - } - Err(err) => { - debug!("--> cannot relate self-types {:?}", err); + match self_ty.kind() { + // HACK: opaque types will match anything for which their bounds hold. + // Thus we need to prevent them from trying to match the `&_` autoref + // candidates that get created for `&self` trait methods. + ty::Alias(ty::Opaque, alias_ty) + if self.infcx.can_define_opaque_ty(alias_ty.def_id) + && !xform_self_ty.is_ty_var() => + { return ProbeResult::NoMatch; } + _ => match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) { + Ok(()) => {} + Err(err) => { + debug!("--> cannot relate self-types {:?}", err); + return ProbeResult::NoMatch; + } + }, } let obligation = traits::Obligation::new( self.tcx, @@ -1536,15 +1535,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - // FIXME: Make this `ocx.sup` once we define opaques more eagerly. - match self.at(cause, self.param_env).sup( - DefineOpaqueTypes::No, - xform_self_ty, - self_ty, - ) { - Ok(infer_ok) => { - ocx.register_infer_ok_obligations(infer_ok); - } + match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) { + Ok(()) => {} Err(err) => { debug!("--> cannot relate self-types {:?}", err); return ProbeResult::NoMatch; @@ -1665,6 +1657,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// Similarly to `probe_for_return_type`, this method attempts to find the best matching /// candidate method where the method name may have been misspelled. Similarly to other /// edit distance based suggestions, we provide at most one such suggestion. + #[instrument(level = "debug", skip(self))] pub(crate) fn probe_for_similar_candidate( &mut self, ) -> Result, MethodError<'tcx>> { diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 50b6c77e1b2..4fad721ce98 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -156,7 +156,7 @@ pub struct CandidateStep<'tcx> { #[derive(Copy, Clone, Debug, HashStable)] pub struct MethodAutoderefStepsResult<'tcx> { - /// The valid autoderef steps that could be find. + /// The valid autoderef steps that could be found. pub steps: &'tcx [CandidateStep<'tcx>], /// If Some(T), a type autoderef reported an error on. pub opt_bad_ty: Option<&'tcx MethodAutoderefBadTy<'tcx>>, diff --git a/tests/ui/impl-trait/method-resolution.current.stderr b/tests/ui/impl-trait/method-resolution.current.stderr deleted file mode 100644 index 6d10693c893..00000000000 --- a/tests/ui/impl-trait/method-resolution.current.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error[E0599]: no method named `bar` found for struct `Bar` in the current scope - --> $DIR/method-resolution.rs:23:11 - | -LL | struct Bar(T); - | ------------- method `bar` not found for this struct -... -LL | x.bar(); - | ^^^ method not found in `Bar` - | - = note: the method was found for - - `Bar` - -error[E0391]: cycle detected when computing type of opaque `foo::{opaque#0}` - --> $DIR/method-resolution.rs:19:24 - | -LL | fn foo(x: bool) -> Bar { - | ^^^^^^^^^^ - | -note: ...which requires type-checking `foo`... - --> $DIR/method-resolution.rs:23:9 - | -LL | x.bar(); - | ^ - = note: ...which requires evaluating trait selection obligation `Bar: core::marker::Unpin`... - = note: ...which again requires computing type of opaque `foo::{opaque#0}`, completing the cycle -note: cycle used when computing type of `foo::{opaque#0}` - --> $DIR/method-resolution.rs:19:24 - | -LL | fn foo(x: bool) -> Bar { - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0391, E0599. -For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/method-resolution.rs b/tests/ui/impl-trait/method-resolution.rs index 07618aa6408..60fbacd8646 100644 --- a/tests/ui/impl-trait/method-resolution.rs +++ b/tests/ui/impl-trait/method-resolution.rs @@ -1,10 +1,9 @@ -//! Check that we do not constrain hidden types during method resolution. -//! Otherwise we'd pick up that calling `bar` can be satisfied iff `u32` -//! is the hidden type of the RPIT. +//! Since there is only one possible `bar` method, we invoke it and subsequently +//! constrain `foo`'s RPIT to `u32`. //@ revisions: current next //@[next] compile-flags: -Znext-solver -//@[next] check-pass +//@ check-pass trait Trait {} @@ -17,11 +16,9 @@ impl Bar { } fn foo(x: bool) -> Bar { - //[current]~^ ERROR: cycle detected if x { let x = foo(false); x.bar(); - //[current]~^ ERROR: no method named `bar` found } todo!() } diff --git a/tests/ui/impl-trait/method-resolution2.rs b/tests/ui/impl-trait/method-resolution2.rs index 2930b42b8bc..88d4f3d9896 100644 --- a/tests/ui/impl-trait/method-resolution2.rs +++ b/tests/ui/impl-trait/method-resolution2.rs @@ -1,5 +1,5 @@ //! Check that the method call does not constrain the RPIT to `i32`, even though -//! `i32` is the only trait that satisfies the RPIT's trait bounds. +//! `i32` is the only type that satisfies the RPIT's trait bounds. //@ revisions: current next //@[next] compile-flags: -Znext-solver diff --git a/tests/ui/impl-trait/method-resolution3.current.stderr b/tests/ui/impl-trait/method-resolution3.current.stderr index 7407b489e32..87dd862ef8f 100644 --- a/tests/ui/impl-trait/method-resolution3.current.stderr +++ b/tests/ui/impl-trait/method-resolution3.current.stderr @@ -1,37 +1,20 @@ -error[E0599]: no method named `bar` found for struct `Bar` in the current scope - --> $DIR/method-resolution3.rs:22:11 +error[E0034]: multiple applicable items in scope + --> $DIR/method-resolution3.rs:21:11 | -LL | struct Bar(T); - | ------------- method `bar` not found for this struct -... LL | x.bar(); - | ^^^ method not found in `Bar` + | ^^^ multiple `bar` found | - = note: the method was found for - - `Bar` - - `Bar` - -error[E0391]: cycle detected when computing type of opaque `foo::{opaque#0}` - --> $DIR/method-resolution3.rs:18:24 - | -LL | fn foo(x: bool) -> Bar { - | ^^^^^^^^^^ +note: candidate #1 is defined in an impl for the type `Bar` + --> $DIR/method-resolution3.rs:15:5 | -note: ...which requires type-checking `foo`... - --> $DIR/method-resolution3.rs:22:9 - | -LL | x.bar(); - | ^ - = note: ...which requires evaluating trait selection obligation `Bar: core::marker::Unpin`... - = note: ...which again requires computing type of opaque `foo::{opaque#0}`, completing the cycle -note: cycle used when computing type of `foo::{opaque#0}` - --> $DIR/method-resolution3.rs:18:24 +LL | fn bar(self) {} + | ^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Bar` + --> $DIR/method-resolution3.rs:11:5 | -LL | fn foo(x: bool) -> Bar { - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +LL | fn bar(self) {} + | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0391, E0599. -For more information about an error, try `rustc --explain E0391`. +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/impl-trait/method-resolution3.next.stderr b/tests/ui/impl-trait/method-resolution3.next.stderr index 53b77c620ba..87dd862ef8f 100644 --- a/tests/ui/impl-trait/method-resolution3.next.stderr +++ b/tests/ui/impl-trait/method-resolution3.next.stderr @@ -1,5 +1,5 @@ error[E0034]: multiple applicable items in scope - --> $DIR/method-resolution3.rs:22:11 + --> $DIR/method-resolution3.rs:21:11 | LL | x.bar(); | ^^^ multiple `bar` found diff --git a/tests/ui/impl-trait/method-resolution3.rs b/tests/ui/impl-trait/method-resolution3.rs index 8474e2da7db..8c47ef4fc75 100644 --- a/tests/ui/impl-trait/method-resolution3.rs +++ b/tests/ui/impl-trait/method-resolution3.rs @@ -16,12 +16,10 @@ impl Bar { } fn foo(x: bool) -> Bar { - //[current]~^ ERROR: cycle if x { let x = foo(false); x.bar(); - //[current]~^ ERROR: no method named `bar` - //[next]~^^ ERROR: multiple applicable items in scope + //~^ ERROR: multiple applicable items in scope } todo!() } diff --git a/tests/ui/impl-trait/method-resolution4.rs b/tests/ui/impl-trait/method-resolution4.rs index 3578db7cb55..91884eb59fd 100644 --- a/tests/ui/impl-trait/method-resolution4.rs +++ b/tests/ui/impl-trait/method-resolution4.rs @@ -4,9 +4,9 @@ //! variable, but get a type mismatch when comparing `&mut _` with //! `std::iter::Empty`. -//@[current] check-pass //@ revisions: current next //@[next] compile-flags: -Znext-solver +//@[current] check-pass fn foo(b: bool) -> impl Iterator { if b { diff --git a/tests/ui/methods/opaque_param_in_ufc.rs b/tests/ui/methods/opaque_param_in_ufc.rs index a4b27a0131f..b170e6805f6 100644 --- a/tests/ui/methods/opaque_param_in_ufc.rs +++ b/tests/ui/methods/opaque_param_in_ufc.rs @@ -1,4 +1,7 @@ #![feature(type_alias_impl_trait)] + +//@ check-pass + struct Foo(T); impl Foo { @@ -15,14 +18,11 @@ fn bar() -> Bar { impl Foo { fn foo() -> Bar { Self::method(); - //~^ ERROR: no function or associated item named `method` found for struct `Foo` Foo::::method(); - //~^ ERROR: no function or associated item named `method` found for struct `Foo` let x = Foo(bar()); Foo::method2(x); let x = Self(bar()); Self::method2(x); - //~^ ERROR: no function or associated item named `method2` found for struct `Foo` todo!() } } diff --git a/tests/ui/methods/opaque_param_in_ufc.stderr b/tests/ui/methods/opaque_param_in_ufc.stderr deleted file mode 100644 index 7e5bbbac8a9..00000000000 --- a/tests/ui/methods/opaque_param_in_ufc.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error[E0599]: no function or associated item named `method` found for struct `Foo` in the current scope - --> $DIR/opaque_param_in_ufc.rs:17:15 - | -LL | struct Foo(T); - | ------------- function or associated item `method` not found for this struct -... -LL | Self::method(); - | ^^^^^^ function or associated item not found in `Foo` - | - = note: the function or associated item was found for - - `Foo` - -error[E0599]: no function or associated item named `method` found for struct `Foo` in the current scope - --> $DIR/opaque_param_in_ufc.rs:19:21 - | -LL | struct Foo(T); - | ------------- function or associated item `method` not found for this struct -... -LL | Foo::::method(); - | ^^^^^^ function or associated item not found in `Foo` - | - = note: the function or associated item was found for - - `Foo` - -error[E0599]: no function or associated item named `method2` found for struct `Foo` in the current scope - --> $DIR/opaque_param_in_ufc.rs:24:15 - | -LL | struct Foo(T); - | ------------- function or associated item `method2` not found for this struct -... -LL | Self::method2(x); - | ^^^^^^^ function or associated item not found in `Foo` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution2.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution2.current.stderr deleted file mode 100644 index e68ea70a8ef..00000000000 --- a/tests/ui/type-alias-impl-trait/method_resolution2.current.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error[E0599]: no method named `foo` found for struct `Bar` in the current scope - --> $DIR/method_resolution2.rs:17:14 - | -LL | struct Bar(T); - | ------------- method `foo` not found for this struct -... -LL | self.foo() - | ^^^ method not found in `Bar` - | - = note: the method was found for - - `Bar` - -error[E0391]: cycle detected when computing type of opaque `Foo::{opaque#0}` - --> $DIR/method_resolution2.rs:10:12 - | -LL | type Foo = impl Sized; - | ^^^^^^^^^^ - | -note: ...which requires type-checking `::bar`... - --> $DIR/method_resolution2.rs:17:9 - | -LL | self.foo() - | ^^^^ - = note: ...which requires evaluating trait selection obligation `Bar: core::marker::Unpin`... - = note: ...which again requires computing type of opaque `Foo::{opaque#0}`, completing the cycle -note: cycle used when computing type of `Foo::{opaque#0}` - --> $DIR/method_resolution2.rs:10:12 - | -LL | type Foo = impl Sized; - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0391, E0599. -For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution2.rs b/tests/ui/type-alias-impl-trait/method_resolution2.rs index d252f8640d4..f69661db799 100644 --- a/tests/ui/type-alias-impl-trait/method_resolution2.rs +++ b/tests/ui/type-alias-impl-trait/method_resolution2.rs @@ -1,21 +1,19 @@ -//! Check that we do not unify `Bar` with `Bar`, even though the +//! Check that we do unify `Bar` with `Bar`, as the //! `foo` method call can be resolved unambiguously by doing so. //@ revisions: current next //@[next] compile-flags: -Znext-solver -//@[next] check-pass +//@ check-pass #![feature(type_alias_impl_trait)] type Foo = impl Sized; -//[current]~^ ERROR: cycle struct Bar(T); impl Bar { fn bar(self) { self.foo() - //[current]~^ ERROR: no method named `foo` } } diff --git a/tests/ui/type-alias-impl-trait/method_resolution5.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution5.current.stderr deleted file mode 100644 index 193e6e14709..00000000000 --- a/tests/ui/type-alias-impl-trait/method_resolution5.current.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0599]: no method named `bar` found for struct `Bar` in the current scope - --> $DIR/method_resolution5.rs:25:14 - | -LL | struct Bar(T); - | ------------- method `bar` not found for this struct -... -LL | self.bar() - | ^^^ method not found in `Bar` - | - = note: the method was found for - - `Bar` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution5.rs b/tests/ui/type-alias-impl-trait/method_resolution5.rs index 69335c9dede..64355e4560d 100644 --- a/tests/ui/type-alias-impl-trait/method_resolution5.rs +++ b/tests/ui/type-alias-impl-trait/method_resolution5.rs @@ -3,7 +3,7 @@ //@ revisions: current next //@[next] compile-flags: -Znext-solver -//@[next] check-pass +//@ check-pass #![feature(type_alias_impl_trait)] @@ -23,7 +23,6 @@ impl Bar { Foo:, { self.bar() - //[current]~^ ERROR: no method named `bar` } } -- cgit 1.4.1-3-g733a5 From 9314831b456b3f17c0849173436531d7d92b2231 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Jun 2024 11:30:23 +0200 Subject: Implement `CompletedProcess::assert_stdout_contains` and improve error output --- src/tools/run-make-support/src/command.rs | 10 ++++++++-- src/tools/run-make-support/src/lib.rs | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index d689dc2f979..5ee58e4e7a9 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -6,7 +6,7 @@ use std::path::Path; use std::process::{Command as StdCommand, ExitStatus, Output, Stdio}; use crate::drop_bomb::DropBomb; -use crate::{assert_not_contains, handle_failed_output}; +use crate::{assert_contains, assert_not_contains, handle_failed_output}; /// This is a custom command wrapper that simplifies working with commands and makes it easier to /// ensure that we check the exit status of executed processes. @@ -167,6 +167,12 @@ impl CompletedProcess { self } + #[track_caller] + pub fn assert_stdout_contains>(self, needle: S) -> Self { + assert_contains(&self.stdout_utf8(), needle.as_ref()); + self + } + #[track_caller] pub fn assert_stdout_not_contains>(&self, needle: S) -> &Self { assert_not_contains(&self.stdout_utf8(), needle.as_ref()); @@ -182,7 +188,7 @@ impl CompletedProcess { #[track_caller] pub fn assert_stderr_contains>(&self, needle: S) -> &Self { - assert!(self.stderr_utf8().contains(needle.as_ref())); + assert_contains(&self.stderr_utf8(), needle.as_ref()); self } diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 0238255a53f..8bb6a8d51d0 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -315,6 +315,18 @@ pub fn read_dir(dir: impl AsRef, callback: F) { } } +/// Check that `haystack` contains `needle`. Panic otherwise. +#[track_caller] +pub fn assert_contains(haystack: &str, needle: &str) { + if !haystack.contains(needle) { + eprintln!("=== HAYSTACK ==="); + eprintln!("{}", haystack); + eprintln!("=== NEEDLE ==="); + eprintln!("{}", needle); + panic!("needle was not found in haystack"); + } +} + /// Check that `haystack` does not contain `needle`. Panic otherwise. #[track_caller] pub fn assert_not_contains(haystack: &str, needle: &str) { -- cgit 1.4.1-3-g733a5 From 96f9fe5488e74f8b0f75c993ffbcca2c14ba9d01 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Jun 2024 11:21:25 +0200 Subject: Migrate `run-make/allow-non-lint-warnings-cmdline` to `rmake.rs` --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/allow-non-lint-warnings-cmdline/Makefile | 12 ------------ tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs | 8 ++++++++ 3 files changed, 8 insertions(+), 13 deletions(-) delete mode 100644 tests/run-make/allow-non-lint-warnings-cmdline/Makefile create mode 100644 tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 37da5d9c88d..280420d022d 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,5 +1,4 @@ run-make/allocator-shim-circular-deps/Makefile -run-make/allow-non-lint-warnings-cmdline/Makefile run-make/archive-duplicate-names/Makefile run-make/atomic-lock-free/Makefile run-make/branch-protection-check-IBT/Makefile diff --git a/tests/run-make/allow-non-lint-warnings-cmdline/Makefile b/tests/run-make/allow-non-lint-warnings-cmdline/Makefile deleted file mode 100644 index 78b9a7b9898..00000000000 --- a/tests/run-make/allow-non-lint-warnings-cmdline/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Test that -A warnings makes the 'empty trait list for derive' warning go away -OUT=$(shell $(RUSTC) foo.rs -A warnings 2>&1 | grep "warning" ) - -all: foo - test -z '$(OUT)' - -# This is just to make sure the above command actually succeeds -foo: - $(RUSTC) foo.rs -A warnings diff --git a/tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs b/tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs new file mode 100644 index 00000000000..3866ed3f5be --- /dev/null +++ b/tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs @@ -0,0 +1,8 @@ +// Test that -A warnings makes the 'empty trait list for derive' warning go away. + +use run_make_support::rustc; + +fn main() { + let output = rustc().input("foo.rs").arg("-Awarnings").run(); + output.assert_stderr_not_contains("warning"); +} -- cgit 1.4.1-3-g733a5 From eca8d209d9c75ed0ba7ce434d62d9460d42271f5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Jun 2024 12:52:05 +0200 Subject: Make `run-make/allow-non-lint-warnings-cmdline` into a ui test --- tests/run-make/allow-non-lint-warnings-cmdline/foo.rs | 5 ----- tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs | 8 -------- tests/ui/allow-non-lint-warnings.rs | 8 ++++++++ 3 files changed, 8 insertions(+), 13 deletions(-) delete mode 100644 tests/run-make/allow-non-lint-warnings-cmdline/foo.rs delete mode 100644 tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs create mode 100644 tests/ui/allow-non-lint-warnings.rs diff --git a/tests/run-make/allow-non-lint-warnings-cmdline/foo.rs b/tests/run-make/allow-non-lint-warnings-cmdline/foo.rs deleted file mode 100644 index 02e8ccabf79..00000000000 --- a/tests/run-make/allow-non-lint-warnings-cmdline/foo.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[derive()] -#[derive(Copy, Clone)] -pub struct Foo; - -pub fn main() {} diff --git a/tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs b/tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs deleted file mode 100644 index 3866ed3f5be..00000000000 --- a/tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Test that -A warnings makes the 'empty trait list for derive' warning go away. - -use run_make_support::rustc; - -fn main() { - let output = rustc().input("foo.rs").arg("-Awarnings").run(); - output.assert_stderr_not_contains("warning"); -} diff --git a/tests/ui/allow-non-lint-warnings.rs b/tests/ui/allow-non-lint-warnings.rs new file mode 100644 index 00000000000..f8f5a78ebff --- /dev/null +++ b/tests/ui/allow-non-lint-warnings.rs @@ -0,0 +1,8 @@ +//@ compile-flags: -Awarnings +//@ check-pass + +#[derive()] +#[derive(Copy, Clone)] +pub struct Foo; + +pub fn main() {} -- cgit 1.4.1-3-g733a5 From 9bff23005dc8cfca8fab4e5edaaf7d910b6c10f3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 11 Jun 2024 14:05:30 +0200 Subject: Allow to bless diff tests --- src/tools/run-make-support/src/diff/mod.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs index 105cdbc7b32..d0be57ca9d7 100644 --- a/src/tools/run-make-support/src/diff/mod.rs +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -1,6 +1,6 @@ use regex::Regex; use similar::TextDiff; -use std::path::Path; +use std::path::{Path, PathBuf}; use crate::drop_bomb::DropBomb; @@ -17,6 +17,7 @@ pub fn diff() -> Diff { pub struct Diff { expected: Option, expected_name: Option, + expected_file: Option, actual: Option, actual_name: Option, normalizers: Vec<(String, String)>, @@ -30,6 +31,7 @@ impl Diff { Self { expected: None, expected_name: None, + expected_file: None, actual: None, actual_name: None, normalizers: Vec::new(), @@ -43,6 +45,7 @@ impl Diff { let content = std::fs::read_to_string(path).expect("failed to read file"); let name = path.to_string_lossy().to_string(); + self.expected_file = Some(path.into()); self.expected = Some(content); self.expected_name = Some(name); self @@ -104,6 +107,15 @@ impl Diff { .to_string(); if !output.is_empty() { + // If we can bless (meaning we have a file to write into and the `RUSTC_BLESS_TEST` + // environment variable set), then we write into the file and return. + if let Some(ref expected_file) = self.expected_file { + if std::env::var("RUSTC_BLESS_TEST").is_ok() { + println!("Blessing `{}`", expected_file.display()); + std::fs::write(expected_file, actual).unwrap(); + return; + } + } panic!( "test failed: `{}` is different from `{}`\n\n{}", expected_name, actual_name, output -- cgit 1.4.1-3-g733a5 From be7b587cd13af17bd23dd8e38182c454df23e278 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 11 Jun 2024 14:05:55 +0200 Subject: Migrate `run-make/const_fn_mir` to `rmake.rs` --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/const_fn_mir/Makefile | 6 ------ tests/run-make/const_fn_mir/rmake.rs | 8 ++++++++ 3 files changed, 8 insertions(+), 7 deletions(-) delete mode 100644 tests/run-make/const_fn_mir/Makefile create mode 100644 tests/run-make/const_fn_mir/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 37da5d9c88d..14d7bfe9ad4 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -18,7 +18,6 @@ run-make/compiler-lookup-paths-2/Makefile run-make/compiler-lookup-paths/Makefile run-make/compiler-rt-works-on-mingw/Makefile run-make/compressed-debuginfo/Makefile -run-make/const_fn_mir/Makefile run-make/crate-hash-rustc-version/Makefile run-make/crate-name-priority/Makefile run-make/cross-lang-lto-clang/Makefile diff --git a/tests/run-make/const_fn_mir/Makefile b/tests/run-make/const_fn_mir/Makefile deleted file mode 100644 index 3399446130d..00000000000 --- a/tests/run-make/const_fn_mir/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# needs-unwind -Cpanic=abort gives different MIR output -include ../tools.mk - -all: - $(RUSTC) main.rs --emit=mir -o "$(TMPDIR)"/dump.mir - $(RUSTC_TEST_OP) "$(TMPDIR)"/dump.mir dump.mir diff --git a/tests/run-make/const_fn_mir/rmake.rs b/tests/run-make/const_fn_mir/rmake.rs new file mode 100644 index 00000000000..a4cc4299b1b --- /dev/null +++ b/tests/run-make/const_fn_mir/rmake.rs @@ -0,0 +1,8 @@ +// The `needs-unwind -Cpanic=abort` gives a different MIR output. + +use run_make_support::{cwd, diff, rustc}; + +fn main() { + rustc().input("main.rs").emit("mir").output("dump-actual.mir").run(); + diff().expected_file("dump.mir").actual_file("dump-actual.mir").run(); +} -- cgit 1.4.1-3-g733a5 From 58e3ac0877bc5daf53e42383fc51b8c8e2d2a7bb Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 13 Jun 2024 15:06:34 +0300 Subject: extend the check for LLVM build We don't build LLVM when using the precompiled version from the CI builder. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/sanity.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index b5f17b9f54e..da80f10b7dd 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -137,19 +137,20 @@ pub fn check(build: &mut Build) { } // We need cmake, but only if we're actually building LLVM or sanitizers. - let building_llvm = build - .hosts - .iter() - .map(|host| { - build.config.llvm_enabled(*host) - && build - .config - .target_config - .get(host) - .map(|config| config.llvm_config.is_none()) - .unwrap_or(true) - }) - .any(|build_llvm_ourselves| build_llvm_ourselves); + let building_llvm = !build.config.llvm_from_ci + && build + .hosts + .iter() + .map(|host| { + build.config.llvm_enabled(*host) + && build + .config + .target_config + .get(host) + .map(|config| config.llvm_config.is_none()) + .unwrap_or(true) + }) + .any(|build_llvm_ourselves| build_llvm_ourselves); let need_cmake = building_llvm || build.config.any_sanitizers_to_build(); if need_cmake && cmd_finder.maybe_have("cmake").is_none() { -- cgit 1.4.1-3-g733a5 From ea98e42bfd7e3723a68cb2dd6f6ac4a4866a400e Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Jun 2024 14:43:16 +0200 Subject: rebase blessing --- compiler/rustc_hir_typeck/src/fallback.rs | 2 +- .../never-type-fallback-breaking.e2021.stderr | 23 ++++++++++++++++++++++ .../never-type-fallback-breaking.e2024.stderr | 6 +++--- tests/ui/editions/never-type-fallback-breaking.rs | 4 ++++ 4 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 tests/ui/editions/never-type-fallback-breaking.e2021.stderr diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index dbc329a12bf..b7937f458b3 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -477,7 +477,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { behavior: DivergingFallbackBehavior, diverging_vids: &[ty::TyVid], ) { - let DivergingFallbackBehavior::FallbackToUnit = behavior else { return }; + let DivergingFallbackBehavior::ToUnit = behavior else { return }; // Fallback happens if and only if there are diverging variables if diverging_vids.is_empty() { diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr new file mode 100644 index 00000000000..92c233a0d9c --- /dev/null +++ b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr @@ -0,0 +1,23 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/never-type-fallback-breaking.rs:15:1 + | +LL | fn m() { + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: this function depends on never type fallback being `()` + --> $DIR/never-type-fallback-breaking.rs:27:1 + | +LL | fn q() -> Option<()> { + | ^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly + +warning: 2 warnings emitted + diff --git a/tests/ui/editions/never-type-fallback-breaking.e2024.stderr b/tests/ui/editions/never-type-fallback-breaking.e2024.stderr index e9a8882eb6c..461e4ae0bdf 100644 --- a/tests/ui/editions/never-type-fallback-breaking.e2024.stderr +++ b/tests/ui/editions/never-type-fallback-breaking.e2024.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `!: Default` is not satisfied - --> $DIR/never-type-fallback-breaking.rs:17:17 + --> $DIR/never-type-fallback-breaking.rs:19:17 | LL | true => Default::default(), | ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `!` @@ -8,7 +8,7 @@ LL | true => Default::default(), = help: did you intend to use the type `()` here instead? error[E0277]: the trait bound `!: Default` is not satisfied - --> $DIR/never-type-fallback-breaking.rs:30:5 + --> $DIR/never-type-fallback-breaking.rs:34:5 | LL | deserialize()?; | ^^^^^^^^^^^^^ the trait `Default` is not implemented for `!` @@ -16,7 +16,7 @@ LL | deserialize()?; = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information) = help: did you intend to use the type `()` here instead? note: required by a bound in `deserialize` - --> $DIR/never-type-fallback-breaking.rs:26:23 + --> $DIR/never-type-fallback-breaking.rs:30:23 | LL | fn deserialize() -> Option { | ^^^^^^^ required by this bound in `deserialize` diff --git a/tests/ui/editions/never-type-fallback-breaking.rs b/tests/ui/editions/never-type-fallback-breaking.rs index 7dfa4702807..7b4a1b1de04 100644 --- a/tests/ui/editions/never-type-fallback-breaking.rs +++ b/tests/ui/editions/never-type-fallback-breaking.rs @@ -13,6 +13,8 @@ fn main() { } fn m() { + //[e2021]~^ this function depends on never type fallback being `()` + //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! let x = match true { true => Default::default(), //[e2024]~^ error: the trait bound `!: Default` is not satisfied @@ -23,6 +25,8 @@ fn m() { } fn q() -> Option<()> { + //[e2021]~^ this function depends on never type fallback being `()` + //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! fn deserialize() -> Option { Some(T::default()) } -- cgit 1.4.1-3-g733a5 From 0cc099b8a205d838f8b67996e9a75c2217574fc0 Mon Sep 17 00:00:00 2001 From: Florian Sextl Date: Thu, 13 Jun 2024 14:45:45 +0200 Subject: fix wrong assert_unsafe_precondition message for core::ptr::copy --- library/core/src/intrinsics.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index cd3534ecb12..6b5054a9f06 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -3043,8 +3043,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { unsafe { ub_checks::assert_unsafe_precondition!( check_language_ub, - "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \ - and the specified memory ranges do not overlap", + "ptr::copy requires that both pointer arguments are aligned and non-null", ( src: *const () = src as *const (), dst: *mut () = dst as *mut (), -- cgit 1.4.1-3-g733a5 From 5f4111f781abcd8faca117e18e25c633f9effdcc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Jun 2024 11:39:45 +0200 Subject: Update run-make-support/diff to new `fs_wrapper` API --- src/tools/run-make-support/src/diff/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs index d0be57ca9d7..3e0bdc1c6f6 100644 --- a/src/tools/run-make-support/src/diff/mod.rs +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -3,6 +3,7 @@ use similar::TextDiff; use std::path::{Path, PathBuf}; use crate::drop_bomb::DropBomb; +use crate::fs_wrapper; #[cfg(test)] mod tests; @@ -42,7 +43,7 @@ impl Diff { /// Specify the expected output for the diff from a file. pub fn expected_file>(&mut self, path: P) -> &mut Self { let path = path.as_ref(); - let content = std::fs::read_to_string(path).expect("failed to read file"); + let content = fs_wrapper::read_to_string(path); let name = path.to_string_lossy().to_string(); self.expected_file = Some(path.into()); @@ -61,10 +62,7 @@ impl Diff { /// Specify the actual output for the diff from a file. pub fn actual_file>(&mut self, path: P) -> &mut Self { let path = path.as_ref(); - let content = match std::fs::read_to_string(path) { - Ok(c) => c, - Err(e) => panic!("failed to read `{}`: {:?}", path.display(), e), - }; + let content = fs_wrapper::read_to_string(path); let name = path.to_string_lossy().to_string(); self.actual = Some(content); @@ -112,7 +110,7 @@ impl Diff { if let Some(ref expected_file) = self.expected_file { if std::env::var("RUSTC_BLESS_TEST").is_ok() { println!("Blessing `{}`", expected_file.display()); - std::fs::write(expected_file, actual).unwrap(); + fs_wrapper::write(expected_file, actual); return; } } -- cgit 1.4.1-3-g733a5 From 93ee07c75603ad5492cf789eee89fd61ecc9d3ad Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 11:15:57 -0400 Subject: Check that alias-relate terms are WF if reporting an error in alias-relate --- .../rustc_trait_selection/src/solve/fulfill.rs | 24 ++++++++ .../defaults-unsound-62211-1.next.stderr | 21 ++----- .../associated-types/defaults-unsound-62211-1.rs | 1 - .../defaults-unsound-62211-2.next.stderr | 21 ++----- .../associated-types/defaults-unsound-62211-2.rs | 1 - tests/ui/associated-types/issue-54108.next.stderr | 21 ++----- tests/ui/associated-types/issue-54108.rs | 1 - tests/ui/traits/next-solver/coroutine.fail.stderr | 47 +-------------- tests/ui/traits/next-solver/coroutine.rs | 2 - tests/ui/traits/next-solver/fn-trait.rs | 4 -- tests/ui/traits/next-solver/fn-trait.stderr | 67 ++-------------------- 11 files changed, 43 insertions(+), 167 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3c3d5dfe79c..519a24f6975 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -515,6 +515,30 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?; } + // alias-relate may fail because the lhs or rhs can't be normalized, + // and therefore is treated as rigid. + if let Some(ty::PredicateKind::AliasRelate(lhs, rhs, _)) = pred_kind.no_bound_vars() { + if let Some(obligation) = goal + .infcx() + .visit_proof_tree( + goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(lhs.into())), + self, + ) + .break_value() + { + return ControlFlow::Break(obligation); + } else if let Some(obligation) = goal + .infcx() + .visit_proof_tree( + goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(rhs.into())), + self, + ) + .break_value() + { + return ControlFlow::Break(obligation); + } + } + ControlFlow::Break(self.obligation.clone()) } } diff --git a/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr b/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr index 0fc1bb0b00f..010f51df15a 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr @@ -31,18 +31,6 @@ help: consider further restricting `Self` LL | trait UncheckedCopy: Sized + AddAssign<&'static str> { | +++++++++++++++++++++++++ -error[E0271]: type mismatch resolving `::Target == str` - --> $DIR/defaults-unsound-62211-1.rs:24:96 - | -LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^ types differ - | -note: required by a bound in `UncheckedCopy::Output` - --> $DIR/defaults-unsound-62211-1.rs:24:31 - | -LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output` - error[E0277]: the trait bound `Self: Deref` is not satisfied --> $DIR/defaults-unsound-62211-1.rs:24:96 | @@ -50,10 +38,10 @@ LL | type Output: Copy + Deref + AddAssign<&'static str> + Fro | ^^^^ the trait `Deref` is not implemented for `Self` | note: required by a bound in `UncheckedCopy::Output` - --> $DIR/defaults-unsound-62211-1.rs:24:25 + --> $DIR/defaults-unsound-62211-1.rs:24:31 | LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output` + | ^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output` help: consider further restricting `Self` | LL | trait UncheckedCopy: Sized + Deref { @@ -75,7 +63,6 @@ help: consider further restricting `Self` LL | trait UncheckedCopy: Sized + Copy { | ++++++ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/defaults-unsound-62211-1.rs b/tests/ui/associated-types/defaults-unsound-62211-1.rs index f054611ed78..124bac0ea72 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-1.rs +++ b/tests/ui/associated-types/defaults-unsound-62211-1.rs @@ -26,7 +26,6 @@ trait UncheckedCopy: Sized { //~| ERROR the trait bound `Self: Deref` is not satisfied //~| ERROR cannot add-assign `&'static str` to `Self` //~| ERROR `Self` doesn't implement `std::fmt::Display` - //[next]~| ERROR type mismatch resolving `::Target == str` // We said the Output type was Copy, so we can Copy it freely! fn unchecked_copy(other: &Self::Output) -> Self::Output { diff --git a/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr b/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr index 751352d7c16..93478946570 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr @@ -31,18 +31,6 @@ help: consider further restricting `Self` LL | trait UncheckedCopy: Sized + AddAssign<&'static str> { | +++++++++++++++++++++++++ -error[E0271]: type mismatch resolving `::Target == str` - --> $DIR/defaults-unsound-62211-2.rs:24:96 - | -LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^ types differ - | -note: required by a bound in `UncheckedCopy::Output` - --> $DIR/defaults-unsound-62211-2.rs:24:31 - | -LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output` - error[E0277]: the trait bound `Self: Deref` is not satisfied --> $DIR/defaults-unsound-62211-2.rs:24:96 | @@ -50,10 +38,10 @@ LL | type Output: Copy + Deref + AddAssign<&'static str> + Fro | ^^^^ the trait `Deref` is not implemented for `Self` | note: required by a bound in `UncheckedCopy::Output` - --> $DIR/defaults-unsound-62211-2.rs:24:25 + --> $DIR/defaults-unsound-62211-2.rs:24:31 | LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output` + | ^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output` help: consider further restricting `Self` | LL | trait UncheckedCopy: Sized + Deref { @@ -75,7 +63,6 @@ help: consider further restricting `Self` LL | trait UncheckedCopy: Sized + Copy { | ++++++ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/defaults-unsound-62211-2.rs b/tests/ui/associated-types/defaults-unsound-62211-2.rs index 956f14df0d5..998c39b5bad 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-2.rs +++ b/tests/ui/associated-types/defaults-unsound-62211-2.rs @@ -26,7 +26,6 @@ trait UncheckedCopy: Sized { //~| ERROR the trait bound `Self: Deref` is not satisfied //~| ERROR cannot add-assign `&'static str` to `Self` //~| ERROR `Self` doesn't implement `std::fmt::Display` - //[next]~| ERROR type mismatch resolving `::Target == str` // We said the Output type was Copy, so we can Copy it freely! fn unchecked_copy(other: &Self::Output) -> Self::Output { diff --git a/tests/ui/associated-types/issue-54108.next.stderr b/tests/ui/associated-types/issue-54108.next.stderr index 9f6f00e7ca8..5e2fa551afe 100644 --- a/tests/ui/associated-types/issue-54108.next.stderr +++ b/tests/ui/associated-types/issue-54108.next.stderr @@ -1,15 +1,3 @@ -error[E0271]: type mismatch resolving `<::ActualSize as Add>::Output == ::ActualSize` - --> $DIR/issue-54108.rs:23:17 - | -LL | type Size = ::ActualSize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ - | -note: required by a bound in `Encoder::Size` - --> $DIR/issue-54108.rs:8:20 - | -LL | type Size: Add; - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `Encoder::Size` - error[E0277]: cannot add `::ActualSize` to `::ActualSize` --> $DIR/issue-54108.rs:23:17 | @@ -18,16 +6,15 @@ LL | type Size = ::ActualSize; | = help: the trait `Add` is not implemented for `::ActualSize` note: required by a bound in `Encoder::Size` - --> $DIR/issue-54108.rs:8:16 + --> $DIR/issue-54108.rs:8:20 | LL | type Size: Add; - | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Encoder::Size` + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `Encoder::Size` help: consider further restricting the associated type | LL | T: SubEncoder, ::ActualSize: Add | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/issue-54108.rs b/tests/ui/associated-types/issue-54108.rs index 7c652fd7f49..bcc54f33362 100644 --- a/tests/ui/associated-types/issue-54108.rs +++ b/tests/ui/associated-types/issue-54108.rs @@ -22,7 +22,6 @@ where { type Size = ::ActualSize; //~^ ERROR: cannot add `::ActualSize` to `::ActualSize` - //[next]~| ERROR type mismatch resolving `<::ActualSize as Add>::Output == ::ActualSize` fn foo(&self) -> Self::Size { self.bar() + self.bar() diff --git a/tests/ui/traits/next-solver/coroutine.fail.stderr b/tests/ui/traits/next-solver/coroutine.fail.stderr index e880d05a4dd..8c263e8644b 100644 --- a/tests/ui/traits/next-solver/coroutine.fail.stderr +++ b/tests/ui/traits/next-solver/coroutine.fail.stderr @@ -6,8 +6,6 @@ LL | needs_coroutine( LL | #[coroutine] LL | / || { LL | | -LL | | -LL | | LL | | yield (); LL | | }, | |_________^ the trait `Coroutine` is not implemented for `{coroutine@$DIR/coroutine.rs:20:9: 20:11}` @@ -18,47 +16,6 @@ note: required by a bound in `needs_coroutine` LL | fn needs_coroutine(_: impl Coroutine) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `needs_coroutine` -error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:20:9: 20:11} as Coroutine>::Yield == B` - --> $DIR/coroutine.rs:20:9 - | -LL | needs_coroutine( - | --------------- required by a bound introduced by this call -LL | #[coroutine] -LL | / || { -LL | | -LL | | -LL | | -LL | | yield (); -LL | | }, - | |_________^ types differ - | -note: required by a bound in `needs_coroutine` - --> $DIR/coroutine.rs:14:41 - | -LL | fn needs_coroutine(_: impl Coroutine) {} - | ^^^^^^^^^ required by this bound in `needs_coroutine` - -error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:20:9: 20:11} as Coroutine>::Return == C` - --> $DIR/coroutine.rs:20:9 - | -LL | needs_coroutine( - | --------------- required by a bound introduced by this call -LL | #[coroutine] -LL | / || { -LL | | -LL | | -LL | | -LL | | yield (); -LL | | }, - | |_________^ types differ - | -note: required by a bound in `needs_coroutine` - --> $DIR/coroutine.rs:14:52 - | -LL | fn needs_coroutine(_: impl Coroutine) {} - | ^^^^^^^^^^ required by this bound in `needs_coroutine` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/coroutine.rs b/tests/ui/traits/next-solver/coroutine.rs index 1882a62cf29..bdc34842f6d 100644 --- a/tests/ui/traits/next-solver/coroutine.rs +++ b/tests/ui/traits/next-solver/coroutine.rs @@ -19,8 +19,6 @@ fn main() { #[coroutine] || { //[fail]~^ ERROR Coroutine` is not satisfied - //[fail]~| ERROR as Coroutine>::Yield == B` - //[fail]~| ERROR as Coroutine>::Return == C` yield (); }, ); diff --git a/tests/ui/traits/next-solver/fn-trait.rs b/tests/ui/traits/next-solver/fn-trait.rs index 6d6ae9260b0..7994dd3052c 100644 --- a/tests/ui/traits/next-solver/fn-trait.rs +++ b/tests/ui/traits/next-solver/fn-trait.rs @@ -19,14 +19,10 @@ fn main() { require_fn(f as fn() -> i32); require_fn(f as unsafe fn() -> i32); //~^ ERROR: expected a `Fn()` closure, found `unsafe fn() -> i32` - //~| ERROR: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` require_fn(g); //~^ ERROR: expected a `Fn()` closure, found `extern "C" fn() -> i32 {g}` - //~| ERROR: type mismatch resolving ` i32 {g} as FnOnce<()>>::Output == i32` require_fn(g as extern "C" fn() -> i32); //~^ ERROR: expected a `Fn()` closure, found `extern "C" fn() -> i32` - //~| ERROR: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` require_fn(h); //~^ ERROR: expected a `Fn()` closure, found `unsafe fn() -> i32 {h}` - //~| ERROR: type mismatch resolving ` i32 {h} as FnOnce<()>>::Output == i32` } diff --git a/tests/ui/traits/next-solver/fn-trait.stderr b/tests/ui/traits/next-solver/fn-trait.stderr index 86d97cb16b3..00243fd9059 100644 --- a/tests/ui/traits/next-solver/fn-trait.stderr +++ b/tests/ui/traits/next-solver/fn-trait.stderr @@ -15,22 +15,8 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^^^^^^^^^ required by this bound in `require_fn` -error[E0271]: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` - --> $DIR/fn-trait.rs:20:16 - | -LL | require_fn(f as unsafe fn() -> i32); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^ types differ - | | - | required by a bound introduced by this call - | -note: required by a bound in `require_fn` - --> $DIR/fn-trait.rs:3:31 - | -LL | fn require_fn(_: impl Fn() -> i32) {} - | ^^^ required by this bound in `require_fn` - error[E0277]: expected a `Fn()` closure, found `extern "C" fn() -> i32 {g}` - --> $DIR/fn-trait.rs:23:16 + --> $DIR/fn-trait.rs:22:16 | LL | require_fn(g); | ---------- ^ expected an `Fn()` closure, found `extern "C" fn() -> i32 {g}` @@ -45,22 +31,8 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^^^^^^^^^ required by this bound in `require_fn` -error[E0271]: type mismatch resolving ` i32 {g} as FnOnce<()>>::Output == i32` - --> $DIR/fn-trait.rs:23:16 - | -LL | require_fn(g); - | ---------- ^ types differ - | | - | required by a bound introduced by this call - | -note: required by a bound in `require_fn` - --> $DIR/fn-trait.rs:3:31 - | -LL | fn require_fn(_: impl Fn() -> i32) {} - | ^^^ required by this bound in `require_fn` - error[E0277]: expected a `Fn()` closure, found `extern "C" fn() -> i32` - --> $DIR/fn-trait.rs:26:16 + --> $DIR/fn-trait.rs:24:16 | LL | require_fn(g as extern "C" fn() -> i32); | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn()` closure, found `extern "C" fn() -> i32` @@ -75,22 +47,8 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^^^^^^^^^ required by this bound in `require_fn` -error[E0271]: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` - --> $DIR/fn-trait.rs:26:16 - | -LL | require_fn(g as extern "C" fn() -> i32); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ - | | - | required by a bound introduced by this call - | -note: required by a bound in `require_fn` - --> $DIR/fn-trait.rs:3:31 - | -LL | fn require_fn(_: impl Fn() -> i32) {} - | ^^^ required by this bound in `require_fn` - error[E0277]: expected a `Fn()` closure, found `unsafe fn() -> i32 {h}` - --> $DIR/fn-trait.rs:29:16 + --> $DIR/fn-trait.rs:26:16 | LL | require_fn(h); | ---------- ^ call the function in a closure: `|| unsafe { /* code */ }` @@ -106,21 +64,6 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^^^^^^^^^ required by this bound in `require_fn` -error[E0271]: type mismatch resolving ` i32 {h} as FnOnce<()>>::Output == i32` - --> $DIR/fn-trait.rs:29:16 - | -LL | require_fn(h); - | ---------- ^ types differ - | | - | required by a bound introduced by this call - | -note: required by a bound in `require_fn` - --> $DIR/fn-trait.rs:3:31 - | -LL | fn require_fn(_: impl Fn() -> i32) {} - | ^^^ required by this bound in `require_fn` - -error: aborting due to 8 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. -- cgit 1.4.1-3-g733a5 From d3812ac95fbf67725f1d13392a611b776b1a2608 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 18:15:33 -0400 Subject: LangItem-ify Coroutine trait in solvers --- compiler/rustc_hir/src/lang_items.rs | 4 +++- compiler/rustc_span/src/symbol.rs | 2 ++ .../rustc_trait_selection/src/solve/normalizes_to/mod.rs | 13 ++++++++----- compiler/rustc_trait_selection/src/traits/project.rs | 9 +++++---- library/core/src/ops/coroutine.rs | 2 ++ 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c3ccba487ed..69461957f80 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -244,7 +244,9 @@ language_item_table! { AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0); CoroutineState, sym::coroutine_state, coroutine_state, Target::Enum, GenericRequirement::None; - Coroutine, sym::coroutine, coroutine_trait, Target::Trait, GenericRequirement::Minimum(1); + Coroutine, sym::coroutine, coroutine_trait, Target::Trait, GenericRequirement::Exact(1); + CoroutineReturn, sym::coroutine_return, coroutine_return, Target::AssocTy, GenericRequirement::Exact(1); + CoroutineYield, sym::coroutine_yield, coroutine_yield, Target::AssocTy, GenericRequirement::Exact(1); CoroutineResume, sym::coroutine_resume, coroutine_resume, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e245dfb9f5d..c89323b7f16 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -635,7 +635,9 @@ symbols! { coroutine, coroutine_clone, coroutine_resume, + coroutine_return, coroutine_state, + coroutine_yield, coroutines, cosf128, cosf16, diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 787f08a084e..50253d81528 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::NormalizesTo; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{TypeVisitableExt, Upcast}; use rustc_middle::{bug, span_bug}; -use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP}; +use rustc_span::{ErrorGuaranteed, DUMMY_SP}; mod anon_const; mod inherent; @@ -719,13 +719,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { let coroutine = args.as_coroutine(); - let name = tcx.associated_item(goal.predicate.def_id()).name; - let term = if name == sym::Return { + let lang_items = tcx.lang_items(); + let term = if Some(goal.predicate.def_id()) == lang_items.coroutine_return() { coroutine.return_ty().into() - } else if name == sym::Yield { + } else if Some(goal.predicate.def_id()) == lang_items.coroutine_yield() { coroutine.yield_ty().into() } else { - bug!("unexpected associated item `<{self_ty} as Coroutine>::{name}`") + bug!( + "unexpected associated item `<{self_ty} as Coroutine>::{}`", + tcx.item_name(goal.predicate.def_id()) + ) }; Self::probe_and_consider_implied_clause( diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 2c9cb79664b..32409e13842 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1373,15 +1373,16 @@ fn confirm_coroutine_candidate<'cx, 'tcx>( coroutine_sig, ); - let name = tcx.associated_item(obligation.predicate.def_id).name; - let ty = if name == sym::Return { + let lang_items = tcx.lang_items(); + let ty = if Some(obligation.predicate.def_id) == lang_items.coroutine_return() { return_ty - } else if name == sym::Yield { + } else if Some(obligation.predicate.def_id) == lang_items.coroutine_yield() { yield_ty } else { span_bug!( tcx.def_span(obligation.predicate.def_id), - "unexpected associated type: `Coroutine::{name}`" + "unexpected associated type: `Coroutine::{}`", + tcx.item_name(obligation.predicate.def_id), ); }; diff --git a/library/core/src/ops/coroutine.rs b/library/core/src/ops/coroutine.rs index 6a6c5db1ab1..753f14c6b85 100644 --- a/library/core/src/ops/coroutine.rs +++ b/library/core/src/ops/coroutine.rs @@ -76,6 +76,7 @@ pub trait Coroutine { /// values which are allowed to be returned each time a coroutine yields. /// For example an iterator-as-a-coroutine would likely have this type as /// `T`, the type being iterated over. + #[cfg_attr(not(bootstrap), lang = "coroutine_yield")] type Yield; /// The type of value this coroutine returns. @@ -84,6 +85,7 @@ pub trait Coroutine { /// `return` statement or implicitly as the last expression of a coroutine /// literal. For example futures would use this as `Result` as it /// represents a completed future. + #[cfg_attr(not(bootstrap), lang = "coroutine_return")] type Return; /// Resumes the execution of this coroutine. -- cgit 1.4.1-3-g733a5 From b79360ad16cf845d3beda5048f96d4460bd81b27 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 29 May 2024 20:15:56 -0400 Subject: Rework most of structural_traits to be Interner-agnostic --- compiler/rustc_infer/src/infer/mod.rs | 21 +- compiler/rustc_middle/src/ty/adt.rs | 17 ++ compiler/rustc_middle/src/ty/context.rs | 53 ++++- compiler/rustc_middle/src/ty/generic_args.rs | 2 + compiler/rustc_middle/src/ty/mod.rs | 2 + compiler/rustc_middle/src/ty/sty.rs | 4 + .../src/solve/assembly/structural_traits.rs | 217 +++++++++++---------- compiler/rustc_type_ir/src/infcx.rs | 41 +++- compiler/rustc_type_ir/src/inherent.rs | 80 +++++++- compiler/rustc_type_ir/src/interner.rs | 52 +++-- 10 files changed, 350 insertions(+), 139 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 32b50053b50..46f18bd77a0 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -44,7 +44,7 @@ use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid}; use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Symbol; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use snapshot::undo_log::InferCtxtUndoLogs; use std::cell::{Cell, RefCell}; use std::fmt; @@ -405,6 +405,25 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { } } } + + fn instantiate_binder_with_infer + Copy>( + &self, + value: ty::Binder<'tcx, T>, + ) -> T { + self.instantiate_binder_with_fresh_vars( + DUMMY_SP, + BoundRegionConversionTime::HigherRankedType, + value, + ) + } + + fn enter_forall + Copy, U>( + &self, + value: ty::Binder<'tcx, T>, + f: impl FnOnce(T) -> U, + ) -> U { + self.enter_forall(value, f) + } } /// See the `error_reporting` module for more details. diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 886dbd317af..a89ebe46c37 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -204,6 +204,23 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { fn def_id(self) -> DefId { self.did() } + + fn is_phantom_data(self) -> bool { + self.is_phantom_data() + } + + fn all_field_tys( + self, + tcx: TyCtxt<'tcx>, + ) -> ty::EarlyBinder<'tcx, impl Iterator>> { + ty::EarlyBinder::bind( + self.all_fields().map(move |field| tcx.type_of(field.did).skip_binder()), + ) + } + + fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option>> { + self.sized_constraint(tcx) + } } #[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 65d744239a6..98c60ffee12 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -154,7 +154,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type VariancesOf = &'tcx [ty::Variance]; - fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf { + fn variances_of(self, def_id: DefId) -> Self::VariancesOf { self.variances_of(def_id) } @@ -198,7 +198,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn trait_ref_and_own_args_for_alias( self, - def_id: Self::DefId, + def_id: DefId, args: Self::GenericArgs, ) -> (rustc_type_ir::TraitRef, Self::GenericArgsSlice) { assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); @@ -246,7 +246,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.mk_type_list_from_iter(args) } - fn parent(self, def_id: Self::DefId) -> Self::DefId { + fn parent(self, def_id: DefId) -> DefId { self.parent(def_id) } @@ -259,6 +259,49 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn features(self) -> Self::Features { self.features() } + + fn bound_coroutine_hidden_types( + self, + def_id: DefId, + ) -> impl Iterator>>> { + self.bound_coroutine_hidden_types(def_id) + } + + fn fn_sig(self, def_id: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> { + self.fn_sig(def_id) + } + + fn coroutine_movability(self, def_id: DefId) -> rustc_ast::Movability { + self.coroutine_movability(def_id) + } + + fn coroutine_for_closure(self, def_id: DefId) -> DefId { + self.coroutine_for_closure(def_id) + } + + fn generics_require_sized_self(self, def_id: DefId) -> bool { + self.generics_require_sized_self(def_id) + } + + fn item_bounds( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl Iterator>> { + self.item_bounds(def_id).map_bound(IntoIterator::into_iter) + } + + fn super_predicates_of( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl Iterator>> { + ty::EarlyBinder::bind( + self.super_predicates_of(def_id).instantiate_identity(self).predicates.into_iter(), + ) + } + + fn has_target_features(self, def_id: DefId) -> bool { + !self.codegen_fn_attrs(def_id).target_features.is_empty() + } } impl<'tcx> rustc_type_ir::inherent::Abi> for abi::Abi { @@ -281,6 +324,10 @@ impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_featu fn generic_const_exprs(self) -> bool { self.generic_const_exprs } + + fn coroutine_clone(self) -> bool { + self.coroutine_clone + } } type InternedSet<'tcx, T> = ShardedHashMap, ()>; diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 7fff3d01324..54c88e48614 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -41,6 +41,8 @@ pub struct GenericArg<'tcx> { marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>, } +impl<'tcx> rustc_type_ir::inherent::GenericArg> for GenericArg<'tcx> {} + impl<'tcx> rustc_type_ir::inherent::GenericArgs> for ty::GenericArgsRef<'tcx> { fn type_at(self, i: usize) -> Ty<'tcx> { self.type_at(i) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 83f8de6b6f9..c322c87bce4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -488,6 +488,8 @@ pub struct Term<'tcx> { marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>, } +impl<'tcx> rustc_type_ir::inherent::Term> for Term<'tcx> {} + impl<'tcx> rustc_type_ir::inherent::IntoKind for Term<'tcx> { type Kind = TermKind<'tcx>; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index ba9ed0d5b70..8308e537e5e 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -786,6 +786,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { tcx.types.bool } + fn new_u8(tcx: TyCtxt<'tcx>) -> Self { + tcx.types.u8 + } + fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferTy) -> Self { Ty::new_infer(tcx, infer) } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 98f98d9992d..c90b458d7b1 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -1,14 +1,13 @@ //! Code which is used by built-in goals that match "structurally", such a auto //! traits, `Copy`/`Clone`. + +use rustc_ast_ir::{Movability, Mutability}; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::LangItem; -use rustc_hir::{def_id::DefId, Movability, Mutability}; -use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::query::NoSolution; -use rustc_macros::{TypeFoldable, TypeVisitable}; -use rustc_middle::bug; -use rustc_middle::traits::solve::Goal; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, Upcast}; +use rustc_next_trait_solver::solve::{Goal, NoSolution}; +use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{self as ty, InferCtxtLike, Interner, Upcast}; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::solve::EvalCtxt; @@ -17,12 +16,15 @@ use crate::solve::EvalCtxt; // For types with an "existential" binder, i.e. coroutine witnesses, we also // instantiate the binder with placeholders eagerly. #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( - ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, - ty: Ty<'tcx>, -) -> Result>>, NoSolution> { +pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait< + Infcx: InferCtxtLike, + I: Interner, +>( + ecx: &EvalCtxt<'_, Infcx>, + ty: I::Ty, +) -> Result>, NoSolution> { let tcx = ecx.interner(); - match *ty.kind() { + match ty.kind() { ty::Uint(_) | ty::Int(_) | ty::Bool @@ -34,7 +36,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( | ty::Char => Ok(vec![]), // Treat `str` like it's defined as `struct str([u8]);` - ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, tcx.types.u8))]), + ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, Ty::new_u8(tcx)))]), ty::Dynamic(..) | ty::Param(..) @@ -43,7 +45,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( | ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) => { - bug!("unexpected type `{ty}`") + panic!("unexpected type `{ty:?}`") } ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => { @@ -56,7 +58,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - Ok(tys.iter().map(ty::Binder::dummy).collect()) + Ok(tys.into_iter().map(ty::Binder::dummy).collect()) } ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]), @@ -76,31 +78,36 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ty::CoroutineWitness(def_id, args) => Ok(ecx .interner() .bound_coroutine_hidden_types(def_id) - .map(|bty| bty.instantiate(tcx, args)) + .map(|bty| bty.instantiate(tcx, &args)) .collect()), // For `PhantomData`, we pass `T`. ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![ty::Binder::dummy(args.type_at(0))]), - ty::Adt(def, args) => { - Ok(def.all_fields().map(|f| ty::Binder::dummy(f.ty(tcx, args))).collect()) - } + ty::Adt(def, args) => Ok(def + .all_field_tys(tcx) + .iter_instantiated(tcx, &args) + .map(ty::Binder::dummy) + .collect()), ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, args))]) + Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, &args))]) } } } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( - ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, - ty: Ty<'tcx>, -) -> Result>>, NoSolution> { - match *ty.kind() { +pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait< + Infcx: InferCtxtLike, + I: Interner, +>( + ecx: &EvalCtxt<'_, Infcx>, + ty: I::Ty, +) -> Result>, NoSolution> { + match ty.kind() { // impl Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char, &mut? T, [T; N], dyn* Trait, ! // impl Sized for Coroutine, CoroutineWitness, Closure, CoroutineClosure ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) @@ -133,7 +140,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("unexpected type `{ty}`") + panic!("unexpected type `{ty:?}`") } // impl Sized for () @@ -151,7 +158,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( // if the ADT is sized for all possible args. ty::Adt(def, args) => { if let Some(sized_crit) = def.sized_constraint(ecx.interner()) { - Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), args))]) + Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), &args))]) } else { Ok(vec![]) } @@ -160,11 +167,14 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( - ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, - ty: Ty<'tcx>, -) -> Result>>, NoSolution> { - match *ty.kind() { +pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait< + Infcx: InferCtxtLike, + I: Interner, +>( + ecx: &EvalCtxt<'_, Infcx>, + ty: I::Ty, +) -> Result>, NoSolution> { + match ty.kind() { // impl Copy/Clone for FnDef, FnPtr ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]), @@ -196,11 +206,11 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("unexpected type `{ty}`") + panic!("unexpected type `{ty:?}`") } // impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone - ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()), + ty::Tuple(tys) => Ok(tys.into_iter().map(ty::Binder::dummy).collect()), // impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]), @@ -212,7 +222,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::Coroutine(def_id, args) => match ecx.interner().coroutine_movability(def_id) { Movability::Static => Err(NoSolution), Movability::Movable => { - if ecx.interner().features().coroutine_clone { + if ecx.interner().features().coroutine_clone() { let coroutine = args.as_coroutine(); Ok(vec![ ty::Binder::dummy(coroutine.tupled_upvars_ty()), @@ -228,27 +238,25 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::CoroutineWitness(def_id, args) => Ok(ecx .interner() .bound_coroutine_hidden_types(def_id) - .map(|bty| bty.instantiate(ecx.interner(), args)) + .map(|bty| bty.instantiate(ecx.interner(), &args)) .collect()), } } // Returns a binder of the tupled inputs types and output type from a builtin callable type. -pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( - tcx: TyCtxt<'tcx>, - self_ty: Ty<'tcx>, +pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable( + tcx: I, + self_ty: I::Ty, goal_kind: ty::ClosureKind, -) -> Result, Ty<'tcx>)>>, NoSolution> { - match *self_ty.kind() { +) -> Result>, NoSolution> { + match self_ty.kind() { // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. ty::FnDef(def_id, args) => { let sig = tcx.fn_sig(def_id); - if sig.skip_binder().is_fn_trait_compatible() - && tcx.codegen_fn_attrs(def_id).target_features.is_empty() - { + if sig.skip_binder().is_fn_trait_compatible() && !tcx.has_target_features(def_id) { Ok(Some( - sig.instantiate(tcx, args) - .map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output())), + sig.instantiate(tcx, &args) + .map_bound(|sig| (Ty::new_tup(tcx, &sig.inputs()), sig.output())), )) } else { Err(NoSolution) @@ -257,7 +265,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. ty::FnPtr(sig) => { if sig.is_fn_trait_compatible() { - Ok(Some(sig.map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output())))) + Ok(Some(sig.map_bound(|sig| (Ty::new_tup(tcx, &sig.inputs()), sig.output())))) } else { Err(NoSolution) } @@ -311,7 +319,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( tcx, goal_kind, // No captures by ref, so this doesn't matter. - tcx.lifetimes.re_static, + Region::new_static(tcx), def_id, args, sig, @@ -326,7 +334,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( coroutine_closure_to_ambiguous_coroutine( tcx, goal_kind, // No captures by ref, so this doesn't matter. - tcx.lifetimes.re_static, + Region::new_static(tcx), def_id, args, sig, @@ -362,22 +370,24 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("unexpected type `{self_ty}`") + panic!("unexpected type `{self_ty:?}`") } } } /// Relevant types for an async callable, including its inputs, output, /// and the return type you get from awaiting the output. -#[derive(Copy, Clone, Debug, TypeVisitable, TypeFoldable)] -pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> { - pub tupled_inputs_ty: Ty<'tcx>, +#[derive(derivative::Derivative)] +#[derivative(Clone(bound = ""), Copy(bound = ""), Debug(bound = ""))] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +pub(in crate::solve) struct AsyncCallableRelevantTypes { + pub tupled_inputs_ty: I::Ty, /// Type returned by calling the closure /// i.e. `f()`. - pub output_coroutine_ty: Ty<'tcx>, + pub output_coroutine_ty: I::Ty, /// Type returned by `await`ing the output /// i.e. `f().await`. - pub coroutine_return_ty: Ty<'tcx>, + pub coroutine_return_ty: I::Ty, } // Returns a binder of the tupled inputs types, output type, and coroutine type @@ -385,16 +395,13 @@ pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> { // the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper` // which enforces the closure is actually callable with the given trait. When we // know the kind already, we can short-circuit this check. -pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tcx>( - tcx: TyCtxt<'tcx>, - self_ty: Ty<'tcx>, +pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable( + tcx: I, + self_ty: I::Ty, goal_kind: ty::ClosureKind, - env_region: ty::Region<'tcx>, -) -> Result< - (ty::Binder<'tcx, AsyncCallableRelevantTypes<'tcx>>, Vec>), - NoSolution, -> { - match *self_ty.kind() { + env_region: I::Region, +) -> Result<(ty::Binder>, Vec), NoSolution> { + match self_ty.kind() { ty::CoroutineClosure(def_id, args) => { let args = args.as_coroutine_closure(); let kind_ty = args.kind_ty(); @@ -457,7 +464,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]); Ok(( bound_sig.rebind(AsyncCallableRelevantTypes { - tupled_inputs_ty: Ty::new_tup(tcx, sig.inputs()), + tupled_inputs_ty: Ty::new_tup(tcx, &sig.inputs()), output_coroutine_ty: sig.output(), coroutine_return_ty: future_output_ty, }), @@ -542,21 +549,21 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("unexpected type `{self_ty}`") + panic!("unexpected type `{self_ty:?}`") } } } /// Given a coroutine-closure, project to its returned coroutine when we are *certain* /// that the closure's kind is compatible with the goal. -fn coroutine_closure_to_certain_coroutine<'tcx>( - tcx: TyCtxt<'tcx>, +fn coroutine_closure_to_certain_coroutine( + tcx: I, goal_kind: ty::ClosureKind, - goal_region: ty::Region<'tcx>, - def_id: DefId, - args: ty::CoroutineClosureArgs>, - sig: ty::CoroutineClosureSignature>, -) -> Ty<'tcx> { + goal_region: I::Region, + def_id: I::DefId, + args: ty::CoroutineClosureArgs, + sig: ty::CoroutineClosureSignature, +) -> I::Ty { sig.to_coroutine_given_kind_and_upvars( tcx, args.parent_args(), @@ -573,20 +580,20 @@ fn coroutine_closure_to_certain_coroutine<'tcx>( /// yet what the closure's upvars are. /// /// Note that we do not also push a `AsyncFnKindHelper` goal here. -fn coroutine_closure_to_ambiguous_coroutine<'tcx>( - tcx: TyCtxt<'tcx>, +fn coroutine_closure_to_ambiguous_coroutine( + tcx: I, goal_kind: ty::ClosureKind, - goal_region: ty::Region<'tcx>, - def_id: DefId, - args: ty::CoroutineClosureArgs>, - sig: ty::CoroutineClosureSignature>, -) -> Ty<'tcx> { + goal_region: I::Region, + def_id: I::DefId, + args: ty::CoroutineClosureArgs, + sig: ty::CoroutineClosureSignature, +) -> I::Ty { let upvars_projection_def_id = tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); let tupled_upvars_ty = Ty::new_projection( tcx, upvars_projection_def_id, [ - ty::GenericArg::from(args.kind_ty()), + I::GenericArg::from(args.kind_ty()), Ty::from_closure_kind(tcx, goal_kind).into(), goal_region.into(), sig.tupled_inputs_ty.into(), @@ -643,17 +650,19 @@ fn coroutine_closure_to_ambiguous_coroutine<'tcx>( // This is unsound in general and once that is fixed, we don't need to // normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9 // for more details. -pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( - ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - object_bound: &'tcx ty::List>, -) -> Vec>> { +pub(in crate::solve) fn predicates_for_object_candidate< + Infcx: InferCtxtLike, + I: Interner, +>( + ecx: &EvalCtxt<'_, Infcx>, + param_env: I::ParamEnv, + trait_ref: ty::TraitRef, + object_bounds: I::BoundExistentialPredicates, +) -> Vec> { let tcx = ecx.interner(); let mut requirements = vec![]; - requirements.extend( - tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.args).predicates, - ); + requirements + .extend(tcx.super_predicates_of(trait_ref.def_id).iter_instantiated(tcx, &trait_ref.args)); for item in tcx.associated_items(trait_ref.def_id).in_definition_order() { // FIXME(associated_const_equality): Also add associated consts to // the requirements here. @@ -665,19 +674,19 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( } requirements - .extend(tcx.item_bounds(item.def_id).iter_instantiated(tcx, trait_ref.args)); + .extend(tcx.item_bounds(item.def_id).iter_instantiated(tcx, &trait_ref.args)); } } let mut replace_projection_with = FxHashMap::default(); - for bound in object_bound { + for bound in object_bounds { if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() { let proj = proj.with_self_ty(tcx, trait_ref.self_ty()); let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj)); assert_eq!( old_ty, None, - "{} has two generic parameters: {} and {}", + "{:?} has two generic parameters: {:?} and {:?}", proj.projection_term, proj.term, old_ty.unwrap() @@ -696,20 +705,22 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( .collect() } -struct ReplaceProjectionWith<'a, 'tcx> { - ecx: &'a EvalCtxt<'a, InferCtxt<'tcx>>, - param_env: ty::ParamEnv<'tcx>, - mapping: FxHashMap>, - nested: Vec>>, +struct ReplaceProjectionWith<'a, Infcx: InferCtxtLike, I: Interner> { + ecx: &'a EvalCtxt<'a, Infcx>, + param_env: I::ParamEnv, + mapping: FxHashMap>>, + nested: Vec>, } -impl<'tcx> TypeFolder> for ReplaceProjectionWith<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { +impl, I: Interner> TypeFolder + for ReplaceProjectionWith<'_, Infcx, I> +{ + fn interner(&self) -> I { self.ecx.interner() } - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Alias(ty::Projection, alias_ty) = *ty.kind() + fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + if let ty::Alias(ty::Projection, alias_ty) = ty.kind() && let Some(replacement) = self.mapping.get(&alias_ty.def_id) { // We may have a case where our object type's projection bound is higher-ranked, diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs index 24e10722448..680e9e961d1 100644 --- a/compiler/rustc_type_ir/src/infcx.rs +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -1,23 +1,44 @@ -use crate::{ConstVid, EffectVid, FloatVid, IntVid, Interner, RegionVid, TyVid, UniverseIndex}; +use crate::fold::TypeFoldable; +use crate::{self as ty, Interner}; pub trait InferCtxtLike { type Interner: Interner; fn interner(&self) -> Self::Interner; - fn universe_of_ty(&self, ty: TyVid) -> Option; - fn universe_of_lt(&self, lt: RegionVid) -> Option; - fn universe_of_ct(&self, ct: ConstVid) -> Option; + fn universe_of_ty(&self, ty: ty::TyVid) -> Option; + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option; + fn universe_of_ct(&self, ct: ty::ConstVid) -> Option; - fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> ::Ty; - fn opportunistic_resolve_int_var(&self, vid: IntVid) -> ::Ty; - fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> ::Ty; - fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> ::Const; + fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> ::Ty; + fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> ::Ty; + fn opportunistic_resolve_float_var( + &self, + vid: ty::FloatVid, + ) -> ::Ty; + fn opportunistic_resolve_ct_var( + &self, + vid: ty::ConstVid, + ) -> ::Const; fn opportunistic_resolve_effect_var( &self, - vid: EffectVid, + vid: ty::EffectVid, ) -> ::Const; - fn opportunistic_resolve_lt_var(&self, vid: RegionVid) -> ::Region; + fn opportunistic_resolve_lt_var( + &self, + vid: ty::RegionVid, + ) -> ::Region; fn defining_opaque_types(&self) -> ::DefiningOpaqueTypes; + + fn instantiate_binder_with_infer + Copy>( + &self, + value: ty::Binder, + ) -> T; + + fn enter_forall + Copy, U>( + &self, + value: ty::Binder, + f: impl FnOnce(T) -> U, + ) -> U; } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 2fc765f1c8f..bd88c4291e2 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -29,6 +29,8 @@ pub trait Ty>: { fn new_bool(interner: I) -> Self; + fn new_u8(interner: I) -> Self; + fn new_infer(interner: I, var: ty::InferTy) -> Self; fn new_var(interner: I, var: ty::TyVid) -> Self; @@ -39,6 +41,18 @@ pub trait Ty>: fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy) -> Self; + fn new_projection( + interner: I, + def_id: I::DefId, + args: impl IntoIterator>, + ) -> Self { + Ty::new_alias( + interner, + ty::AliasTyKind::Projection, + ty::AliasTy::new(interner, def_id, args), + ) + } + fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self; fn new_adt(interner: I, adt_def: I::AdtDef, args: I::GenericArgs) -> Self; @@ -75,6 +89,12 @@ pub trait Ty>: It: Iterator, T: CollectAndApply; + fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_fn_ptr(interner: I, sig: ty::Binder>) -> Self; + + fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self; + fn tuple_fields(self) -> I::Tys; fn to_opt_closure_kind(self) -> Option; @@ -83,11 +103,17 @@ pub trait Ty>: fn from_coroutine_closure_kind(interner: I, kind: ty::ClosureKind) -> Self; - fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; - - fn new_fn_ptr(interner: I, sig: ty::Binder>) -> Self; - - fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self; + fn is_ty_var(self) -> bool { + matches!(self.kind(), ty::Infer(ty::TyVar(_))) + } + + fn fn_sig(self, interner: I) -> ty::Binder> { + match self.kind() { + ty::FnPtr(sig) => sig, + ty::FnDef(def_id, args) => interner.fn_sig(def_id).instantiate(interner, &args), + _ => todo!("TODO:"), + } + } } pub trait Tys>: @@ -122,7 +148,6 @@ pub trait Region>: + Into + IntoKind> + Flags - + TypeVisitable + Relate { fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundRegion) -> Self; @@ -164,6 +189,25 @@ pub trait GenericsOf> { fn count(&self) -> usize; } +pub trait GenericArg>: + Copy + + Debug + + Hash + + Eq + + IntoKind> + + TypeVisitable + + Relate + + From + + From + + From +{ +} + +pub trait Term>: + Copy + Debug + Hash + Eq + IntoKind> + TypeFoldable + Relate +{ +} + pub trait GenericArgs>: Copy + Debug @@ -172,7 +216,6 @@ pub trait GenericArgs>: + IntoIterator + Deref> + Default - + TypeFoldable + Relate { fn type_at(self, i: usize) -> I::Ty; @@ -188,6 +231,16 @@ pub trait GenericArgs>: fn split_closure_args(self) -> ty::ClosureArgsParts; fn split_coroutine_closure_args(self) -> ty::CoroutineClosureArgsParts; fn split_coroutine_args(self) -> ty::CoroutineArgsParts; + + fn as_closure(self) -> ty::ClosureArgs { + ty::ClosureArgs { args: self } + } + fn as_coroutine_closure(self) -> ty::CoroutineClosureArgs { + ty::CoroutineClosureArgs { args: self } + } + fn as_coroutine(self) -> ty::CoroutineArgs { + ty::CoroutineArgs { args: self } + } } pub trait Predicate>: @@ -198,7 +251,10 @@ pub trait Predicate>: + TypeSuperVisitable + TypeSuperFoldable + Flags + + UpcastFrom + UpcastFrom> + + UpcastFrom> + + UpcastFrom>> { fn is_coinductive(self, interner: I) -> bool; } @@ -208,6 +264,7 @@ pub trait Clause>: + Debug + Hash + Eq + + TypeFoldable // FIXME: Remove these, uplift the `Upcast` impls. + UpcastFrom>> + UpcastFrom>> @@ -242,8 +299,17 @@ pub trait ParamLike { pub trait AdtDef: Copy + Debug + Hash + Eq { fn def_id(self) -> I::DefId; + + fn is_phantom_data(self) -> bool; + + // FIXME: perhaps use `all_fields` and expose `FieldDef`. + fn all_field_tys(self, interner: I) -> ty::EarlyBinder>; + + fn sized_constraint(self, interner: I) -> Option>; } pub trait Features: Copy { fn generic_const_exprs(self) -> bool; + + fn coroutine_clone(self) -> bool; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index b7f412ecb8e..ad983cc4187 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -1,3 +1,4 @@ +use rustc_ast_ir::Movability; use smallvec::SmallVec; use std::fmt::Debug; use std::hash::Hash; @@ -31,20 +32,8 @@ pub trait Interner: type GenericArgs: GenericArgs; type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref; - type GenericArg: Copy - + Debug - + Hash - + Eq - + IntoKind> - + TypeVisitable - + Relate; - type Term: Copy - + Debug - + Hash - + Eq - + IntoKind> - + TypeFoldable - + Relate; + type GenericArg: GenericArg; + type Term: Term; type BoundVarKinds: Copy + Debug @@ -74,7 +63,12 @@ pub trait Interner: // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; - type BoundExistentialPredicates: Copy + Debug + Hash + Eq + Relate; + type BoundExistentialPredicates: Copy + + Debug + + Hash + + Eq + + Relate + + IntoIterator>>; type AllocId: Copy + Debug + Hash + Eq; type Pat: Copy + Debug + Hash + Eq + Debug + Relate; type Safety: Safety + TypeFoldable + Relate; @@ -153,6 +147,34 @@ pub trait Interner: type Features: Features; fn features(self) -> Self::Features; + + fn bound_coroutine_hidden_types( + self, + def_id: Self::DefId, + ) -> impl Iterator>>; + + fn fn_sig( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>>; + + fn coroutine_movability(self, def_id: Self::DefId) -> Movability; + + fn coroutine_for_closure(self, def_id: Self::DefId) -> Self::DefId; + + fn generics_require_sized_self(self, def_id: Self::DefId) -> bool; + + fn item_bounds( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>; + + fn super_predicates_of( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>; + + fn has_target_features(self, def_id: Self::DefId) -> bool; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` -- cgit 1.4.1-3-g733a5 From e82db89b4dbf0ddcc67f7804a01c322c761415b4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 17:48:37 -0400 Subject: Finish uplifting all of structural_traits --- compiler/rustc_infer/src/infer/at.rs | 44 ++++ .../rustc_infer/src/infer/error_reporting/mod.rs | 2 + compiler/rustc_infer/src/infer/mod.rs | 75 ++++-- compiler/rustc_middle/src/ty/context.rs | 23 +- compiler/rustc_middle/src/ty/predicate.rs | 9 + .../src/solve/assembly/structural_traits.rs | 37 +-- .../src/solve/eval_ctxt/mod.rs | 293 ++++++++++----------- compiler/rustc_trait_selection/src/solve/mod.rs | 11 - .../src/solve/normalizes_to/mod.rs | 2 +- compiler/rustc_type_ir/src/infcx.rs | 30 ++- compiler/rustc_type_ir/src/inherent.rs | 50 ++++ compiler/rustc_type_ir/src/interner.rs | 5 + compiler/rustc_type_ir/src/lang_items.rs | 8 + compiler/rustc_type_ir/src/lib.rs | 1 + 14 files changed, 385 insertions(+), 205 deletions(-) create mode 100644 compiler/rustc_type_ir/src/lang_items.rs diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 01bd732a4cd..2d06a7c693f 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -225,6 +225,50 @@ impl<'a, 'tcx> At<'a, 'tcx> { } } + /// Used in the new solver since we don't care about tracking an `ObligationCause`. + pub fn relate_no_trace( + self, + expected: T, + variance: ty::Variance, + actual: T, + ) -> Result>>, NoSolution> + where + T: Relate>, + { + let mut fields = CombineFields::new( + self.infcx, + TypeTrace::dummy(self.cause), + self.param_env, + DefineOpaqueTypes::Yes, + ); + fields.sub().relate_with_variance( + variance, + ty::VarianceDiagInfo::default(), + expected, + actual, + )?; + Ok(fields.goals) + } + + /// Used in the new solver since we don't care about tracking an `ObligationCause`. + pub fn eq_structurally_relating_aliases_no_trace( + self, + expected: T, + actual: T, + ) -> Result>>, NoSolution> + where + T: Relate>, + { + let mut fields = CombineFields::new( + self.infcx, + TypeTrace::dummy(self.cause), + self.param_env, + DefineOpaqueTypes::Yes, + ); + fields.equate(StructurallyRelateAliases::Yes).relate(expected, actual)?; + Ok(fields.goals) + } + /// Computes the least-upper-bound, or mutual supertype, of two /// values. The order of the arguments doesn't matter, but since /// this can result in an error (e.g., if asked to compute LUB of diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index ed483c6cbeb..d8a2857a11d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1707,6 +1707,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ValuePairs::ExistentialProjection(_) => { (false, Mismatch::Fixed("existential projection")) } + infer::DummyPair => (false, Mismatch::Fixed("values")), }; let Some(vals) = self.values_str(values) else { // Derived error. Cancel the emitter. @@ -2275,6 +2276,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let (exp, fnd) = self.cmp_fn_sig(&exp_found.expected, &exp_found.found); Some((exp, fnd, None)) } + infer::DummyPair => None, } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 46f18bd77a0..e95949b92a9 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -11,7 +11,7 @@ pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; pub use ValuePairs::*; -use crate::infer::relate::RelateResult; +use crate::infer::relate::{Relate, RelateResult}; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; use error_reporting::TypeErrCtxt; use free_regions::RegionRelations; @@ -35,6 +35,7 @@ use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::select; +use rustc_middle::traits::solve::{Goal, NoSolution}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BoundVarReplacerDelegate; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; @@ -352,29 +353,21 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { } } - fn universe_of_ct(&self, ct: ConstVid) -> Option { - // Same issue as with `universe_of_ty` - match self.probe_const_var(ct) { + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option { + match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { Err(universe) => Some(universe), Ok(_) => None, } } - fn universe_of_lt(&self, lt: ty::RegionVid) -> Option { - match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { + fn universe_of_ct(&self, ct: ConstVid) -> Option { + // Same issue as with `universe_of_ty` + match self.probe_const_var(ct) { Err(universe) => Some(universe), Ok(_) => None, } } - fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { - self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) - } - - fn defining_opaque_types(&self) -> &'tcx ty::List { - self.defining_opaque_types - } - fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> { match self.probe_ty_var(vid) { Ok(ty) => ty, @@ -406,6 +399,26 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { } } + fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { + self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) + } + + fn defining_opaque_types(&self) -> &'tcx ty::List { + self.defining_opaque_types + } + + fn next_ty_infer(&self) -> Ty<'tcx> { + self.next_ty_var(DUMMY_SP) + } + + fn next_const_infer(&self) -> ty::Const<'tcx> { + self.next_const_var(DUMMY_SP) + } + + fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> { + self.fresh_args_for_item(DUMMY_SP, def_id) + } + fn instantiate_binder_with_infer + Copy>( &self, value: ty::Binder<'tcx, T>, @@ -417,13 +430,40 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { ) } - fn enter_forall + Copy, U>( + fn enter_forall> + Copy, U>( &self, value: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U, ) -> U { self.enter_forall(value, f) } + + fn relate>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result>>, NoSolution> { + self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) + } + + fn eq_structurally_relating_aliases>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result>>, NoSolution> { + self.at(&ObligationCause::dummy(), param_env) + .eq_structurally_relating_aliases_no_trace(lhs, rhs) + } + + fn resolve_vars_if_possible(&self, value: T) -> T + where + T: TypeFoldable>, + { + self.resolve_vars_if_possible(value) + } } /// See the `error_reporting` module for more details. @@ -436,6 +476,7 @@ pub enum ValuePairs<'tcx> { PolySigs(ExpectedFound>), ExistentialTraitRef(ExpectedFound>), ExistentialProjection(ExpectedFound>), + DummyPair, } impl<'tcx> ValuePairs<'tcx> { @@ -1858,6 +1899,10 @@ impl<'tcx> TypeTrace<'tcx> { values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } + + fn dummy(cause: &ObligationCause<'tcx>) -> TypeTrace<'tcx> { + TypeTrace { cause: cause.clone(), values: ValuePairs::DummyPair } + } } impl<'tcx> SubregionOrigin<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 98c60ffee12..ebcb47966eb 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -70,9 +70,9 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::fold::TypeFoldable; +use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::TyKind::*; -use rustc_type_ir::WithCachedTypeInfo; -use rustc_type_ir::{CollectAndApply, Interner, TypeFlags}; +use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, instrument}; use std::assert_matches::assert_matches; @@ -302,6 +302,25 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn has_target_features(self, def_id: DefId) -> bool { !self.codegen_fn_attrs(def_id).target_features.is_empty() } + + fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId { + self.require_lang_item( + match lang_item { + TraitSolverLangItem::Future => hir::LangItem::Future, + TraitSolverLangItem::FutureOutput => hir::LangItem::FutureOutput, + TraitSolverLangItem::AsyncFnKindHelper => hir::LangItem::AsyncFnKindHelper, + TraitSolverLangItem::AsyncFnKindUpvars => hir::LangItem::AsyncFnKindUpvars, + }, + None, + ) + } + + fn associated_type_def_ids(self, def_id: DefId) -> impl Iterator { + self.associated_items(def_id) + .in_definition_order() + .filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type)) + .map(|assoc_item| assoc_item.def_id) + } } impl<'tcx> rustc_type_ir::inherent::Abi> for abi::Abi { diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 785aa8d456f..0f63490ea01 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -51,6 +51,14 @@ impl<'tcx> rustc_type_ir::inherent::Predicate> for Predicate<'tcx> } } +impl<'tcx> rustc_type_ir::inherent::IntoKind for Predicate<'tcx> { + type Kind = ty::Binder<'tcx, ty::PredicateKind<'tcx>>; + + fn kind(self) -> Self::Kind { + self.kind() + } +} + impl<'tcx> rustc_type_ir::visit::Flags for Predicate<'tcx> { fn flags(&self) -> TypeFlags { self.0.flags @@ -120,6 +128,7 @@ impl<'tcx> Predicate<'tcx> { /// unsoundly accept some programs. See #91068. #[inline] pub fn allow_normalization(self) -> bool { + // Keep this in sync with the one in `rustc_type_ir::inherent`! match self.kind().skip_binder() { PredicateKind::Clause(ClauseKind::WellFormed(_)) | PredicateKind::AliasRelate(..) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index c90b458d7b1..f232ddcf797 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -6,6 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_next_trait_solver::solve::{Goal, NoSolution}; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; +use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::{self as ty, InferCtxtLike, Interner, Upcast}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; @@ -428,7 +429,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable { let bound_sig = self_ty.fn_sig(tcx); let sig = bound_sig.skip_binder(); - let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let future_trait_def_id = tcx.require_lang_item(TraitSolverLangItem::Future); // `FnDef` and `FnPtr` only implement `AsyncFn*` when their // return type implements `Future`. let nested = vec![ @@ -460,7 +461,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable( args: ty::CoroutineClosureArgs, sig: ty::CoroutineClosureSignature, ) -> I::Ty { - let upvars_projection_def_id = tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); + let upvars_projection_def_id = tcx.require_lang_item(TraitSolverLangItem::AsyncFnKindUpvars); let tupled_upvars_ty = Ty::new_projection( tcx, upvars_projection_def_id, @@ -663,19 +664,19 @@ pub(in crate::solve) fn predicates_for_object_candidate< let mut requirements = vec![]; requirements .extend(tcx.super_predicates_of(trait_ref.def_id).iter_instantiated(tcx, &trait_ref.args)); - for item in tcx.associated_items(trait_ref.def_id).in_definition_order() { - // FIXME(associated_const_equality): Also add associated consts to - // the requirements here. - if item.kind == ty::AssocKind::Type { - // associated types that require `Self: Sized` do not show up in the built-in - // implementation of `Trait for dyn Trait`, and can be dropped here. - if tcx.generics_require_sized_self(item.def_id) { - continue; - } - requirements - .extend(tcx.item_bounds(item.def_id).iter_instantiated(tcx, &trait_ref.args)); + // FIXME(associated_const_equality): Also add associated consts to + // the requirements here. + for associated_type_def_id in tcx.associated_type_def_ids(trait_ref.def_id) { + // associated types that require `Self: Sized` do not show up in the built-in + // implementation of `Trait for dyn Trait`, and can be dropped here. + if tcx.generics_require_sized_self(associated_type_def_id) { + continue; } + + requirements.extend( + tcx.item_bounds(associated_type_def_id).iter_instantiated(tcx, &trait_ref.args), + ); } let mut replace_projection_with = FxHashMap::default(); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 43013a01069..d35101b29f9 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -1,9 +1,6 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; -use rustc_infer::infer::at::ToTrace; -use rustc_infer::infer::{ - BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt, -}; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals}; use rustc_infer::traits::ObligationCause; @@ -15,11 +12,12 @@ use rustc_middle::traits::solve::{ use rustc_middle::ty::AliasRelationDirection; use rustc_middle::ty::TypeFolder; use rustc_middle::ty::{ - self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, + self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, }; use rustc_span::DUMMY_SP; use rustc_type_ir::fold::TypeSuperFoldable; +use rustc_type_ir::inherent::*; +use rustc_type_ir::relate::Relate; use rustc_type_ir::{self as ir, CanonicalVarValues, Interner}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::ops::ControlFlow; @@ -456,28 +454,6 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } } - #[instrument(level = "trace", skip(self))] - pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) { - goal.predicate = goal - .predicate - .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); - self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal); - self.nested_goals.normalizes_to_goals.push(goal); - } - - #[instrument(level = "debug", skip(self))] - pub(super) fn add_goal( - &mut self, - source: GoalSource, - mut goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) { - goal.predicate = goal - .predicate - .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); - self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal); - self.nested_goals.goals.push((source, goal)); - } - // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning // the certainty of all the goals. #[instrument(level = "trace", skip(self))] @@ -600,30 +576,65 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { pub(super) fn interner(&self) -> I { self.infcx.interner() } -} -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { - pub(super) fn next_ty_infer(&mut self) -> Ty<'tcx> { - let ty = self.infcx.next_ty_var(DUMMY_SP); + #[instrument(level = "trace", skip(self))] + pub(super) fn add_normalizes_to_goal( + &mut self, + mut goal: ir::solve::Goal>, + ) { + goal.predicate = goal + .predicate + .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); + self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal); + self.nested_goals.normalizes_to_goals.push(goal); + } + + #[instrument(level = "debug", skip(self))] + pub(super) fn add_goal( + &mut self, + source: GoalSource, + mut goal: ir::solve::Goal, + ) { + goal.predicate = goal + .predicate + .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); + self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal); + self.nested_goals.goals.push((source, goal)); + } + + #[instrument(level = "trace", skip(self, goals))] + pub(super) fn add_goals( + &mut self, + source: GoalSource, + goals: impl IntoIterator>, + ) { + for goal in goals { + self.add_goal(source, goal); + } + } + + pub(super) fn next_ty_infer(&mut self) -> I::Ty { + let ty = self.infcx.next_ty_infer(); self.inspect.add_var_value(ty); ty } - pub(super) fn next_const_infer(&mut self) -> ty::Const<'tcx> { - let ct = self.infcx.next_const_var(DUMMY_SP); + pub(super) fn next_const_infer(&mut self) -> I::Const { + let ct = self.infcx.next_const_infer(); self.inspect.add_var_value(ct); ct } /// Returns a ty infer or a const infer depending on whether `kind` is a `Ty` or `Const`. /// If `kind` is an integer inference variable this will still return a ty infer var. - pub(super) fn next_term_infer_of_kind(&mut self, kind: ty::Term<'tcx>) -> ty::Term<'tcx> { - match kind.unpack() { - ty::TermKind::Ty(_) => self.next_ty_infer().into(), - ty::TermKind::Const(_) => self.next_const_infer().into(), + pub(super) fn next_term_infer_of_kind(&mut self, kind: I::Term) -> I::Term { + match kind.kind() { + ir::TermKind::Ty(_) => self.next_ty_infer().into(), + ir::TermKind::Const(_) => self.next_const_infer().into(), } } + /* TODO: /// Is the projection predicate is of the form `exists ::Assoc = T`. /// /// This is the case if the `term` does not occur in any other part of the predicate @@ -631,18 +642,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self), ret)] pub(super) fn term_is_fully_unconstrained( &self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, + goal: ir::solve::Goal>, ) -> bool { - let universe_of_term = match goal.predicate.term.unpack() { - ty::TermKind::Ty(ty) => { - if let &ty::Infer(ty::TyVar(vid)) = ty.kind() { + let universe_of_term = match goal.predicate.term.kind() { + ir::TermKind::Ty(ty) => { + if let ir::Infer(ir::TyVar(vid)) = ty.kind() { self.infcx.universe_of_ty(vid).unwrap() } else { return false; } } - ty::TermKind::Const(ct) => { - if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { + ir::TermKind::Const(ct) => { + if let ir::ConstKind::Infer(ir::InferConst::Var(vid)) = ct.kind() { self.infcx.universe_of_ct(vid).unwrap() } else { return false; @@ -650,14 +661,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } }; - struct ContainsTermOrNotNameable<'a, 'tcx> { - term: ty::Term<'tcx>, - universe_of_term: ty::UniverseIndex, - infcx: &'a InferCtxt<'tcx>, + struct ContainsTermOrNotNameable<'a, Infcx: InferCtxtLike, I: Interner> { + term: I::Term, + universe_of_term: ir::UniverseIndex, + infcx: &'a Infcx, } - impl<'a, 'tcx> ContainsTermOrNotNameable<'a, 'tcx> { - fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> { + impl, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> { + fn check_nameable(&self, universe: ir::UniverseIndex) -> ControlFlow<()> { if self.universe_of_term.can_name(universe) { ControlFlow::Continue(()) } else { @@ -666,12 +677,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } - impl<'tcx> TypeVisitor> for ContainsTermOrNotNameable<'_, 'tcx> { + impl, I: Interner> TypeVisitor + for ContainsTermOrNotNameable<'_, Infcx, I> + { type Result = ControlFlow<()>; - fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { - match *t.kind() { - ty::Infer(ty::TyVar(vid)) => { - if let ty::TermKind::Ty(term) = self.term.unpack() + fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + match t.kind() { + ir::Infer(ir::TyVar(vid)) => { + if let ir::TermKind::Ty(term) = self.term.kind() && let Some(term_vid) = term.ty_vid() && self.infcx.root_var(vid) == self.infcx.root_var(term_vid) { @@ -680,7 +693,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.check_nameable(self.infcx.universe_of_ty(vid).unwrap()) } } - ty::Placeholder(p) => self.check_nameable(p.universe), + ir::Placeholder(p) => self.check_nameable(p.universe()), _ => { if t.has_non_region_infer() || t.has_placeholders() { t.super_visit_with(self) @@ -691,11 +704,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } - fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result { + fn visit_const(&mut self, c: I::Const) -> Self::Result { match c.kind() { - ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { - if let ty::TermKind::Const(term) = self.term.unpack() - && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() + ir::ConstKind::Infer(ir::InferConst::Var(vid)) => { + if let ir::TermKind::Const(term) = self.term.kind() + && let ir::ConstKind::Infer(ir::InferConst::Var(term_vid)) = term.kind() && self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid) { ControlFlow::Break(()) @@ -703,7 +716,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.check_nameable(self.infcx.universe_of_ct(vid).unwrap()) } } - ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe), + ir::ConstKind::Placeholder(p) => self.check_nameable(p.universe()), _ => { if c.has_non_region_infer() || c.has_placeholders() { c.super_visit_with(self) @@ -723,25 +736,16 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal.predicate.alias.visit_with(&mut visitor).is_continue() && goal.param_env.visit_with(&mut visitor).is_continue() } + */ #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn eq>( + pub(super) fn eq>( &mut self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, lhs: T, rhs: T, ) -> Result<(), NoSolution> { - self.infcx - .at(&ObligationCause::dummy(), param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .eq(DefineOpaqueTypes::Yes, lhs, rhs) - .map(|InferOk { value: (), obligations }| { - self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); - }) - .map_err(|e| { - trace!(?e, "failed to equate"); - NoSolution - }) + self.relate(param_env, lhs, ir::Variance::Invariant, rhs) } /// This should be used when relating a rigid alias with another type. @@ -752,10 +756,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self, param_env), ret)] pub(super) fn relate_rigid_alias_non_alias( &mut self, - param_env: ty::ParamEnv<'tcx>, - alias: ty::AliasTerm<'tcx>, - variance: ty::Variance, - term: ty::Term<'tcx>, + param_env: I::ParamEnv, + alias: ir::AliasTerm, + variance: ir::Variance, + term: I::Term, ) -> Result<(), NoSolution> { // NOTE: this check is purely an optimization, the structural eq would // always fail if the term is not an inference variable. @@ -770,12 +774,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // Alternatively we could modify `Equate` for this case by adding another // variant to `StructurallyRelateAliases`. let identity_args = self.fresh_args_for_item(alias.def_id); - let rigid_ctor = ty::AliasTerm::new(tcx, alias.def_id, identity_args); + let rigid_ctor = ir::AliasTerm::new(tcx, alias.def_id, identity_args); let ctor_term = rigid_ctor.to_term(tcx); - let InferOk { value: (), obligations } = self - .infcx - .at(&ObligationCause::dummy(), param_env) - .eq_structurally_relating_aliases(term, ctor_term)?; + let obligations = + self.infcx.eq_structurally_relating_aliases(param_env, term, ctor_term)?; debug_assert!(obligations.is_empty()); self.relate(param_env, alias, variance, rigid_ctor) } else { @@ -787,58 +789,38 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// unconstrained "return value" or when we're sure that all aliases in /// the types are rigid. #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn eq_structurally_relating_aliases>( + pub(super) fn eq_structurally_relating_aliases>( &mut self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, lhs: T, rhs: T, ) -> Result<(), NoSolution> { - let cause = ObligationCause::dummy(); - let InferOk { value: (), obligations } = - self.infcx.at(&cause, param_env).eq_structurally_relating_aliases(lhs, rhs)?; - assert!(obligations.is_empty()); + let result = self.infcx.eq_structurally_relating_aliases(param_env, lhs, rhs)?; + assert_eq!(result, vec![]); Ok(()) } #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn sub>( + pub(super) fn sub>( &mut self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, sub: T, sup: T, ) -> Result<(), NoSolution> { - self.infcx - .at(&ObligationCause::dummy(), param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .sub(DefineOpaqueTypes::Yes, sub, sup) - .map(|InferOk { value: (), obligations }| { - self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); - }) - .map_err(|e| { - trace!(?e, "failed to subtype"); - NoSolution - }) + self.relate(param_env, sub, ir::Variance::Covariant, sup) } #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn relate>( + pub(super) fn relate>( &mut self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, lhs: T, - variance: ty::Variance, + variance: ir::Variance, rhs: T, ) -> Result<(), NoSolution> { - self.infcx - .at(&ObligationCause::dummy(), param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .relate(DefineOpaqueTypes::Yes, lhs, variance, rhs) - .map(|InferOk { value: (), obligations }| { - self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); - }) - .map_err(|e| { - trace!(?e, "failed to relate"); - NoSolution - }) + let goals = self.infcx.relate(param_env, lhs, variance, rhs)?; + self.add_goals(GoalSource::Misc, goals); + Ok(()) } /// Equates two values returning the nested goals without adding them @@ -847,58 +829,47 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// If possible, try using `eq` instead which automatically handles nested /// goals correctly. #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn eq_and_get_goals>( + pub(super) fn eq_and_get_goals>( &self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, lhs: T, rhs: T, - ) -> Result>>, NoSolution> { - self.infcx - .at(&ObligationCause::dummy(), param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .eq(DefineOpaqueTypes::Yes, lhs, rhs) - .map(|InferOk { value: (), obligations }| { - obligations.into_iter().map(|o| o.into()).collect() - }) - .map_err(|e| { - trace!(?e, "failed to equate"); - NoSolution - }) + ) -> Result>, NoSolution> { + self.infcx.relate(param_env, lhs, ir::Variance::Invariant, rhs) } - pub(super) fn instantiate_binder_with_infer> + Copy>( + pub(super) fn instantiate_binder_with_infer + Copy>( &self, - value: ty::Binder<'tcx, T>, + value: ir::Binder, ) -> T { - self.infcx.instantiate_binder_with_fresh_vars( - DUMMY_SP, - BoundRegionConversionTime::HigherRankedType, - value, - ) + self.infcx.instantiate_binder_with_infer(value) } - pub(super) fn enter_forall> + Copy, U>( + pub(super) fn enter_forall + Copy, U>( &self, - value: ty::Binder<'tcx, T>, + value: ir::Binder, f: impl FnOnce(T) -> U, ) -> U { self.infcx.enter_forall(value, f) } + pub(super) fn resolve_vars_if_possible(&self, value: T) -> T where - T: TypeFoldable>, + T: TypeFoldable, { self.infcx.resolve_vars_if_possible(value) } - pub(super) fn fresh_args_for_item(&mut self, def_id: DefId) -> ty::GenericArgsRef<'tcx> { - let args = self.infcx.fresh_args_for_item(DUMMY_SP, def_id); + pub(super) fn fresh_args_for_item(&mut self, def_id: I::DefId) -> I::GenericArgs { + let args = self.infcx.fresh_args_for_item(def_id); for arg in args { self.inspect.add_var_value(arg); } args } +} +impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) { self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy()); } @@ -1096,28 +1067,36 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// /// This is a performance optimization to more eagerly detect cycles during trait /// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs. -struct ReplaceAliasWithInfer<'me, 'a, 'tcx> { - ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>, - param_env: ty::ParamEnv<'tcx>, +struct ReplaceAliasWithInfer<'me, 'a, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + ecx: &'me mut EvalCtxt<'a, Infcx>, + param_env: I::ParamEnv, } -impl<'tcx> TypeFolder> for ReplaceAliasWithInfer<'_, '_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { +impl TypeFolder for ReplaceAliasWithInfer<'_, '_, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + fn interner(&self) -> I { self.ecx.interner() } - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match *ty.kind() { - ty::Alias(..) if !ty.has_escaping_bound_vars() => { + fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + match ty.kind() { + ir::Alias(..) if !ty.has_escaping_bound_vars() => { let infer_ty = self.ecx.next_ty_infer(); - let normalizes_to = ty::PredicateKind::AliasRelate( + let normalizes_to = ir::PredicateKind::AliasRelate( ty.into(), infer_ty.into(), AliasRelationDirection::Equate, ); self.ecx.add_goal( GoalSource::Misc, - Goal::new(self.interner(), self.param_env, normalizes_to), + ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to), ); infer_ty } @@ -1125,18 +1104,18 @@ impl<'tcx> TypeFolder> for ReplaceAliasWithInfer<'_, '_, 'tcx> { } } - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + fn fold_const(&mut self, ct: I::Const) -> I::Const { match ct.kind() { - ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { + ir::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { let infer_ct = self.ecx.next_const_infer(); - let normalizes_to = ty::PredicateKind::AliasRelate( + let normalizes_to = ir::PredicateKind::AliasRelate( ct.into(), infer_ct.into(), AliasRelationDirection::Equate, ); self.ecx.add_goal( GoalSource::Misc, - Goal::new(self.interner(), self.param_env, normalizes_to), + ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to), ); infer_ct } @@ -1144,7 +1123,7 @@ impl<'tcx> TypeFolder> for ReplaceAliasWithInfer<'_, '_, 'tcx> { } } - fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate(&mut self, predicate: I::Predicate) -> I::Predicate { if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate } } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index c47b0194964..fdcf4ff11e4 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -235,17 +235,6 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { - #[instrument(level = "trace", skip(self, goals))] - fn add_goals( - &mut self, - source: GoalSource, - goals: impl IntoIterator>>, - ) { - for goal in goals { - self.add_goal(source, goal); - } - } - /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`. /// /// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`. diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 50253d81528..821e1e76736 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -31,7 +31,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { self.set_is_normalizes_to_goal(); - debug_assert!(self.term_is_fully_unconstrained(goal)); + // debug_assert!(self.term_is_fully_unconstrained(goal)); TODO: let normalize_result = self .probe(|&result| ProbeKind::TryNormalizeNonRigid { result }) .enter(|this| this.normalize_at_least_one_step(goal)); diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs index 680e9e961d1..4fb1069ff66 100644 --- a/compiler/rustc_type_ir/src/infcx.rs +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -1,7 +1,9 @@ use crate::fold::TypeFoldable; +use crate::relate::Relate; +use crate::solve::{Goal, NoSolution}; use crate::{self as ty, Interner}; -pub trait InferCtxtLike { +pub trait InferCtxtLike: Sized { type Interner: Interner; fn interner(&self) -> Self::Interner; @@ -31,6 +33,13 @@ pub trait InferCtxtLike { fn defining_opaque_types(&self) -> ::DefiningOpaqueTypes; + fn next_ty_infer(&self) -> ::Ty; + fn next_const_infer(&self) -> ::Const; + fn fresh_args_for_item( + &self, + def_id: ::DefId, + ) -> ::GenericArgs; + fn instantiate_binder_with_infer + Copy>( &self, value: ty::Binder, @@ -41,4 +50,23 @@ pub trait InferCtxtLike { value: ty::Binder, f: impl FnOnce(T) -> U, ) -> U; + + fn relate>( + &self, + param_env: ::ParamEnv, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result::Predicate>>, NoSolution>; + + fn eq_structurally_relating_aliases>( + &self, + param_env: ::ParamEnv, + lhs: T, + rhs: T, + ) -> Result::Predicate>>, NoSolution>; + + fn resolve_vars_if_possible(&self, value: T) -> T + where + T: TypeFoldable; } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index bd88c4291e2..b2231d14535 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -183,6 +183,10 @@ pub trait Const>: fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst) -> Self; fn new_expr(interner: I, expr: I::ExprConst) -> Self; + + fn is_ct_var(self) -> bool { + matches!(self.kind(), ty::ConstKind::Infer(ty::InferConst::Var(_))) + } } pub trait GenericsOf> { @@ -206,6 +210,28 @@ pub trait GenericArg>: pub trait Term>: Copy + Debug + Hash + Eq + IntoKind> + TypeFoldable + Relate { + fn as_type(&self) -> Option { + if let ty::TermKind::Ty(ty) = self.kind() { Some(ty) } else { None } + } + + fn expect_type(&self) -> I::Ty { + self.as_type().expect("expected a type, but found a const") + } + + fn as_const(&self) -> Option { + if let ty::TermKind::Const(c) = self.kind() { Some(c) } else { None } + } + + fn expect_const(&self) -> I::Const { + self.as_const().expect("expected a const, but found a type") + } + + fn is_infer(self) -> bool { + match self.kind() { + ty::TermKind::Ty(ty) => ty.is_ty_var(), + ty::TermKind::Const(ct) => ct.is_ct_var(), + } + } } pub trait GenericArgs>: @@ -251,12 +277,36 @@ pub trait Predicate>: + TypeSuperVisitable + TypeSuperFoldable + Flags + + UpcastFrom> + + UpcastFrom>> + + UpcastFrom> + + UpcastFrom>> + UpcastFrom + UpcastFrom> + UpcastFrom> + UpcastFrom>> + + IntoKind>> { fn is_coinductive(self, interner: I) -> bool; + + fn allow_normalization(self) -> bool { + match self.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) + | ty::PredicateKind::AliasRelate(..) + | ty::PredicateKind::NormalizesTo(..) => false, + ty::PredicateKind::Clause(ty::ClauseKind::Trait(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) + | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::Subtype(_) + | ty::PredicateKind::Coerce(_) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(_)) + | ty::PredicateKind::ConstEquate(_, _) + | ty::PredicateKind::Ambiguous => true, + } + } } pub trait Clause>: diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index ad983cc4187..f4f7a6e901c 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -7,6 +7,7 @@ use std::ops::Deref; use crate::fold::TypeFoldable; use crate::inherent::*; use crate::ir_print::IrPrint; +use crate::lang_items::TraitSolverLangItem; use crate::relate::Relate; use crate::solve::inspect::CanonicalGoalEvaluationStep; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; @@ -175,6 +176,10 @@ pub trait Interner: ) -> ty::EarlyBinder>; fn has_target_features(self, def_id: Self::DefId) -> bool; + + fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId; + + fn associated_type_def_ids(self, def_id: Self::DefId) -> impl Iterator; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs new file mode 100644 index 00000000000..9a3b324fcd7 --- /dev/null +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -0,0 +1,8 @@ +/// Lang items used by the new trait solver. This can be mapped to whatever internal +/// representation of `LangItem`s used in the underlying compiler implementation. +pub enum TraitSolverLangItem { + Future, + FutureOutput, + AsyncFnKindHelper, + AsyncFnKindUpvars, +} diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index a76e278cc05..7f0c3df381d 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -32,6 +32,7 @@ pub mod error; pub mod fold; pub mod inherent; pub mod ir_print; +pub mod lang_items; pub mod lift; pub mod relate; pub mod solve; -- cgit 1.4.1-3-g733a5 From a2fb2ebc177cc4fa5933e72f3a81791e9b0b0083 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 18:35:51 -0400 Subject: Fix some TODOs --- compiler/rustc_infer/src/infer/mod.rs | 8 ++++++++ compiler/rustc_middle/src/ty/context.rs | 8 ++++++++ .../src/solve/eval_ctxt/mod.rs | 7 +++---- .../src/solve/normalizes_to/mod.rs | 2 +- compiler/rustc_type_ir/src/infcx.rs | 3 +++ compiler/rustc_type_ir/src/inherent.rs | 22 +++++++++++++++++++--- compiler/rustc_type_ir/src/interner.rs | 4 ++-- 7 files changed, 44 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e95949b92a9..6f40b9f7295 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -368,6 +368,14 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { } } + fn root_ty_var(&self, var: TyVid) -> TyVid { + self.root_var(var) + } + + fn root_const_var(&self, var: ConstVid) -> ConstVid { + self.root_const_var(var) + } + fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> { match self.probe_ty_var(vid) { Ok(ty) => ty, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index ebcb47966eb..849e10a952b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -324,12 +324,20 @@ impl<'tcx> Interner for TyCtxt<'tcx> { } impl<'tcx> rustc_type_ir::inherent::Abi> for abi::Abi { + fn rust() -> Self { + abi::Abi::Rust + } + fn is_rust(self) -> bool { matches!(self, abi::Abi::Rust) } } impl<'tcx> rustc_type_ir::inherent::Safety> for hir::Safety { + fn safe() -> Self { + hir::Safety::Safe + } + fn is_safe(self) -> bool { matches!(self, hir::Safety::Safe) } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index d35101b29f9..860c580374d 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -18,6 +18,7 @@ use rustc_span::DUMMY_SP; use rustc_type_ir::fold::TypeSuperFoldable; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; +use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_type_ir::{self as ir, CanonicalVarValues, Interner}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::ops::ControlFlow; @@ -634,7 +635,6 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { } } - /* TODO: /// Is the projection predicate is of the form `exists ::Assoc = T`. /// /// This is the case if the `term` does not occur in any other part of the predicate @@ -685,8 +685,8 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { match t.kind() { ir::Infer(ir::TyVar(vid)) => { if let ir::TermKind::Ty(term) = self.term.kind() - && let Some(term_vid) = term.ty_vid() - && self.infcx.root_var(vid) == self.infcx.root_var(term_vid) + && let ir::Infer(ir::TyVar(term_vid)) = term.kind() + && self.infcx.root_ty_var(vid) == self.infcx.root_ty_var(term_vid) { ControlFlow::Break(()) } else { @@ -736,7 +736,6 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { goal.predicate.alias.visit_with(&mut visitor).is_continue() && goal.param_env.visit_with(&mut visitor).is_continue() } - */ #[instrument(level = "trace", skip(self, param_env), ret)] pub(super) fn eq>( diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 821e1e76736..50253d81528 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -31,7 +31,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { self.set_is_normalizes_to_goal(); - // debug_assert!(self.term_is_fully_unconstrained(goal)); TODO: + debug_assert!(self.term_is_fully_unconstrained(goal)); let normalize_result = self .probe(|&result| ProbeKind::TryNormalizeNonRigid { result }) .enter(|this| this.normalize_at_least_one_step(goal)); diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs index 4fb1069ff66..92a717a0d9e 100644 --- a/compiler/rustc_type_ir/src/infcx.rs +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -12,6 +12,9 @@ pub trait InferCtxtLike: Sized { fn universe_of_lt(&self, lt: ty::RegionVid) -> Option; fn universe_of_ct(&self, ct: ty::ConstVid) -> Option; + fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid; + fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid; + fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> ::Ty; fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> ::Ty; fn opportunistic_resolve_float_var( diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index b2231d14535..3f919d4b876 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -111,7 +111,19 @@ pub trait Ty>: match self.kind() { ty::FnPtr(sig) => sig, ty::FnDef(def_id, args) => interner.fn_sig(def_id).instantiate(interner, &args), - _ => todo!("TODO:"), + ty::Error(_) => { + // ignore errors (#54954) + ty::Binder::dummy(ty::FnSig { + inputs_and_output: Default::default(), + c_variadic: false, + safety: I::Safety::safe(), + abi: I::Abi::rust(), + }) + } + ty::Closure(..) => panic!( + "to get the signature of a closure, use `args.as_closure().sig()` not `fn_sig()`", + ), + _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self), } } } @@ -129,12 +141,16 @@ pub trait Tys>: fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty); } -pub trait Abi>: Copy + Debug + Hash + Eq + TypeVisitable { +pub trait Abi>: Copy + Debug + Hash + Eq + Relate { + fn rust() -> Self; + /// Whether this ABI is `extern "Rust"`. fn is_rust(self) -> bool; } -pub trait Safety>: Copy + Debug + Hash + Eq + TypeVisitable { +pub trait Safety>: Copy + Debug + Hash + Eq + Relate { + fn safe() -> Self; + fn is_safe(self) -> bool; fn prefix_str(self) -> &'static str; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index f4f7a6e901c..bcf6c9b1a0e 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -72,8 +72,8 @@ pub trait Interner: + IntoIterator>>; type AllocId: Copy + Debug + Hash + Eq; type Pat: Copy + Debug + Hash + Eq + Debug + Relate; - type Safety: Safety + TypeFoldable + Relate; - type Abi: Abi + TypeFoldable + Relate; + type Safety: Safety; + type Abi: Abi; // Kinds of consts type Const: Const; -- cgit 1.4.1-3-g733a5 From ed1618dedc77b4984e8267ba015728aac665e360 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Jun 2024 15:35:38 +0200 Subject: MIR visitor: constant -> const_operand --- compiler/rustc_borrowck/src/renumber.rs | 2 +- compiler/rustc_borrowck/src/type_check/mod.rs | 6 +++--- compiler/rustc_middle/src/mir/pretty.rs | 4 ++-- compiler/rustc_middle/src/mir/visit.rs | 14 +++++++------- compiler/rustc_mir_transform/src/known_panics_lint.rs | 6 +++--- compiler/rustc_mir_transform/src/promote_consts.rs | 2 +- compiler/rustc_mir_transform/src/required_consts.rs | 2 +- compiler/rustc_mir_transform/src/reveal_all.rs | 4 ++-- compiler/rustc_monomorphize/src/collector.rs | 2 +- compiler/rustc_monomorphize/src/polymorphize.rs | 2 +- compiler/rustc_smir/src/rustc_smir/builder.rs | 8 ++++++-- 11 files changed, 28 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index d382f264c37..2858a407e09 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> { } #[instrument(skip(self), level = "debug")] - fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { + fn visit_const_operand(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { let const_ = constant.const_; constant.const_ = self.renumber_regions(const_, || RegionCtxt::Location(location)); debug!("constant: {:#?}", constant); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index fcfb297d50a..d51e3dbba3c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -301,10 +301,10 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { self.sanitize_place(place, location, context); } - fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) { - debug!(?constant, ?location, "visit_constant"); + fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, location: Location) { + debug!(?constant, ?location, "visit_const_operand"); - self.super_constant(constant, location); + self.super_const_operand(constant, location); let ty = self.sanitize_type(constant, constant.const_.ty()); self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index b64b7e2b1dc..f1c3cb69896 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1287,7 +1287,7 @@ fn use_verbose(ty: Ty<'_>, fn_def: bool) -> bool { } impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { - fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _location: Location) { + fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, _location: Location) { let ConstOperand { span, user_ty, const_ } = constant; if use_verbose(const_.ty(), true) { self.push("mir::ConstOperand"); @@ -1415,7 +1415,7 @@ pub fn write_allocations<'tcx>( struct CollectAllocIds(BTreeSet); impl<'tcx> Visitor<'tcx> for CollectAllocIds { - fn visit_constant(&mut self, c: &ConstOperand<'tcx>, _: Location) { + fn visit_const_operand(&mut self, c: &ConstOperand<'tcx>, _: Location) { match c.const_ { Const::Ty(_, _) | Const::Unevaluated(..) => {} Const::Val(val, _) => { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index f553b417294..10609e56f2c 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -184,12 +184,12 @@ macro_rules! make_mir_visitor { /// This is called for every constant in the MIR body and every `required_consts` /// (i.e., including consts that have been dead-code-eliminated). - fn visit_constant( + fn visit_const_operand( &mut self, constant: & $($mutability)? ConstOperand<'tcx>, location: Location, ) { - self.super_constant(constant, location); + self.super_const_operand(constant, location); } fn visit_ty_const( @@ -597,7 +597,7 @@ macro_rules! make_mir_visitor { } InlineAsmOperand::Const { value } | InlineAsmOperand::SymFn { value } => { - self.visit_constant(value, location); + self.visit_const_operand(value, location); } InlineAsmOperand::Out { place: None, .. } | InlineAsmOperand::SymStatic { def_id: _ } @@ -788,7 +788,7 @@ macro_rules! make_mir_visitor { ); } Operand::Constant(constant) => { - self.visit_constant(constant, location); + self.visit_const_operand(constant, location); } } } @@ -867,7 +867,7 @@ macro_rules! make_mir_visitor { } } match value { - VarDebugInfoContents::Const(c) => self.visit_constant(c, location), + VarDebugInfoContents::Const(c) => self.visit_const_operand(c, location), VarDebugInfoContents::Place(place) => self.visit_place( place, @@ -882,7 +882,7 @@ macro_rules! make_mir_visitor { _scope: $(& $mutability)? SourceScope ) {} - fn super_constant( + fn super_const_operand( &mut self, constant: & $($mutability)? ConstOperand<'tcx>, location: Location @@ -1057,7 +1057,7 @@ macro_rules! super_body { for const_ in &$($mutability)? $body.required_consts { let location = Location::START; - $self.visit_constant(const_, location); + $self.visit_const_operand(const_, location); } } } diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 6a20b46e7f9..8d6c00bbedb 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -706,9 +706,9 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { self.super_operand(operand, location); } - fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) { - trace!("visit_constant: {:?}", constant); - self.super_constant(constant, location); + fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, location: Location) { + trace!("visit_const_operand: {:?}", constant); + self.super_const_operand(constant, location); self.eval_constant(constant); } diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index ecd1179ca99..ecdca8292b4 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -956,7 +956,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { } } - fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, _location: Location) { + fn visit_const_operand(&mut self, constant: &mut ConstOperand<'tcx>, _location: Location) { if constant.const_.is_required_const() { self.promoted.required_consts.push(*constant); } diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs index 71ac929d35e..00bfb5e6600 100644 --- a/compiler/rustc_mir_transform/src/required_consts.rs +++ b/compiler/rustc_mir_transform/src/required_consts.rs @@ -12,7 +12,7 @@ impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { } impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> { - fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _: Location) { + fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, _: Location) { if constant.const_.is_required_const() { self.required_consts.push(*constant); } diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs index 4d2eca57840..5eaa024f846 100644 --- a/compiler/rustc_mir_transform/src/reveal_all.rs +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -49,14 +49,14 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> { } #[inline] - fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { + fn visit_const_operand(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { // We have to use `try_normalize_erasing_regions` here, since it's // possible that we visit impossible-to-satisfy where clauses here, // see #91745 if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.const_) { constant.const_ = c; } - self.super_constant(constant, location); + self.super_const_operand(constant, location); } #[inline] diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 61680dbfaf5..91eaa957d7e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -799,7 +799,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { /// This does not walk the MIR of the constant as that is not needed for codegen, all we need is /// to ensure that the constant evaluates successfully and walk the result. #[instrument(skip(self), level = "debug")] - fn visit_constant(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) { + fn visit_const_operand(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) { // No `super_constant` as we don't care about `visit_ty`/`visit_ty_const`. let Some(val) = self.eval_constant(constant) else { return }; collect_const_value(self.tcx, val, self.used_items); diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index a3ca9e9f9cf..c187cb63ee1 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -261,7 +261,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.super_local_decl(local, local_decl); } - fn visit_constant(&mut self, ct: &mir::ConstOperand<'tcx>, location: Location) { + fn visit_const_operand(&mut self, ct: &mir::ConstOperand<'tcx>, location: Location) { match ct.const_ { mir::Const::Ty(_, c) => { c.visit_with(self); diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs index 221224eed01..577373cbc95 100644 --- a/compiler/rustc_smir/src/rustc_smir/builder.rs +++ b/compiler/rustc_smir/src/rustc_smir/builder.rs @@ -52,7 +52,11 @@ impl<'tcx> BodyBuilder<'tcx> { } impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { - fn visit_constant(&mut self, constant: &mut mir::ConstOperand<'tcx>, location: mir::Location) { + fn visit_const_operand( + &mut self, + constant: &mut mir::ConstOperand<'tcx>, + location: mir::Location, + ) { let const_ = constant.const_; let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), constant.span) { Ok(v) => v, @@ -63,7 +67,7 @@ impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { }; let ty = constant.ty(); constant.const_ = mir::Const::Val(val, ty); - self.super_constant(constant, location); + self.super_const_operand(constant, location); } fn tcx(&self) -> TyCtxt<'tcx> { -- cgit 1.4.1-3-g733a5 From c8e42065f0f1d1a5cdb29c4279b1f2c25bc8737b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 13 Jun 2024 09:47:42 -0400 Subject: Address nits - Remove the ValuePairs glob import - Make DummyPairs -> ValuePairs::Dummy and make it bug more - Fix WC - Make interner return `impl IntoIterator`s --- compiler/rustc_infer/src/infer/at.rs | 37 ++++++++++------- .../rustc_infer/src/infer/error_reporting/mod.rs | 22 ++++++----- compiler/rustc_infer/src/infer/mod.rs | 11 +++--- compiler/rustc_middle/src/ty/context.rs | 8 ++-- compiler/rustc_middle/src/ty/predicate.rs | 4 ++ .../src/solve/assembly/structural_traits.rs | 46 ++++++++++++---------- .../src/solve/inspect/build.rs | 7 ++-- compiler/rustc_type_ir/src/inherent.rs | 20 +--------- compiler/rustc_type_ir/src/interner.rs | 8 ++-- 9 files changed, 85 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 2d06a7c693f..5e9c3c64e39 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -347,7 +347,7 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } } @@ -359,7 +359,10 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { a: Self, b: Self, ) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: Regions(ExpectedFound::new(a_is_expected, a, b)) } + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)), + } } } @@ -372,7 +375,7 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } } @@ -388,13 +391,13 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { cause: cause.clone(), values: match (a.unpack(), b.unpack()) { (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => { - Regions(ExpectedFound::new(a_is_expected, a, b)) + ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)) } (GenericArgKind::Type(a), GenericArgKind::Type(b)) => { - Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) } (GenericArgKind::Const(a), GenericArgKind::Const(b)) => { - Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) } ( @@ -423,7 +426,10 @@ impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> { a: Self, b: Self, ) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: Terms(ExpectedFound::new(a_is_expected, a, b)) } + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a, b)), + } } } @@ -436,7 +442,7 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)), } } } @@ -450,7 +456,7 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } } @@ -462,7 +468,10 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> { a: Self, b: Self, ) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: Aliases(ExpectedFound::new(a_is_expected, a, b)) } + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a, b)), + } } } @@ -475,7 +484,7 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: PolySigs(ExpectedFound::new( + values: ValuePairs::PolySigs(ExpectedFound::new( a_is_expected, ty::Binder::dummy(a), ty::Binder::dummy(b), @@ -493,7 +502,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: PolySigs(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::PolySigs(ExpectedFound::new(a_is_expected, a, b)), } } } @@ -507,7 +516,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)), } } } @@ -521,7 +530,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)), } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index d8a2857a11d..7fb07a5d30c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1707,7 +1707,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ValuePairs::ExistentialProjection(_) => { (false, Mismatch::Fixed("existential projection")) } - infer::DummyPair => (false, Mismatch::Fixed("values")), + ValuePairs::Dummy => { + bug!("do not expect to report a type error from a ValuePairs::Dummy") + } }; let Some(vals) = self.values_str(values) else { // Derived error. Cancel the emitter. @@ -2251,12 +2253,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { values: ValuePairs<'tcx>, ) -> Option<(DiagStyledString, DiagStyledString, Option)> { match values { - infer::Regions(exp_found) => self.expected_found_str(exp_found), - infer::Terms(exp_found) => self.expected_found_str_term(exp_found), - infer::Aliases(exp_found) => self.expected_found_str(exp_found), - infer::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), - infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), - infer::TraitRefs(exp_found) => { + ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found), + ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found), + ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found), + ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), + ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), + ValuePairs::TraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { expected: exp_found.expected.print_trait_sugared(), found: exp_found.found.print_trait_sugared(), @@ -2268,7 +2270,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ret => ret, } } - infer::PolySigs(exp_found) => { + ValuePairs::PolySigs(exp_found) => { let exp_found = self.resolve_vars_if_possible(exp_found); if exp_found.references_error() { return None; @@ -2276,7 +2278,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let (exp, fnd) = self.cmp_fn_sig(&exp_found.expected, &exp_found.found); Some((exp, fnd, None)) } - infer::DummyPair => None, + ValuePairs::Dummy => { + bug!("do not expect to report a type error from a ValuePairs::Dummy") + } } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 6f40b9f7295..dcf415e720f 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -9,7 +9,6 @@ pub use rustc_middle::ty::IntVarValue; pub use BoundRegionConversionTime::*; pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; -pub use ValuePairs::*; use crate::infer::relate::{Relate, RelateResult}; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; @@ -484,7 +483,7 @@ pub enum ValuePairs<'tcx> { PolySigs(ExpectedFound>), ExistentialTraitRef(ExpectedFound>), ExistentialProjection(ExpectedFound>), - DummyPair, + Dummy, } impl<'tcx> ValuePairs<'tcx> { @@ -1880,7 +1879,7 @@ impl<'tcx> TypeTrace<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } @@ -1892,7 +1891,7 @@ impl<'tcx> TypeTrace<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)), } } @@ -1904,12 +1903,12 @@ impl<'tcx> TypeTrace<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } fn dummy(cause: &ObligationCause<'tcx>) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: ValuePairs::DummyPair } + TypeTrace { cause: cause.clone(), values: ValuePairs::Dummy } } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 849e10a952b..3651c990c97 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -263,7 +263,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn bound_coroutine_hidden_types( self, def_id: DefId, - ) -> impl Iterator>>> { + ) -> impl IntoIterator>>> { self.bound_coroutine_hidden_types(def_id) } @@ -286,14 +286,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn item_bounds( self, def_id: DefId, - ) -> ty::EarlyBinder<'tcx, impl Iterator>> { + ) -> ty::EarlyBinder<'tcx, impl IntoIterator>> { self.item_bounds(def_id).map_bound(IntoIterator::into_iter) } fn super_predicates_of( self, def_id: DefId, - ) -> ty::EarlyBinder<'tcx, impl Iterator>> { + ) -> ty::EarlyBinder<'tcx, impl IntoIterator>> { ty::EarlyBinder::bind( self.super_predicates_of(def_id).instantiate_identity(self).predicates.into_iter(), ) @@ -315,7 +315,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) } - fn associated_type_def_ids(self, def_id: DefId) -> impl Iterator { + fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator { self.associated_items(def_id) .in_definition_order() .filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type)) diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 0f63490ea01..ae36f2624ca 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -49,6 +49,10 @@ impl<'tcx> rustc_type_ir::inherent::Predicate> for Predicate<'tcx> fn is_coinductive(self, interner: TyCtxt<'tcx>) -> bool { self.is_coinductive(interner) } + + fn allow_normalization(self) -> bool { + self.allow_normalization() + } } impl<'tcx> rustc_type_ir::inherent::IntoKind for Predicate<'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index f232ddcf797..d6074617caf 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -17,13 +17,14 @@ use crate::solve::EvalCtxt; // For types with an "existential" binder, i.e. coroutine witnesses, we also // instantiate the binder with placeholders eagerly. #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait< - Infcx: InferCtxtLike, - I: Interner, ->( +pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait( ecx: &EvalCtxt<'_, Infcx>, ty: I::Ty, -) -> Result>, NoSolution> { +) -> Result>, NoSolution> +where + Infcx: InferCtxtLike, + I: Interner, +{ let tcx = ecx.interner(); match ty.kind() { ty::Uint(_) @@ -79,6 +80,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait< ty::CoroutineWitness(def_id, args) => Ok(ecx .interner() .bound_coroutine_hidden_types(def_id) + .into_iter() .map(|bty| bty.instantiate(tcx, &args)) .collect()), @@ -101,13 +103,14 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait< } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait< - Infcx: InferCtxtLike, - I: Interner, ->( +pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait( ecx: &EvalCtxt<'_, Infcx>, ty: I::Ty, -) -> Result>, NoSolution> { +) -> Result>, NoSolution> +where + Infcx: InferCtxtLike, + I: Interner, +{ match ty.kind() { // impl Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char, &mut? T, [T; N], dyn* Trait, ! // impl Sized for Coroutine, CoroutineWitness, Closure, CoroutineClosure @@ -168,13 +171,14 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait< } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait< - Infcx: InferCtxtLike, - I: Interner, ->( +pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait( ecx: &EvalCtxt<'_, Infcx>, ty: I::Ty, -) -> Result>, NoSolution> { +) -> Result>, NoSolution> +where + Infcx: InferCtxtLike, + I: Interner, +{ match ty.kind() { // impl Copy/Clone for FnDef, FnPtr ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]), @@ -239,6 +243,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait< ty::CoroutineWitness(def_id, args) => Ok(ecx .interner() .bound_coroutine_hidden_types(def_id) + .into_iter() .map(|bty| bty.instantiate(ecx.interner(), &args)) .collect()), } @@ -651,15 +656,16 @@ fn coroutine_closure_to_ambiguous_coroutine( // This is unsound in general and once that is fixed, we don't need to // normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9 // for more details. -pub(in crate::solve) fn predicates_for_object_candidate< - Infcx: InferCtxtLike, - I: Interner, ->( +pub(in crate::solve) fn predicates_for_object_candidate( ecx: &EvalCtxt<'_, Infcx>, param_env: I::ParamEnv, trait_ref: ty::TraitRef, object_bounds: I::BoundExistentialPredicates, -) -> Vec> { +) -> Vec> +where + Infcx: InferCtxtLike, + I: Interner, +{ let tcx = ecx.interner(); let mut requirements = vec![]; requirements diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index 84c04900ae4..35750598bc7 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -34,10 +34,11 @@ use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; /// trees. At the end of trait solving `ProofTreeBuilder::finalize` /// is called to recursively convert the whole structure to a /// finished proof tree. -pub(in crate::solve) struct ProofTreeBuilder< +pub(in crate::solve) struct ProofTreeBuilder::Interner> +where Infcx: InferCtxtLike, - I: Interner = ::Interner, -> { + I: Interner, +{ _infcx: PhantomData, state: Option>>, } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 3f919d4b876..6b84592978a 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -305,24 +305,8 @@ pub trait Predicate>: { fn is_coinductive(self, interner: I) -> bool; - fn allow_normalization(self) -> bool { - match self.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::NormalizesTo(..) => false, - ty::PredicateKind::Clause(ty::ClauseKind::Trait(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) - | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::Subtype(_) - | ty::PredicateKind::Coerce(_) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(_)) - | ty::PredicateKind::ConstEquate(_, _) - | ty::PredicateKind::Ambiguous => true, - } - } + // FIXME: Eventually uplift the impl out of rustc and make this defaulted. + fn allow_normalization(self) -> bool; } pub trait Clause>: diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index bcf6c9b1a0e..a2b71e1fc25 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -152,7 +152,7 @@ pub trait Interner: fn bound_coroutine_hidden_types( self, def_id: Self::DefId, - ) -> impl Iterator>>; + ) -> impl IntoIterator>>; fn fn_sig( self, @@ -168,18 +168,18 @@ pub trait Interner: fn item_bounds( self, def_id: Self::DefId, - ) -> ty::EarlyBinder>; + ) -> ty::EarlyBinder>; fn super_predicates_of( self, def_id: Self::DefId, - ) -> ty::EarlyBinder>; + ) -> ty::EarlyBinder>; fn has_target_features(self, def_id: Self::DefId) -> bool; fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId; - fn associated_type_def_ids(self, def_id: Self::DefId) -> impl Iterator; + fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` -- cgit 1.4.1-3-g733a5 From b89a0a7838dc95362235a17d6f3d2cb90f466728 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 13 Jun 2024 16:04:31 +0200 Subject: Add debuginfo tests for collapse_debuginfo for statics. --- .../collapse-debuginfo-static-external.rs | 24 ++++++++++++++++++++++ tests/debuginfo/collapse-debuginfo-static.rs | 24 ++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/debuginfo/collapse-debuginfo-static-external.rs create mode 100644 tests/debuginfo/collapse-debuginfo-static.rs diff --git a/tests/debuginfo/collapse-debuginfo-static-external.rs b/tests/debuginfo/collapse-debuginfo-static-external.rs new file mode 100644 index 00000000000..2209bb9bd94 --- /dev/null +++ b/tests/debuginfo/collapse-debuginfo-static-external.rs @@ -0,0 +1,24 @@ +//@ ignore-lldb + +// Test that static debug info is not collapsed with #[collapse_debuginfo(external)] + +//@ compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:info line collapse_debuginfo_static_external::FOO +// gdb-check:[...]Line 15[...] + +#[collapse_debuginfo(external)] +macro_rules! decl_foo { + () => { + static FOO: u32 = 0; + }; +} + +decl_foo!(); + +fn main() { + // prevent FOO from getting optimized out + std::hint::black_box(&FOO); +} diff --git a/tests/debuginfo/collapse-debuginfo-static.rs b/tests/debuginfo/collapse-debuginfo-static.rs new file mode 100644 index 00000000000..e6469da4785 --- /dev/null +++ b/tests/debuginfo/collapse-debuginfo-static.rs @@ -0,0 +1,24 @@ +//@ ignore-lldb + +// Test that static debug info is collapsed with #[collapse_debuginfo(yes)] + +//@ compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:info line collapse_debuginfo_static::FOO +// gdb-check:[...]Line 19[...] + +#[collapse_debuginfo(yes)] +macro_rules! decl_foo { + () => { + static FOO: u32 = 0; + }; +} + +decl_foo!(); + +fn main() { + // prevent FOO from getting optimized out + std::hint::black_box(&FOO); +} -- cgit 1.4.1-3-g733a5 From dcee529e5c9dc505cc28b6b05d50b78ae2ab8b7e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Jun 2024 15:37:27 +0200 Subject: smir: merge identical Constant and ConstOperand types --- compiler/rustc_smir/src/rustc_smir/convert/mir.rs | 6 ++--- compiler/stable_mir/src/mir/body.rs | 27 +++++++++-------------- compiler/stable_mir/src/mir/pretty.rs | 2 +- compiler/stable_mir/src/mir/visit.rs | 12 +++++----- tests/ui-fulldeps/stable-mir/check_transform.rs | 8 +++---- 5 files changed, 24 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index bcacf54baf3..f15b82d0c03 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -328,13 +328,13 @@ impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> { } impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> { - type T = stable_mir::mir::Constant; + type T = stable_mir::mir::ConstOperand; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - stable_mir::mir::Constant { + stable_mir::mir::ConstOperand { span: self.span.stable(tables), user_ty: self.user_ty.map(|u| u.as_usize()).or(None), - literal: self.const_.stable(tables), + const_: self.const_.stable(tables), } } } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 43e4682dc10..e0f9e7ae67a 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -637,7 +637,7 @@ pub enum AggregateKind { pub enum Operand { Copy(Place), Move(Place), - Constant(Constant), + Constant(ConstOperand), } #[derive(Clone, Eq, PartialEq)] @@ -653,6 +653,13 @@ impl From for Place { } } +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ConstOperand { + pub span: Span, + pub user_ty: Option, + pub const_: MirConst, +} + /// Debug information pertaining to a user variable. #[derive(Clone, Debug, Eq, PartialEq)] pub struct VarDebugInfo { @@ -714,13 +721,6 @@ pub enum VarDebugInfoContents { Const(ConstOperand), } -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ConstOperand { - pub span: Span, - pub user_ty: Option, - pub const_: MirConst, -} - // In MIR ProjectionElem is parameterized on the second Field argument and the Index argument. This // is so it can be used for both Places (for which the projection elements are of type // ProjectionElem) and user-provided type annotations (for which the projection elements @@ -829,13 +829,6 @@ pub type FieldIdx = usize; type UserTypeAnnotationIndex = usize; -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Constant { - pub span: Span, - pub user_ty: Option, - pub literal: MirConst, -} - /// The possible branch sites of a [TerminatorKind::SwitchInt]. #[derive(Clone, Debug, Eq, PartialEq)] pub struct SwitchTargets { @@ -1001,9 +994,9 @@ impl Operand { } } -impl Constant { +impl ConstOperand { pub fn ty(&self) -> Ty { - self.literal.ty() + self.const_.ty() } } diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index 2fb180b84c7..83734a0d138 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -310,7 +310,7 @@ fn pretty_operand(operand: &Operand) -> String { Operand::Move(mv) => { format!("move {:?}", mv) } - Operand::Constant(cnst) => pretty_mir_const(&cnst.literal), + Operand::Constant(cnst) => pretty_mir_const(&cnst.const_), } } diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index 10f30083dc2..50d7bae21db 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -108,8 +108,8 @@ pub trait MirVisitor { self.super_ty(ty) } - fn visit_constant(&mut self, constant: &Constant, location: Location) { - self.super_constant(constant, location) + fn visit_const_operand(&mut self, constant: &ConstOperand, location: Location) { + self.super_const_operand(constant, location) } fn visit_mir_const(&mut self, constant: &MirConst, location: Location) { @@ -366,7 +366,7 @@ pub trait MirVisitor { self.visit_place(place, PlaceContext::NON_MUTATING, location) } Operand::Constant(constant) => { - self.visit_constant(constant, location); + self.visit_const_operand(constant, location); } } } @@ -380,10 +380,10 @@ pub trait MirVisitor { let _ = ty; } - fn super_constant(&mut self, constant: &Constant, location: Location) { - let Constant { span, user_ty: _, literal } = constant; + fn super_const_operand(&mut self, constant: &ConstOperand, location: Location) { + let ConstOperand { span, user_ty: _, const_ } = constant; self.visit_span(span); - self.visit_mir_const(literal, location); + self.visit_mir_const(const_, location); } fn super_mir_const(&mut self, constant: &MirConst, location: Location) { diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs index b203e76e54f..1d3e4c6845b 100644 --- a/tests/ui-fulldeps/stable-mir/check_transform.rs +++ b/tests/ui-fulldeps/stable-mir/check_transform.rs @@ -21,7 +21,7 @@ extern crate stable_mir; use rustc_smir::rustc_internal; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::Instance; -use stable_mir::mir::{Body, Constant, Operand, Rvalue, StatementKind, TerminatorKind}; +use stable_mir::mir::{Body, ConstOperand, Operand, Rvalue, StatementKind, TerminatorKind}; use stable_mir::ty::{ConstantKind, MirConst}; use stable_mir::{CrateDef, CrateItems, ItemKind}; use std::convert::TryFrom; @@ -72,7 +72,7 @@ fn check_msg(body: &Body, expected: &str) { .unwrap() } }; - let ConstantKind::Allocated(alloc) = msg_const.literal.kind() else { + let ConstantKind::Allocated(alloc) = msg_const.const_.kind() else { unreachable!() }; assert_eq!(alloc.provenance.ptrs.len(), 1); @@ -96,8 +96,8 @@ fn change_panic_msg(mut body: Body, new_msg: &str) -> Body { match &mut bb.terminator.kind { TerminatorKind::Call { args, .. } => { let new_const = MirConst::from_str(new_msg); - args[0] = Operand::Constant(Constant { - literal: new_const, + args[0] = Operand::Constant(ConstOperand { + const_: new_const, span: bb.terminator.span, user_ty: None, }); -- cgit 1.4.1-3-g733a5 From dfc55145270c5ec8de1bcd19ae05f056100108a5 Mon Sep 17 00:00:00 2001 From: beetrees Date: Thu, 13 Jun 2024 16:09:45 +0100 Subject: Add `f16` and `f128` inline ASM support for `x86` and `x86-64` --- compiler/rustc_codegen_llvm/src/asm.rs | 100 +++++++++ .../rustc_hir_analysis/src/check/intrinsicck.rs | 4 + compiler/rustc_target/src/asm/mod.rs | 12 + compiler/rustc_target/src/asm/x86.rs | 22 +- tests/assembly/asm/x86-types.rs | 244 ++++++++++++++++++--- tests/ui/asm/x86_64/type-check-3.stderr | 10 +- 6 files changed, 350 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index db28c6857b7..60e63b956db 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -959,6 +959,43 @@ fn llvm_fixup_input<'ll, 'tcx>( InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), Abi::Vector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, bx.cx.type_vector(bx.cx.type_f64(), 8)), + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if bx.sess().asm_arch == Some(InlineAsmArch::X86) + && s.primitive() == Primitive::Float(Float::F128) => + { + bx.bitcast(value, bx.type_vector(bx.type_i32(), 4)) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if s.primitive() == Primitive::Float(Float::F16) => { + let value = bx.insert_element( + bx.const_undef(bx.type_vector(bx.type_f16(), 8)), + value, + bx.const_usize(0), + ); + bx.bitcast(value, bx.type_vector(bx.type_i16(), 8)) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Vector { element, count: count @ (8 | 16) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) + } ( InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s), @@ -1036,6 +1073,39 @@ fn llvm_fixup_output<'ll, 'tcx>( InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), Abi::Vector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, layout.llvm_type(bx.cx)), + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if bx.sess().asm_arch == Some(InlineAsmArch::X86) + && s.primitive() == Primitive::Float(Float::F128) => + { + bx.bitcast(value, bx.type_f128()) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if s.primitive() == Primitive::Float(Float::F16) => { + let value = bx.bitcast(value, bx.type_vector(bx.type_f16(), 8)); + bx.extract_element(value, bx.const_usize(0)) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Vector { element, count: count @ (8 | 16) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) + } ( InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s), @@ -1109,6 +1179,36 @@ fn llvm_fixup_output_type<'ll, 'tcx>( InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), Abi::Vector { .. }, ) if layout.size.bytes() == 64 => cx.type_vector(cx.type_f64(), 8), + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if cx.sess().asm_arch == Some(InlineAsmArch::X86) + && s.primitive() == Primitive::Float(Float::F128) => + { + cx.type_vector(cx.type_i32(), 4) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if s.primitive() == Primitive::Float(Float::F16) => cx.type_vector(cx.type_i16(), 8), + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Vector { element, count: count @ (8 | 16) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + cx.type_vector(cx.type_i16(), count) + } ( InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s), diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 2672614a895..88cbd0217f2 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -62,8 +62,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Some(InlineAsmType::I64), ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Some(InlineAsmType::I128), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(asm_ty_isize), + ty::Float(FloatTy::F16) => Some(InlineAsmType::F16), ty::Float(FloatTy::F32) => Some(InlineAsmType::F32), ty::Float(FloatTy::F64) => Some(InlineAsmType::F64), + ty::Float(FloatTy::F128) => Some(InlineAsmType::F128), ty::FnPtr(_) => Some(asm_ty_isize), ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Some(asm_ty_isize), ty::Adt(adt, args) if adt.repr().simd() => { @@ -105,8 +107,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { width => bug!("unsupported pointer width: {width}"), }) } + ty::Float(FloatTy::F16) => Some(InlineAsmType::VecF16(size)), ty::Float(FloatTy::F32) => Some(InlineAsmType::VecF32(size)), ty::Float(FloatTy::F64) => Some(InlineAsmType::VecF64(size)), + ty::Float(FloatTy::F128) => Some(InlineAsmType::VecF128(size)), _ => None, } } diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 5f4ce5ed599..b057bf94a08 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -707,15 +707,19 @@ pub enum InlineAsmType { I32, I64, I128, + F16, F32, F64, + F128, VecI8(u64), VecI16(u64), VecI32(u64), VecI64(u64), VecI128(u64), + VecF16(u64), VecF32(u64), VecF64(u64), + VecF128(u64), } impl InlineAsmType { @@ -730,15 +734,19 @@ impl InlineAsmType { Self::I32 => 4, Self::I64 => 8, Self::I128 => 16, + Self::F16 => 2, Self::F32 => 4, Self::F64 => 8, + Self::F128 => 16, Self::VecI8(n) => n * 1, Self::VecI16(n) => n * 2, Self::VecI32(n) => n * 4, Self::VecI64(n) => n * 8, Self::VecI128(n) => n * 16, + Self::VecF16(n) => n * 2, Self::VecF32(n) => n * 4, Self::VecF64(n) => n * 8, + Self::VecF128(n) => n * 16, }) } } @@ -751,15 +759,19 @@ impl fmt::Display for InlineAsmType { Self::I32 => f.write_str("i32"), Self::I64 => f.write_str("i64"), Self::I128 => f.write_str("i128"), + Self::F16 => f.write_str("f16"), Self::F32 => f.write_str("f32"), Self::F64 => f.write_str("f64"), + Self::F128 => f.write_str("f128"), Self::VecI8(n) => write!(f, "i8x{n}"), Self::VecI16(n) => write!(f, "i16x{n}"), Self::VecI32(n) => write!(f, "i32x{n}"), Self::VecI64(n) => write!(f, "i64x{n}"), Self::VecI128(n) => write!(f, "i128x{n}"), + Self::VecF16(n) => write!(f, "f16x{n}"), Self::VecF32(n) => write!(f, "f32x{n}"), Self::VecF64(n) => write!(f, "f64x{n}"), + Self::VecF128(n) => write!(f, "f128x{n}"), } } } diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs index 28413a5bcbd..8452961c17c 100644 --- a/compiler/rustc_target/src/asm/x86.rs +++ b/compiler/rustc_target/src/asm/x86.rs @@ -107,26 +107,26 @@ impl X86InlineAsmRegClass { match self { Self::reg | Self::reg_abcd => { if arch == InlineAsmArch::X86_64 { - types! { _: I16, I32, I64, F32, F64; } + types! { _: I16, I32, I64, F16, F32, F64; } } else { - types! { _: I16, I32, F32; } + types! { _: I16, I32, F16, F32; } } } Self::reg_byte => types! { _: I8; }, Self::xmm_reg => types! { - sse: I32, I64, F32, F64, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); + sse: I32, I64, F16, F32, F64, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); }, Self::ymm_reg => types! { - avx: I32, I64, F32, F64, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4); + avx: I32, I64, F16, F32, F64, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), + VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4); }, Self::zmm_reg => types! { - avx512f: I32, I64, F32, F64, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4), - VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF32(16), VecF64(8); + avx512f: I32, I64, F16, F32, F64, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), + VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4), + VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF16(32), VecF32(16), VecF64(8); }, Self::kreg => types! { avx512f: I8, I16; diff --git a/tests/assembly/asm/x86-types.rs b/tests/assembly/asm/x86-types.rs index 2b4ebb05349..8e229614420 100644 --- a/tests/assembly/asm/x86-types.rs +++ b/tests/assembly/asm/x86-types.rs @@ -7,7 +7,7 @@ //@ compile-flags: -C llvm-args=--x86-asm-syntax=intel //@ compile-flags: -C target-feature=+avx512bw -#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![feature(no_core, lang_items, rustc_attrs, repr_simd, f16, f128)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] @@ -41,6 +41,8 @@ pub struct i32x4(i32, i32, i32, i32); #[repr(simd)] pub struct i64x2(i64, i64); #[repr(simd)] +pub struct f16x8(f16, f16, f16, f16, f16, f16, f16, f16); +#[repr(simd)] pub struct f32x4(f32, f32, f32, f32); #[repr(simd)] pub struct f64x2(f64, f64); @@ -87,6 +89,8 @@ pub struct i32x8(i32, i32, i32, i32, i32, i32, i32, i32); #[repr(simd)] pub struct i64x4(i64, i64, i64, i64); #[repr(simd)] +pub struct f16x16(f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16); +#[repr(simd)] pub struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); #[repr(simd)] pub struct f64x4(f64, f64, f64, f64); @@ -198,35 +202,59 @@ pub struct i32x16(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i3 #[repr(simd)] pub struct i64x8(i64, i64, i64, i64, i64, i64, i64, i64); #[repr(simd)] +pub struct f16x32( + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, +); +#[repr(simd)] pub struct f32x16(f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32); #[repr(simd)] pub struct f64x8(f64, f64, f64, f64, f64, f64, f64, f64); -impl Copy for i8 {} -impl Copy for i16 {} -impl Copy for i32 {} -impl Copy for f32 {} -impl Copy for i64 {} -impl Copy for f64 {} -impl Copy for ptr {} -impl Copy for i8x16 {} -impl Copy for i16x8 {} -impl Copy for i32x4 {} -impl Copy for i64x2 {} -impl Copy for f32x4 {} -impl Copy for f64x2 {} -impl Copy for i8x32 {} -impl Copy for i16x16 {} -impl Copy for i32x8 {} -impl Copy for i64x4 {} -impl Copy for f32x8 {} -impl Copy for f64x4 {} -impl Copy for i8x64 {} -impl Copy for i16x32 {} -impl Copy for i32x16 {} -impl Copy for i64x8 {} -impl Copy for f32x16 {} -impl Copy for f64x8 {} +macro_rules! impl_copy { + ($($ty:ident)*) => { + $( + impl Copy for $ty {} + )* + }; +} + +impl_copy!( + i8 i16 f16 i32 f32 i64 f64 f128 ptr + i8x16 i16x8 i32x4 i64x2 f16x8 f32x4 f64x2 + i8x32 i16x16 i32x8 i64x4 f16x16 f32x8 f64x4 + i8x64 i16x32 i32x16 i64x8 f16x32 f32x16 f64x8 +); extern "C" { fn extern_func(); @@ -292,6 +320,13 @@ macro_rules! check_reg { // CHECK: #NO_APP check!(reg_i16 i16 reg "mov"); +// CHECK-LABEL: reg_f16: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f16 f16 reg "mov"); + // CHECK-LABEL: reg_i32: // CHECK: #APP // x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} @@ -334,6 +369,13 @@ check!(reg_ptr ptr reg "mov"); // CHECK: #NO_APP check!(reg_abcd_i16 i16 reg_abcd "mov"); +// CHECK-LABEL: reg_abcd_f16: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_abcd_f16 f16 reg_abcd "mov"); + // CHECK-LABEL: reg_abcd_i32: // CHECK: #APP // x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} @@ -375,6 +417,12 @@ check!(reg_abcd_ptr ptr reg_abcd "mov"); // CHECK: #NO_APP check!(reg_byte i8 reg_byte "mov"); +// CHECK-LABEL: xmm_reg_f16: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f16 f16 xmm_reg "movaps"); + // CHECK-LABEL: xmm_reg_i32: // CHECK: #APP // CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} @@ -399,6 +447,12 @@ check!(xmm_reg_i64 i64 xmm_reg "movaps"); // CHECK: #NO_APP check!(xmm_reg_f64 f64 xmm_reg "movaps"); +// CHECK-LABEL: xmm_reg_f128: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f128 f128 xmm_reg "movaps"); + // CHECK-LABEL: xmm_reg_ptr: // CHECK: #APP // CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} @@ -429,6 +483,12 @@ check!(xmm_reg_i32x4 i32x4 xmm_reg "movaps"); // CHECK: #NO_APP check!(xmm_reg_i64x2 i64x2 xmm_reg "movaps"); +// CHECK-LABEL: xmm_reg_f16x8: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f16x8 f16x8 xmm_reg "movaps"); + // CHECK-LABEL: xmm_reg_f32x4: // CHECK: #APP // CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} @@ -441,6 +501,12 @@ check!(xmm_reg_f32x4 f32x4 xmm_reg "movaps"); // CHECK: #NO_APP check!(xmm_reg_f64x2 f64x2 xmm_reg "movaps"); +// CHECK-LABEL: ymm_reg_f16: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f16 f16 ymm_reg "vmovaps"); + // CHECK-LABEL: ymm_reg_i32: // CHECK: #APP // CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} @@ -465,6 +531,12 @@ check!(ymm_reg_i64 i64 ymm_reg "vmovaps"); // CHECK: #NO_APP check!(ymm_reg_f64 f64 ymm_reg "vmovaps"); +// CHECK-LABEL: ymm_reg_f128: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f128 f128 ymm_reg "vmovaps"); + // CHECK-LABEL: ymm_reg_ptr: // CHECK: #APP // CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} @@ -495,6 +567,12 @@ check!(ymm_reg_i32x4 i32x4 ymm_reg "vmovaps"); // CHECK: #NO_APP check!(ymm_reg_i64x2 i64x2 ymm_reg "vmovaps"); +// CHECK-LABEL: ymm_reg_f16x8: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f16x8 f16x8 ymm_reg "vmovaps"); + // CHECK-LABEL: ymm_reg_f32x4: // CHECK: #APP // CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} @@ -531,6 +609,12 @@ check!(ymm_reg_i32x8 i32x8 ymm_reg "vmovaps"); // CHECK: #NO_APP check!(ymm_reg_i64x4 i64x4 ymm_reg "vmovaps"); +// CHECK-LABEL: ymm_reg_f16x16: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f16x16 f16x16 ymm_reg "vmovaps"); + // CHECK-LABEL: ymm_reg_f32x8: // CHECK: #APP // CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} @@ -543,6 +627,12 @@ check!(ymm_reg_f32x8 f32x8 ymm_reg "vmovaps"); // CHECK: #NO_APP check!(ymm_reg_f64x4 f64x4 ymm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16 f16 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_i32: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -567,6 +657,12 @@ check!(zmm_reg_i64 i64 zmm_reg "vmovaps"); // CHECK: #NO_APP check!(zmm_reg_f64 f64 zmm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f128: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f128 f128 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_ptr: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -597,6 +693,12 @@ check!(zmm_reg_i32x4 i32x4 zmm_reg "vmovaps"); // CHECK: #NO_APP check!(zmm_reg_i64x2 i64x2 zmm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f16x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16x8 f16x8 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_f32x4: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -633,6 +735,12 @@ check!(zmm_reg_i32x8 i32x8 zmm_reg "vmovaps"); // CHECK: #NO_APP check!(zmm_reg_i64x4 i64x4 zmm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f16x16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16x16 f16x16 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_f32x8: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -669,6 +777,12 @@ check!(zmm_reg_i32x16 i32x16 zmm_reg "vmovaps"); // CHECK: #NO_APP check!(zmm_reg_i64x8 i64x8 zmm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f16x32: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16x32 f16x32 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_f32x16: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -717,6 +831,12 @@ check!(kreg_ptr ptr kreg "kmovq"); // CHECK: #NO_APP check_reg!(eax_i16 i16 "eax" "mov"); +// CHECK-LABEL: eax_f16: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check_reg!(eax_f16 f16 "eax" "mov"); + // CHECK-LABEL: eax_i32: // CHECK: #APP // CHECK: mov eax, eax @@ -756,6 +876,12 @@ check_reg!(eax_ptr ptr "eax" "mov"); #[cfg(i686)] check_reg!(ah_byte i8 "ah" "mov"); +// CHECK-LABEL: xmm0_f16: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f16 f16 "xmm0" "movaps"); + // CHECK-LABEL: xmm0_i32: // CHECK: #APP // CHECK: movaps xmm0, xmm0 @@ -780,6 +906,12 @@ check_reg!(xmm0_i64 i64 "xmm0" "movaps"); // CHECK: #NO_APP check_reg!(xmm0_f64 f64 "xmm0" "movaps"); +// CHECK-LABEL: xmm0_f128: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f128 f128 "xmm0" "movaps"); + // CHECK-LABEL: xmm0_ptr: // CHECK: #APP // CHECK: movaps xmm0, xmm0 @@ -810,6 +942,12 @@ check_reg!(xmm0_i32x4 i32x4 "xmm0" "movaps"); // CHECK: #NO_APP check_reg!(xmm0_i64x2 i64x2 "xmm0" "movaps"); +// CHECK-LABEL: xmm0_f16x8: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f16x8 f16x8 "xmm0" "movaps"); + // CHECK-LABEL: xmm0_f32x4: // CHECK: #APP // CHECK: movaps xmm0, xmm0 @@ -822,6 +960,12 @@ check_reg!(xmm0_f32x4 f32x4 "xmm0" "movaps"); // CHECK: #NO_APP check_reg!(xmm0_f64x2 f64x2 "xmm0" "movaps"); +// CHECK-LABEL: ymm0_f16: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f16 f16 "ymm0" "vmovaps"); + // CHECK-LABEL: ymm0_i32: // CHECK: #APP // CHECK: vmovaps ymm0, ymm0 @@ -846,6 +990,12 @@ check_reg!(ymm0_i64 i64 "ymm0" "vmovaps"); // CHECK: #NO_APP check_reg!(ymm0_f64 f64 "ymm0" "vmovaps"); +// CHECK-LABEL: ymm0_f128: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f128 f128 "ymm0" "vmovaps"); + // CHECK-LABEL: ymm0_ptr: // CHECK: #APP // CHECK: vmovaps ymm0, ymm0 @@ -876,6 +1026,12 @@ check_reg!(ymm0_i32x4 i32x4 "ymm0" "vmovaps"); // CHECK: #NO_APP check_reg!(ymm0_i64x2 i64x2 "ymm0" "vmovaps"); +// CHECK-LABEL: ymm0_f16x8: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f16x8 f16x8 "ymm0" "vmovaps"); + // CHECK-LABEL: ymm0_f32x4: // CHECK: #APP // CHECK: vmovaps ymm0, ymm0 @@ -912,6 +1068,12 @@ check_reg!(ymm0_i32x8 i32x8 "ymm0" "vmovaps"); // CHECK: #NO_APP check_reg!(ymm0_i64x4 i64x4 "ymm0" "vmovaps"); +// CHECK-LABEL: ymm0_f16x16: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f16x16 f16x16 "ymm0" "vmovaps"); + // CHECK-LABEL: ymm0_f32x8: // CHECK: #APP // CHECK: vmovaps ymm0, ymm0 @@ -924,6 +1086,12 @@ check_reg!(ymm0_f32x8 f32x8 "ymm0" "vmovaps"); // CHECK: #NO_APP check_reg!(ymm0_f64x4 f64x4 "ymm0" "vmovaps"); +// CHECK-LABEL: zmm0_f16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16 f16 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_i32: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 @@ -948,6 +1116,12 @@ check_reg!(zmm0_i64 i64 "zmm0" "vmovaps"); // CHECK: #NO_APP check_reg!(zmm0_f64 f64 "zmm0" "vmovaps"); +// CHECK-LABEL: zmm0_f128: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f128 f128 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_ptr: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 @@ -978,6 +1152,12 @@ check_reg!(zmm0_i32x4 i32x4 "zmm0" "vmovaps"); // CHECK: #NO_APP check_reg!(zmm0_i64x2 i64x2 "zmm0" "vmovaps"); +// CHECK-LABEL: zmm0_f16x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16x8 f16x8 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_f32x4: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 @@ -1014,6 +1194,12 @@ check_reg!(zmm0_i32x8 i32x8 "zmm0" "vmovaps"); // CHECK: #NO_APP check_reg!(zmm0_i64x4 i64x4 "zmm0" "vmovaps"); +// CHECK-LABEL: zmm0_f16x16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16x16 f16x16 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_f32x8: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 @@ -1050,6 +1236,12 @@ check_reg!(zmm0_i32x16 i32x16 "zmm0" "vmovaps"); // CHECK: #NO_APP check_reg!(zmm0_i64x8 i64x8 "zmm0" "vmovaps"); +// CHECK-LABEL: zmm0_f16x32: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16x32 f16x32 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_f32x16: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 diff --git a/tests/ui/asm/x86_64/type-check-3.stderr b/tests/ui/asm/x86_64/type-check-3.stderr index 34bfcd71cac..202b97ca5c0 100644 --- a/tests/ui/asm/x86_64/type-check-3.stderr +++ b/tests/ui/asm/x86_64/type-check-3.stderr @@ -4,7 +4,7 @@ error: type `i128` cannot be used with this register class LL | asm!("{}", in(reg) 0i128); | ^^^^^ | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f16, f32, f64 error: type `__m128` cannot be used with this register class --> $DIR/type-check-3.rs:16:28 @@ -12,7 +12,7 @@ error: type `__m128` cannot be used with this register class LL | asm!("{}", in(reg) _mm_setzero_ps()); | ^^^^^^^^^^^^^^^^ | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f16, f32, f64 error: type `__m256` cannot be used with this register class --> $DIR/type-check-3.rs:18:28 @@ -20,7 +20,7 @@ error: type `__m256` cannot be used with this register class LL | asm!("{}", in(reg) _mm256_setzero_ps()); | ^^^^^^^^^^^^^^^^^^^ | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f16, f32, f64 error: type `u8` cannot be used with this register class --> $DIR/type-check-3.rs:20:32 @@ -28,7 +28,7 @@ error: type `u8` cannot be used with this register class LL | asm!("{}", in(xmm_reg) 0u8); | ^^^ | - = note: register class `xmm_reg` supports these types: i32, i64, f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + = note: register class `xmm_reg` supports these types: i32, i64, f16, f32, f64, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 error: `avx512bw` target feature is not enabled --> $DIR/type-check-3.rs:29:29 @@ -81,7 +81,7 @@ error: type `i8` cannot be used with this register class LL | asm!("{}", in(reg) 0i8); | ^^^ | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f16, f32, f64 = help: consider using the `reg_byte` register class instead error: incompatible types for asm inout argument -- cgit 1.4.1-3-g733a5 From cc6541385f6e0ae85de021aaed650107c42725e4 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 6 Jun 2024 20:23:15 +0300 Subject: compiletest: apply considerable clippy suggestions Signed-off-by: onur-ozkan --- src/tools/compiletest/src/common.rs | 2 +- src/tools/compiletest/src/header.rs | 24 ++++++------ src/tools/compiletest/src/header/cfg.rs | 2 +- src/tools/compiletest/src/lib.rs | 2 +- src/tools/compiletest/src/read2.rs | 5 +-- src/tools/compiletest/src/read2/tests.rs | 6 +-- src/tools/compiletest/src/runtest.rs | 54 +++++++++++++-------------- src/tools/compiletest/src/runtest/debugger.rs | 2 +- src/tools/compiletest/src/tests.rs | 10 ++--- 9 files changed, 51 insertions(+), 56 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index b0047770564..da7f03441e7 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -582,7 +582,7 @@ impl TargetCfgs { name, Some( value - .strip_suffix("\"") + .strip_suffix('\"') .expect("key-value pair should be properly quoted"), ), ) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index cc972223f6d..ffc706d19a9 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -82,7 +82,7 @@ impl EarlyProps { panic!("errors encountered during EarlyProps parsing"); } - return props; + props } } @@ -382,7 +382,7 @@ impl TestProps { // Individual flags can be single-quoted to preserve spaces; see // . flags - .split("'") + .split('\'') .enumerate() .flat_map(|(i, f)| { if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() } @@ -613,7 +613,7 @@ impl TestProps { for key in &["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] { if let Ok(val) = env::var(key) { - if self.exec_env.iter().find(|&&(ref x, _)| x == key).is_none() { + if !self.exec_env.iter().any(|&(ref x, _)| x == key) { self.exec_env.push(((*key).to_owned(), val)) } } @@ -991,7 +991,7 @@ pub(crate) fn check_directive(directive_ln: &str) -> CheckDirectiveResult<'_> { let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post); let trailing_directive = { // 1. is the directive name followed by a space? (to exclude `:`) - matches!(directive_ln.get(directive_name.len()..), Some(s) if s.starts_with(" ")) + matches!(directive_ln.get(directive_name.len()..), Some(s) if s.starts_with(' ')) // 2. is what is after that directive also a directive (ex: "only-x86 only-arm") && KNOWN_DIRECTIVE_NAMES.contains(&trailing) } @@ -1363,7 +1363,7 @@ pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option { } let version = String::from_utf8(output.stdout).ok()?; for line in version.lines() { - if let Some(version) = line.split("LLVM version ").skip(1).next() { + if let Some(version) = line.split("LLVM version ").nth(1) { return extract_llvm_version(version); } } @@ -1394,7 +1394,7 @@ where let min = parse(min)?; let max = match max { - Some(max) if max.is_empty() => return None, + Some("") => return None, Some(max) => parse(max)?, _ => min, }; @@ -1466,12 +1466,12 @@ pub fn make_test_description( decision!(ignore_gdb(config, ln)); decision!(ignore_lldb(config, ln)); - if config.target == "wasm32-unknown-unknown" { - if config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) { - decision!(IgnoreDecision::Ignore { - reason: "ignored on WASM as the run results cannot be checked there".into(), - }); - } + if config.target == "wasm32-unknown-unknown" + && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) + { + decision!(IgnoreDecision::Ignore { + reason: "ignored on WASM as the run results cannot be checked there".into(), + }); } should_fail |= config.parse_name_directive(ln, "should-fail"); diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index 510043e3bfd..522c52b1de2 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -58,7 +58,7 @@ pub(super) fn parse_cfg_name_directive<'a>( // Some of the matchers might be "" depending on what the target information is. To avoid // problems we outright reject empty directives. - if name == "" { + if name.is_empty() { return ParsedNameDirective::not_a_directive(); } diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 62e71e9b59d..0cf05b32e96 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -1147,7 +1147,7 @@ fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> { } fn not_a_digit(c: char) -> bool { - !c.is_digit(10) + !c.is_ascii_digit() } fn check_overlapping_tests(found_paths: &HashSet) { diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs index 3f1921cb6bd..8c06339f3c3 100644 --- a/src/tools/compiletest/src/read2.rs +++ b/src/tools/compiletest/src/read2.rs @@ -6,7 +6,6 @@ mod tests; pub use self::imp::read2; use std::io::{self, Write}; -use std::mem::replace; use std::process::{Child, Output}; #[derive(Copy, Clone, Debug)] @@ -101,10 +100,10 @@ impl ProcOutput { return; } - let mut head = replace(bytes, Vec::new()); + let mut head = std::mem::take(bytes); // Don't truncate if this as a whole line. // That should make it less likely that we cut a JSON line in half. - if head.last() != Some(&('\n' as u8)) { + if head.last() != Some(&b'\n') { head.truncate(MAX_OUT_LEN); } let skipped = new_len - head.len(); diff --git a/src/tools/compiletest/src/read2/tests.rs b/src/tools/compiletest/src/read2/tests.rs index 5ad2db3cb83..9e052ff069b 100644 --- a/src/tools/compiletest/src/read2/tests.rs +++ b/src/tools/compiletest/src/read2/tests.rs @@ -64,9 +64,9 @@ fn test_abbreviate_filterss_are_detected() { #[test] fn test_abbreviate_filters_avoid_abbreviations() { let mut out = ProcOutput::new(); - let filters = &[std::iter::repeat('a').take(64).collect::()]; + let filters = &["a".repeat(64)]; - let mut expected = vec![b'.'; MAX_OUT_LEN - FILTERED_PATHS_PLACEHOLDER_LEN as usize]; + let mut expected = vec![b'.'; MAX_OUT_LEN - FILTERED_PATHS_PLACEHOLDER_LEN]; expected.extend_from_slice(filters[0].as_bytes()); out.extend(&expected, filters); @@ -81,7 +81,7 @@ fn test_abbreviate_filters_avoid_abbreviations() { #[test] fn test_abbreviate_filters_can_still_cause_abbreviations() { let mut out = ProcOutput::new(); - let filters = &[std::iter::repeat('a').take(64).collect::()]; + let filters = &["a".repeat(64)]; let mut input = vec![b'.'; MAX_OUT_LEN]; input.extend_from_slice(filters[0].as_bytes()); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 9e1d5ea61aa..72b57d91c23 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -374,11 +374,11 @@ impl<'test> TestCx<'test> { // if a test does not crash, consider it an error if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) { - self.fatal(&format!( + self.fatal( "test no longer crashes/triggers ICE! Please give it a mearningful name, \ add a doc-comment to the start of the test explaining why it exists and \ - move it to tests/ui or wherever you see fit." - )); + move it to tests/ui or wherever you see fit.", + ); } } @@ -697,10 +697,10 @@ impl<'test> TestCx<'test> { // since it is extensively used in the testsuite. check_cfg.push_str("cfg(FALSE"); for revision in &self.props.revisions { - check_cfg.push_str(","); - check_cfg.push_str(&normalize_revision(&revision)); + check_cfg.push(','); + check_cfg.push_str(&normalize_revision(revision)); } - check_cfg.push_str(")"); + check_cfg.push(')'); cmd.args(&["--check-cfg", &check_cfg]); } @@ -818,7 +818,7 @@ impl<'test> TestCx<'test> { // Append the other `cdb-command:`s for line in &dbg_cmds.commands { script_str.push_str(line); - script_str.push_str("\n"); + script_str.push('\n'); } script_str.push_str("qq\n"); // Quit the debugger (including remote debugger, if any) @@ -1200,7 +1200,7 @@ impl<'test> TestCx<'test> { // Append the other commands for line in &dbg_cmds.commands { script_str.push_str(line); - script_str.push_str("\n"); + script_str.push('\n'); } // Finally, quit the debugger @@ -1250,7 +1250,7 @@ impl<'test> TestCx<'test> { // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS. let options_to_remove = ["-O".to_owned(), "-g".to_owned(), "--debuginfo".to_owned()]; - options.iter().filter(|x| !options_to_remove.contains(x)).map(|x| x.clone()).collect() + options.iter().filter(|x| !options_to_remove.contains(x)).cloned().collect() } fn maybe_add_external_args(&self, cmd: &mut Command, args: &Vec) { @@ -2504,8 +2504,8 @@ impl<'test> TestCx<'test> { // This works with both `--emit asm` (as default output name for the assembly) // and `ptx-linker` because the latter can write output at requested location. let output_path = self.output_base_name().with_extension(extension); - let output_file = TargetLocation::ThisFile(output_path.clone()); - output_file + + TargetLocation::ThisFile(output_path.clone()) } } @@ -2752,7 +2752,7 @@ impl<'test> TestCx<'test> { for entry in walkdir::WalkDir::new(dir) { let entry = entry.expect("failed to read file"); if entry.file_type().is_file() - && entry.path().extension().and_then(|p| p.to_str()) == Some("html".into()) + && entry.path().extension().and_then(|p| p.to_str()) == Some("html") { let status = Command::new("tidy").args(&tidy_args).arg(entry.path()).status().unwrap(); @@ -2783,8 +2783,7 @@ impl<'test> TestCx<'test> { &compare_dir, self.config.verbose, |file_type, extension| { - file_type.is_file() - && (extension == Some("html".into()) || extension == Some("js".into())) + file_type.is_file() && (extension == Some("html") || extension == Some("js")) }, ) { return; @@ -2830,11 +2829,11 @@ impl<'test> TestCx<'test> { } match String::from_utf8(line.clone()) { Ok(line) => { - if line.starts_with("+") { + if line.starts_with('+') { write!(&mut out, "{}", line.green()).unwrap(); - } else if line.starts_with("-") { + } else if line.starts_with('-') { write!(&mut out, "{}", line.red()).unwrap(); - } else if line.starts_with("@") { + } else if line.starts_with('@') { write!(&mut out, "{}", line.blue()).unwrap(); } else { out.write_all(line.as_bytes()).unwrap(); @@ -2907,7 +2906,7 @@ impl<'test> TestCx<'test> { && line.ends_with(';') { if let Some(ref mut other_files) = other_files { - other_files.push(line.rsplit("mod ").next().unwrap().replace(";", "")); + other_files.push(line.rsplit("mod ").next().unwrap().replace(';', "")); } None } else { @@ -3139,7 +3138,7 @@ impl<'test> TestCx<'test> { let mut string = String::new(); for cgu in cgus { string.push_str(&cgu[..]); - string.push_str(" "); + string.push(' '); } string @@ -3172,10 +3171,7 @@ impl<'test> TestCx<'test> { // CGUs joined with "--". This function splits such composite CGU names // and handles each component individually. fn remove_crate_disambiguators_from_set_of_cgu_names(cgus: &str) -> String { - cgus.split("--") - .map(|cgu| remove_crate_disambiguator_from_cgu(cgu)) - .collect::>() - .join("--") + cgus.split("--").map(remove_crate_disambiguator_from_cgu).collect::>().join("--") } } @@ -3357,7 +3353,7 @@ impl<'test> TestCx<'test> { // endif } - if self.config.target.contains("msvc") && self.config.cc != "" { + if self.config.target.contains("msvc") && !self.config.cc.is_empty() { // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` // and that `lib.exe` lives next to it. let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); @@ -3639,7 +3635,7 @@ impl<'test> TestCx<'test> { // endif } - if self.config.target.contains("msvc") && self.config.cc != "" { + if self.config.target.contains("msvc") && !self.config.cc.is_empty() { // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` // and that `lib.exe` lives next to it. let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); @@ -3830,7 +3826,7 @@ impl<'test> TestCx<'test> { && !self.props.dont_check_compiler_stderr { self.fatal_proc_rec( - &format!("compiler output got truncated, cannot compare with reference file"), + "compiler output got truncated, cannot compare with reference file", &proc_res, ); } @@ -4011,8 +4007,8 @@ impl<'test> TestCx<'test> { crate_name.to_str().expect("crate name implies file name must be valid UTF-8"); // replace `a.foo` -> `a__foo` for crate name purposes. // replace `revision-name-with-dashes` -> `revision_name_with_underscore` - let crate_name = crate_name.replace(".", "__"); - let crate_name = crate_name.replace("-", "_"); + let crate_name = crate_name.replace('.', "__"); + let crate_name = crate_name.replace('-', "_"); rustc.arg("--crate-name"); rustc.arg(crate_name); } @@ -4060,7 +4056,7 @@ impl<'test> TestCx<'test> { fn check_mir_dump(&self, test_info: MiroptTest) { let test_dir = self.testpaths.file.parent().unwrap(); let test_crate = - self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace("-", "_"); + self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace('-', "_"); let MiroptTest { run_filecheck, suffix, files, passes: _ } = test_info; diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index eebe5f3580b..ed6cc97a8ab 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -148,5 +148,5 @@ fn check_single_line(line: &str, check_line: &str) -> bool { rest = &rest[pos + current_fragment.len()..]; } - if !can_end_anywhere && !rest.is_empty() { false } else { true } + can_end_anywhere || rest.is_empty() } diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index e6725dba260..4292f234adc 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -58,11 +58,11 @@ fn test_extract_lldb_version() { #[test] fn is_test_test() { - assert_eq!(true, is_test(&OsString::from("a_test.rs"))); - assert_eq!(false, is_test(&OsString::from(".a_test.rs"))); - assert_eq!(false, is_test(&OsString::from("a_cat.gif"))); - assert_eq!(false, is_test(&OsString::from("#a_dog_gif"))); - assert_eq!(false, is_test(&OsString::from("~a_temp_file"))); + assert!(is_test(&OsString::from("a_test.rs"))); + assert!(!is_test(&OsString::from(".a_test.rs"))); + assert!(!is_test(&OsString::from("a_cat.gif"))); + assert!(!is_test(&OsString::from("#a_dog_gif"))); + assert!(!is_test(&OsString::from("~a_temp_file"))); } #[test] -- cgit 1.4.1-3-g733a5 From a5ef43e1a50c359f8f95b21d62823a2f13d0c883 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 6 Jun 2024 21:00:56 +0300 Subject: build_helper: apply considerable clippy suggestions Signed-off-by: onur-ozkan --- src/tools/build_helper/src/git.rs | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs index a3c857b0268..b4522de6897 100644 --- a/src/tools/build_helper/src/git.rs +++ b/src/tools/build_helper/src/git.rs @@ -21,7 +21,7 @@ fn output_result(cmd: &mut Command) -> Result { String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? )); } - Ok(String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?) + String::from_utf8(output.stdout).map_err(|err| format!("{err:?}")) } /// Finds the remote for rust-lang/rust. @@ -64,18 +64,14 @@ pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result { match output.status.code() { Some(0) => Ok(true), Some(128) => Ok(false), - None => { - return Err(format!( - "git didn't exit properly: {}", - String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? - )); - } - Some(code) => { - return Err(format!( - "git command exited with status code: {code}: {}", - String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? - )); - } + None => Err(format!( + "git didn't exit properly: {}", + String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? + )), + Some(code) => Err(format!( + "git command exited with status code: {code}: {}", + String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? + )), } } @@ -96,7 +92,7 @@ pub fn updated_master_branch( } } - Err(format!("Cannot find any suitable upstream master branch")) + Err("Cannot find any suitable upstream master branch".to_owned()) } pub fn get_git_merge_base( @@ -118,7 +114,7 @@ pub fn get_git_merge_base( pub fn get_git_modified_files( config: &GitConfig<'_>, git_dir: Option<&Path>, - extensions: &Vec<&str>, + extensions: &[&str], ) -> Result>, String> { let merge_base = get_git_merge_base(config, git_dir)?; -- cgit 1.4.1-3-g733a5 From 4a7c1383673fd99bef60b7dda777e7ff4fd50186 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 6 Jun 2024 21:01:19 +0300 Subject: build-manifest: apply considerable clippy suggestions Signed-off-by: onur-ozkan --- src/tools/build-manifest/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 9f33e431274..b4d47cba7c5 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -495,7 +495,7 @@ impl Builder { Some(p) => p, None => return false, }; - pkg.target.get(&c.target).is_some() + pkg.target.contains_key(&c.target) }; extensions.retain(&has_component); components.retain(&has_component); -- cgit 1.4.1-3-g733a5 From 481dcb068f0956a2c71eb0907b231a843344ffee Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 6 Jun 2024 21:01:36 +0300 Subject: jsondoclint: apply considerable clippy suggestions Signed-off-by: onur-ozkan --- src/tools/jsondoclint/src/validator.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 5e35ce242fe..1713a4d812c 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -418,15 +418,13 @@ impl<'a> Validator<'a> { } else { self.fail_expecting(id, expected); } - } else { - if !self.missing_ids.contains(id) { - self.missing_ids.insert(id); + } else if !self.missing_ids.contains(id) { + self.missing_ids.insert(id); - let sels = json_find::find_selector(&self.krate_json, &Value::String(id.0.clone())); - assert_ne!(sels.len(), 0); + let sels = json_find::find_selector(&self.krate_json, &Value::String(id.0.clone())); + assert_ne!(sels.len(), 0); - self.fail(id, ErrorKind::NotFound(sels)) - } + self.fail(id, ErrorKind::NotFound(sels)) } } -- cgit 1.4.1-3-g733a5 From c755df2d35a813476bc70a96b22c9dc21c0e6175 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 6 Jun 2024 21:01:51 +0300 Subject: remote-test-server: apply considerable clippy suggestions Signed-off-by: onur-ozkan --- src/tools/remote-test-server/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index 68d7aa56c43..79f96c50223 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -282,7 +282,7 @@ fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>, conf cmd.env(library_path, env::join_paths(paths).unwrap()); // Some tests assume RUST_TEST_TMPDIR exists - cmd.env("RUST_TEST_TMPDIR", tmp.to_owned()); + cmd.env("RUST_TEST_TMPDIR", tmp); let socket = Arc::new(Mutex::new(reader.into_inner())); -- cgit 1.4.1-3-g733a5 From 5aa3fbce6177d5a1b68fd3e930c033ef9655b58a Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 6 Jun 2024 21:02:08 +0300 Subject: remote-test-client: apply considerable clippy suggestions Signed-off-by: onur-ozkan --- src/tools/remote-test-client/src/main.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index 590c735596e..dd2c09c430b 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -317,13 +317,11 @@ fn run(support_lib_count: usize, exe: String, all_args: Vec) { t!(io::copy(&mut (&mut client).take(amt), &mut stdout)); t!(stdout.flush()); } + } else if amt == 0 { + stderr_done = true; } else { - if amt == 0 { - stderr_done = true; - } else { - t!(io::copy(&mut (&mut client).take(amt), &mut stderr)); - t!(stderr.flush()); - } + t!(io::copy(&mut (&mut client).take(amt), &mut stderr)); + t!(stderr.flush()); } } -- cgit 1.4.1-3-g733a5 From 80d96dffaef846833c8ea47430448b3015cce191 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 6 Jun 2024 21:02:23 +0300 Subject: lint-docs: apply considerable clippy suggestions Signed-off-by: onur-ozkan --- src/tools/lint-docs/src/groups.rs | 8 ++++---- src/tools/lint-docs/src/lib.rs | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 73f5738469e..f246d71d499 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -121,13 +121,13 @@ impl<'a> LintExtractor<'a> { }; to_link.extend(group_lints); let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect(); - write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", ")) + writeln!(result, "| {} | {} | {} |", group_name, description, brackets.join(", ")) .unwrap(); } result.push('\n'); result.push_str("[warn-by-default]: listing/warn-by-default.md\n"); for lint_name in to_link { - let lint_def = match lints.iter().find(|l| l.name == lint_name.replace("-", "_")) { + let lint_def = match lints.iter().find(|l| l.name == lint_name.replace('-', "_")) { Some(def) => def, None => { let msg = format!( @@ -144,9 +144,9 @@ impl<'a> LintExtractor<'a> { } } }; - write!( + writeln!( result, - "[{}]: listing/{}#{}\n", + "[{}]: listing/{}#{}", lint_name, lint_def.level.doc_filename(), lint_name diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index c79b377727a..72d6a495e7e 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -84,8 +84,8 @@ impl Lint { for &expected in &["### Example", "### Explanation", "{{produces}}"] { if expected == "{{produces}}" && self.is_ignored() { if self.doc_contains("{{produces}}") { - return Err(format!( - "the lint example has `ignore`, but also contains the {{{{produces}}}} marker\n\ + return Err( + "the lint example has `ignore`, but also contains the {{produces}} marker\n\ \n\ The documentation generator cannot generate the example output when the \ example is ignored.\n\ @@ -111,7 +111,7 @@ impl Lint { Replacing the output with the text of the example you \ compiled manually yourself.\n\ " - ).into()); + .into()); } continue; } @@ -519,11 +519,11 @@ impl<'a> LintExtractor<'a> { let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect(); these_lints.sort_unstable_by_key(|lint| &lint.name); for lint in &these_lints { - write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap(); + writeln!(result, "* [`{}`](#{})", lint.name, lint.name.replace('_', "-")).unwrap(); } result.push('\n'); for lint in &these_lints { - write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap(); + write!(result, "## {}\n\n", lint.name.replace('_', "-")).unwrap(); for line in &lint.doc { result.push_str(line); result.push('\n'); @@ -583,7 +583,7 @@ fn add_rename_redirect(level: Level, output: &mut String) { let filename = level.doc_filename().replace(".md", ".html"); output.push_str(RENAME_START); for (from, to) in *names { - write!(output, " \"#{from}\": \"{filename}#{to}\",\n").unwrap(); + writeln!(output, " \"#{from}\": \"{filename}#{to}\",").unwrap(); } output.push_str(RENAME_END); } -- cgit 1.4.1-3-g733a5 From a31b1b2eeb99192272c7f27bea7dc336a54e2546 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 6 Jun 2024 21:02:37 +0300 Subject: opt-dist: apply considerable clippy suggestions Signed-off-by: onur-ozkan --- src/tools/opt-dist/src/training.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs index 89f4d8957c8..1237951b3f0 100644 --- a/src/tools/opt-dist/src/training.rs +++ b/src/tools/opt-dist/src/training.rs @@ -216,11 +216,9 @@ pub fn gather_bolt_profiles( log::info!("Profile file count: {}", profiles.len()); // Delete the gathered profiles - for profile in glob::glob(&format!("{profile_prefix}*"))?.into_iter() { - if let Ok(profile) = profile { - if let Err(error) = std::fs::remove_file(&profile) { - log::error!("Cannot delete BOLT profile {}: {error:?}", profile.display()); - } + for profile in glob::glob(&format!("{profile_prefix}*"))?.flatten() { + if let Err(error) = std::fs::remove_file(&profile) { + log::error!("Cannot delete BOLT profile {}: {error:?}", profile.display()); } } -- cgit 1.4.1-3-g733a5 From d12f1a733846c8994fd9d375accc8477ab796ac5 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 6 Jun 2024 21:02:48 +0300 Subject: tidy: apply considerable clippy suggestions Signed-off-by: onur-ozkan --- src/tools/tidy/src/alphabetical.rs | 2 +- src/tools/tidy/src/bins.rs | 6 ++-- src/tools/tidy/src/deps.rs | 8 ++--- src/tools/tidy/src/error_codes.rs | 8 ++--- src/tools/tidy/src/ext_tool_checks.rs | 9 +++--- src/tools/tidy/src/style.rs | 57 ++++++++++++++++++----------------- src/tools/tidy/src/walk.rs | 18 +++++------ src/tools/tidy/src/x_version.rs | 2 +- 8 files changed, 52 insertions(+), 58 deletions(-) diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs index 150a9594350..a29286fa2c5 100644 --- a/src/tools/tidy/src/alphabetical.rs +++ b/src/tools/tidy/src/alphabetical.rs @@ -88,7 +88,7 @@ fn check_section<'a>( let trimmed_line = line.trim_start_matches(' '); if trimmed_line.starts_with("//") - || (trimmed_line.starts_with("#") && !trimmed_line.starts_with("#!")) + || (trimmed_line.starts_with('#') && !trimmed_line.starts_with("#!")) || trimmed_line.starts_with(is_close_bracket) { continue; diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 64ba79dc185..c82e8b6fee9 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -61,7 +61,7 @@ mod os_impl { fs::remove_file(&path).expect("Deleted temp file"); // If the file is executable, then we assume that this // filesystem does not track executability, so skip this check. - return if exec { Unsupported } else { Supported }; + if exec { Unsupported } else { Supported } } Err(e) => { // If the directory is read-only or we otherwise don't have rights, @@ -76,7 +76,7 @@ mod os_impl { panic!("unable to create temporary file `{:?}`: {:?}", path, e); } - }; + } } for &source_dir in sources { @@ -92,7 +92,7 @@ mod os_impl { } } - return true; + true } // FIXME: check when rust-installer test sh files will be removed, diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 2dd3d17f9e3..7337c9843c7 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -699,11 +699,9 @@ fn check_permitted_dependencies( for dep in deps { let dep = pkg_from_id(metadata, dep); // If this path is in-tree, we don't require it to be explicitly permitted. - if dep.source.is_some() { - if !permitted_dependencies.contains(dep.name.as_str()) { - tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id); - has_permitted_dep_error = true; - } + if dep.source.is_some() && !permitted_dependencies.contains(dep.name.as_str()) { + tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id); + has_permitted_dep_error = true; } } diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index 39f7e70b693..47e2be761e6 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -308,11 +308,9 @@ fn check_error_codes_tests( for line in file.lines() { let s = line.trim(); // Assuming the line starts with `error[E`, we can substring the error code out. - if s.starts_with("error[E") { - if &s[6..11] == code { - found_code = true; - break; - } + if s.starts_with("error[E") && &s[6..11] == code { + found_code = true; + break; }; } diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index b54fa5c6b2c..fb626cac3fa 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -78,9 +78,9 @@ fn check_impl( let mut py_path = None; let (cfg_args, file_args): (Vec<_>, Vec<_>) = pos_args - .into_iter() + .iter() .map(OsStr::new) - .partition(|arg| arg.to_str().is_some_and(|s| s.starts_with("-"))); + .partition(|arg| arg.to_str().is_some_and(|s| s.starts_with('-'))); if python_lint || python_fmt { let venv_path = outdir.join("venv"); @@ -277,10 +277,11 @@ fn create_venv_at_path(path: &Path) -> Result<(), Error> { let stderr = String::from_utf8_lossy(&out.stderr); let err = if stderr.contains("No module named virtualenv") { - Error::Generic(format!( + Error::Generic( "virtualenv not found: you may need to install it \ (`python3 -m pip install venv`)" - )) + .to_owned(), + ) } else { Error::Generic(format!( "failed to create venv at '{}' using {sys_py}: {stderr}", diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 2d3888ec75f..7bcb85335e0 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -463,10 +463,13 @@ pub fn check(path: &Path, bad: &mut bool) { } } // for now we just check libcore - if trimmed.contains("unsafe {") && !trimmed.starts_with("//") && !last_safety_comment { - if file.components().any(|c| c.as_os_str() == "core") && !is_test { - suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe"); - } + if trimmed.contains("unsafe {") + && !trimmed.starts_with("//") + && !last_safety_comment + && file.components().any(|c| c.as_os_str() == "core") + && !is_test + { + suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe"); } if trimmed.contains("// SAFETY:") { last_safety_comment = true; @@ -487,10 +490,10 @@ pub fn check(path: &Path, bad: &mut bool) { "copyright notices attributed to the Rust Project Developers are deprecated" ); } - if !file.components().any(|c| c.as_os_str() == "rustc_baked_icu_data") { - if is_unexplained_ignore(&extension, line) { - err(UNEXPLAINED_IGNORE_DOCTEST_INFO); - } + if !file.components().any(|c| c.as_os_str() == "rustc_baked_icu_data") + && is_unexplained_ignore(&extension, line) + { + err(UNEXPLAINED_IGNORE_DOCTEST_INFO); } if filename.ends_with(".cpp") && line.contains("llvm_unreachable") { @@ -525,26 +528,24 @@ 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() { + 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" + ); } } } diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs index 63a03834166..1cecf998e28 100644 --- a/src/tools/tidy/src/walk.rs +++ b/src/tools/tidy/src/walk.rs @@ -79,13 +79,11 @@ pub(crate) fn walk_no_read( let walker = walker.filter_entry(move |e| { !skip(e.path(), e.file_type().map(|ft| ft.is_dir()).unwrap_or(false)) }); - for entry in walker.build() { - if let Ok(entry) = entry { - if entry.file_type().map_or(true, |kind| kind.is_dir() || kind.is_symlink()) { - continue; - } - f(&entry); + for entry in walker.build().flatten() { + if entry.file_type().map_or(true, |kind| kind.is_dir() || kind.is_symlink()) { + continue; } + f(&entry); } } @@ -97,11 +95,9 @@ pub(crate) fn walk_dir( ) { let mut walker = ignore::WalkBuilder::new(path); let walker = walker.filter_entry(move |e| !skip(e.path())); - for entry in walker.build() { - if let Ok(entry) = entry { - if entry.path().is_dir() { - f(&entry); - } + for entry in walker.build().flatten() { + if entry.path().is_dir() { + f(&entry); } } } diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs index c470d502a65..55bfbed8b0e 100644 --- a/src/tools/tidy/src/x_version.rs +++ b/src/tools/tidy/src/x_version.rs @@ -52,7 +52,7 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { ); } } else { - return tidy_error!(bad, "failed to check version of `x`: {}", cargo_list.status); + tidy_error!(bad, "failed to check version of `x`: {}", cargo_list.status) } } -- cgit 1.4.1-3-g733a5 From c8d2b9397acb4e8f92268df4e1146bdd6da3e67b Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 6 Jun 2024 22:31:47 +0300 Subject: fix bootstrap CI failure Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/format.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 2deb9168df2..b96e26dbb3a 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -93,7 +93,7 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result>, Str return Ok(None); } - get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &vec!["rs"]) + get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"]) } #[derive(serde_derive::Deserialize)] -- cgit 1.4.1-3-g733a5 From 4440f50996e12611e82735b57a0be143b18e9ea3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 3 Mar 2024 15:34:22 +0300 Subject: rustc_span: Add conveniences for working with span formats --- compiler/rustc_span/src/lib.rs | 1 + compiler/rustc_span/src/span_encoding.rs | 248 ++++++++++++++++++------------- 2 files changed, 149 insertions(+), 100 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 99fcaf917fe..7b4506d33ca 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -520,6 +520,7 @@ impl SpanData { pub fn with_hi(&self, hi: BytePos) -> Span { Span::new(self.lo, hi, self.ctxt, self.parent) } + /// Avoid if possible, `Span::update_ctxt` should be preferred. #[inline] fn with_ctxt(&self, ctxt: SyntaxContext) -> Span { Span::new(self.lo, self.hi, ctxt, self.parent) diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 52a1267f891..8227597ac6f 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -4,10 +4,10 @@ use crate::SPAN_TRACK; use crate::{BytePos, SpanData}; use rustc_data_structures::fx::FxIndexSet; - // This code is very hot and uses lots of arithmetic, avoid overflow checks for performance. // See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727 use rustc_serialize::int_overflow::DebugStrictAdd; +use std::mem::transmute; /// A compressed span. /// @@ -87,45 +87,130 @@ pub struct Span { ctxt_or_parent_or_marker: u16, } -impl Span { +// Convenience structures for all span formats. +#[derive(Clone, Copy)] +struct InlineCtxt { + lo: u32, + len: u16, + ctxt: u16, +} + +#[derive(Clone, Copy)] +struct InlineParent { + lo: u32, + len_with_tag: u16, + parent: u16, +} + +#[derive(Clone, Copy)] +struct PartiallyInterned { + index: u32, + _marker1: u16, + ctxt: u16, +} + +#[derive(Clone, Copy)] +struct Interned { + index: u32, + _marker1: u16, + _marker2: u16, +} + +impl InlineCtxt { #[inline] - fn data_inline_ctxt(self) -> SpanData { - let len = self.len_with_tag_or_marker as u32; + fn data(self) -> SpanData { + let len = self.len as u32; debug_assert!(len <= MAX_LEN); SpanData { - lo: BytePos(self.lo_or_index), - hi: BytePos(self.lo_or_index.debug_strict_add(len)), - ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32), + lo: BytePos(self.lo), + hi: BytePos(self.lo.debug_strict_add(len)), + ctxt: SyntaxContext::from_u32(self.ctxt as u32), parent: None, } } #[inline] - fn data_inline_parent(self) -> SpanData { - let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32; + fn span(lo: u32, len: u16, ctxt: u16) -> Span { + unsafe { transmute(InlineCtxt { lo, len, ctxt }) } + } +} + +impl InlineParent { + #[inline] + fn data(self) -> SpanData { + let len = (self.len_with_tag & !PARENT_TAG) as u32; debug_assert!(len <= MAX_LEN); - let parent = LocalDefId { - local_def_index: DefIndex::from_u32(self.ctxt_or_parent_or_marker as u32), - }; SpanData { - lo: BytePos(self.lo_or_index), - hi: BytePos(self.lo_or_index.debug_strict_add(len)), + lo: BytePos(self.lo), + hi: BytePos(self.lo.debug_strict_add(len)), ctxt: SyntaxContext::root(), - parent: Some(parent), + parent: Some(LocalDefId { local_def_index: DefIndex::from_u32(self.parent as u32) }), } } #[inline] - fn data_partially_interned(self) -> SpanData { + fn span(lo: u32, len_with_tag: u16, parent: u16) -> Span { + unsafe { transmute(InlineParent { lo, len_with_tag, parent }) } + } +} + +impl PartiallyInterned { + #[inline] + fn data(self) -> SpanData { SpanData { - ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32), - ..with_span_interner(|interner| interner.spans[self.lo_or_index as usize]) + ctxt: SyntaxContext::from_u32(self.ctxt as u32), + ..with_span_interner(|interner| interner.spans[self.index as usize]) } } #[inline] - fn data_interned(self) -> SpanData { - with_span_interner(|interner| interner.spans[self.lo_or_index as usize]) + fn span(index: u32, ctxt: u16) -> Span { + unsafe { transmute(PartiallyInterned { index, _marker1: BASE_LEN_INTERNED_MARKER, ctxt }) } } } +impl Interned { + #[inline] + fn data(self) -> SpanData { + with_span_interner(|interner| interner.spans[self.index as usize]) + } + #[inline] + fn span(index: u32) -> Span { + let _marker1 = BASE_LEN_INTERNED_MARKER; + unsafe { transmute(Interned { index, _marker1, _marker2: CTXT_INTERNED_MARKER }) } + } +} + +// This code is very hot, and converting span to an enum and matching on it doesn't optimize away +// properly. So we are using a macro emulating such a match, but expand it directly to an if-else +// chain. +macro_rules! match_span_kind { + ( + $span:expr, + InlineCtxt($span1:ident) => $arm1:expr, + InlineParent($span2:ident) => $arm2:expr, + PartiallyInterned($span3:ident) => $arm3:expr, + Interned($span4:ident) => $arm4:expr, + ) => { + if $span.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { + if $span.len_with_tag_or_marker & PARENT_TAG == 0 { + // Inline-context format. + let $span1: &mut InlineCtxt = unsafe { transmute(&mut *$span) }; + $arm1 + } else { + // Inline-parent format. + let $span2: &mut InlineParent = unsafe { transmute(&mut *$span) }; + $arm2 + } + } else if $span.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { + // Partially-interned format. + let $span3: &mut PartiallyInterned = unsafe { transmute(&mut *$span) }; + $arm3 + } else { + // Interned format. + let $span4: &mut Interned = unsafe { transmute(&mut *$span) }; + $arm4 + } + }; +} + // `MAX_LEN` is chosen so that `PARENT_TAG | MAX_LEN` is distinct from // `BASE_LEN_INTERNED_MARKER`. (If `MAX_LEN` was 1 higher, this wouldn't be true.) const MAX_LEN: u32 = 0b0111_1111_1111_1110; @@ -154,23 +239,13 @@ impl Span { let (len, ctxt32) = (hi.0 - lo.0, ctxt.as_u32()); if len <= MAX_LEN { if ctxt32 <= MAX_CTXT && parent.is_none() { - // Inline-context format. - return Span { - lo_or_index: lo.0, - len_with_tag_or_marker: len as u16, - ctxt_or_parent_or_marker: ctxt32 as u16, - }; + return InlineCtxt::span(lo.0, len as u16, ctxt32 as u16); } else if ctxt32 == 0 && let Some(parent) = parent && let parent32 = parent.local_def_index.as_u32() && parent32 <= MAX_CTXT { - // Inline-parent format. - return Span { - lo_or_index: lo.0, - len_with_tag_or_marker: PARENT_TAG | len as u16, - ctxt_or_parent_or_marker: parent32 as u16, - }; + return InlineParent::span(lo.0, PARENT_TAG | len as u16, parent32 as u16); } } @@ -179,20 +254,10 @@ impl Span { with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent })) }; if ctxt32 <= MAX_CTXT { - // Partially-interned format. - Span { - // Interned ctxt should never be read, so it can use any value. - lo_or_index: index(SyntaxContext::from_u32(u32::MAX)), - len_with_tag_or_marker: BASE_LEN_INTERNED_MARKER, - ctxt_or_parent_or_marker: ctxt32 as u16, - } + // Interned ctxt should never be read, so it can use any value. + PartiallyInterned::span(index(SyntaxContext::from_u32(u32::MAX)), ctxt32 as u16) } else { - // Interned format. - Span { - lo_or_index: index(ctxt), - len_with_tag_or_marker: BASE_LEN_INTERNED_MARKER, - ctxt_or_parent_or_marker: CTXT_INTERNED_MARKER, - } + Interned::span(index(ctxt)) } } @@ -208,21 +273,13 @@ impl Span { /// Internal function to translate between an encoded span and the expanded representation. /// This function must not be used outside the incremental engine. #[inline] - pub fn data_untracked(self) -> SpanData { - if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { - if self.len_with_tag_or_marker & PARENT_TAG == 0 { - // Inline-context format. - self.data_inline_ctxt() - } else { - // Inline-parent format. - self.data_inline_parent() - } - } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { - // Partially-interned format. - self.data_partially_interned() - } else { - // Interned format. - self.data_interned() + pub fn data_untracked(mut self) -> SpanData { + match_span_kind! { + &mut self, + InlineCtxt(span) => span.data(), + InlineParent(span) => span.data(), + PartiallyInterned(span) => span.data(), + Interned(span) => span.data(), } } @@ -249,42 +306,41 @@ impl Span { #[inline] pub fn update_ctxt(&mut self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) { let (updated_ctxt32, data); - if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { - if self.len_with_tag_or_marker & PARENT_TAG == 0 { - // Inline-context format. + match_span_kind! { + self, + InlineCtxt(span) => { updated_ctxt32 = - update(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)).as_u32(); + update(SyntaxContext::from_u32(span.ctxt as u32)).as_u32(); // Any small new context including zero will preserve the format. if updated_ctxt32 <= MAX_CTXT { - self.ctxt_or_parent_or_marker = updated_ctxt32 as u16; + span.ctxt = updated_ctxt32 as u16; return; } - data = self.data_inline_ctxt(); - } else { - // Inline-parent format. + data = span.data(); + }, + InlineParent(span) => { updated_ctxt32 = update(SyntaxContext::root()).as_u32(); // Only if the new context is zero the format will be preserved. if updated_ctxt32 == 0 { // Do nothing. return; } - data = self.data_inline_parent(); - } - } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { - // Partially-interned format. - updated_ctxt32 = - update(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)).as_u32(); - // Any small new context excluding zero will preserve the format. - // Zero may change the format to `InlineParent` if parent and len are small enough. - if updated_ctxt32 <= MAX_CTXT && updated_ctxt32 != 0 { - self.ctxt_or_parent_or_marker = updated_ctxt32 as u16; - return; - } - data = self.data_partially_interned(); - } else { - // Interned format. - data = self.data_interned(); - updated_ctxt32 = update(data.ctxt).as_u32(); + data = span.data(); + }, + PartiallyInterned(span) => { + updated_ctxt32 = update(SyntaxContext::from_u32(span.ctxt as u32)).as_u32(); + // Any small new context excluding zero will preserve the format. + // Zero may change the format to `InlineParent` if parent and len are small enough. + if updated_ctxt32 <= MAX_CTXT && updated_ctxt32 != 0 { + span.ctxt = updated_ctxt32 as u16; + return; + } + data = span.data(); + }, + Interned(span) => { + data = span.data(); + updated_ctxt32 = update(data.ctxt).as_u32(); + }, } // We could not keep the span in the same inline format, fall back to the complete logic. @@ -294,21 +350,13 @@ impl Span { // Returns either syntactic context, if it can be retrieved without taking the interner lock, // or an index into the interner if it cannot. #[inline] - fn inline_ctxt(self) -> Result { - if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { - if self.len_with_tag_or_marker & PARENT_TAG == 0 { - // Inline-context format. - Ok(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)) - } else { - // Inline-parent format. - Ok(SyntaxContext::root()) - } - } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { - // Partially-interned format. - Ok(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)) - } else { - // Interned format. - Err(self.lo_or_index as usize) + fn inline_ctxt(mut self) -> Result { + match_span_kind! { + &mut self, + InlineCtxt(span) => Ok(SyntaxContext::from_u32(span.ctxt as u32)), + InlineParent(_span) => Ok(SyntaxContext::root()), + PartiallyInterned(span) => Ok(SyntaxContext::from_u32(span.ctxt as u32)), + Interned(span) => Err(span.index as usize), } } -- cgit 1.4.1-3-g733a5 From 6fea953267298e98ee630e595efcfe1c3a287976 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 12 Jun 2024 01:58:29 +0300 Subject: rustc_span: By-value interface for ctxt update --- compiler/rustc_expand/src/mbe/transcribe.rs | 2 +- compiler/rustc_span/src/lib.rs | 22 +++++++++------------- compiler/rustc_span/src/span_encoding.rs | 28 +++++++++++++--------------- 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 25e961d6009..5aa9242fa16 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -30,7 +30,7 @@ impl MutVisitor for Marker { // it's some advanced case with macro-generated macros. So if we cache the marked version // of that context once, we'll typically have a 100% cache hit rate after that. let Marker(expn_id, transparency, ref mut cache) = *self; - span.update_ctxt(|ctxt| { + *span = span.map_ctxt(|ctxt| { *cache .entry(ctxt) .or_insert_with(|| ctxt.apply_mark(expn_id.to_expn_id(), transparency)) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 7b4506d33ca..b7ffe6c618a 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -520,7 +520,7 @@ impl SpanData { pub fn with_hi(&self, hi: BytePos) -> Span { Span::new(self.lo, hi, self.ctxt, self.parent) } - /// Avoid if possible, `Span::update_ctxt` should be preferred. + /// Avoid if possible, `Span::map_ctxt` should be preferred. #[inline] fn with_ctxt(&self, ctxt: SyntaxContext) -> Span { Span::new(self.lo, self.hi, ctxt, self.parent) @@ -577,9 +577,8 @@ impl Span { self.data().with_hi(hi) } #[inline] - pub fn with_ctxt(mut self, ctxt: SyntaxContext) -> Span { - self.update_ctxt(|_| ctxt); - self + pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span { + self.map_ctxt(|_| ctxt) } #[inline] pub fn parent(self) -> Option { @@ -1060,9 +1059,8 @@ impl Span { } #[inline] - pub fn apply_mark(mut self, expn_id: ExpnId, transparency: Transparency) -> Span { - self.update_ctxt(|ctxt| ctxt.apply_mark(expn_id, transparency)); - self + pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span { + self.map_ctxt(|ctxt| ctxt.apply_mark(expn_id, transparency)) } #[inline] @@ -1110,15 +1108,13 @@ impl Span { } #[inline] - pub fn normalize_to_macros_2_0(mut self) -> Span { - self.update_ctxt(|ctxt| ctxt.normalize_to_macros_2_0()); - self + pub fn normalize_to_macros_2_0(self) -> Span { + self.map_ctxt(|ctxt| ctxt.normalize_to_macros_2_0()) } #[inline] - pub fn normalize_to_macro_rules(mut self) -> Span { - self.update_ctxt(|ctxt| ctxt.normalize_to_macro_rules()); - self + pub fn normalize_to_macro_rules(self) -> Span { + self.map_ctxt(|ctxt| ctxt.normalize_to_macro_rules()) } } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 8227597ac6f..69d7b4ca8c2 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -192,20 +192,20 @@ macro_rules! match_span_kind { if $span.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { if $span.len_with_tag_or_marker & PARENT_TAG == 0 { // Inline-context format. - let $span1: &mut InlineCtxt = unsafe { transmute(&mut *$span) }; + let $span1: InlineCtxt = unsafe { transmute($span) }; $arm1 } else { // Inline-parent format. - let $span2: &mut InlineParent = unsafe { transmute(&mut *$span) }; + let $span2: InlineParent = unsafe { transmute($span) }; $arm2 } } else if $span.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { // Partially-interned format. - let $span3: &mut PartiallyInterned = unsafe { transmute(&mut *$span) }; + let $span3: PartiallyInterned = unsafe { transmute($span) }; $arm3 } else { // Interned format. - let $span4: &mut Interned = unsafe { transmute(&mut *$span) }; + let $span4: Interned = unsafe { transmute($span) }; $arm4 } }; @@ -273,9 +273,9 @@ impl Span { /// Internal function to translate between an encoded span and the expanded representation. /// This function must not be used outside the incremental engine. #[inline] - pub fn data_untracked(mut self) -> SpanData { + pub fn data_untracked(self) -> SpanData { match_span_kind! { - &mut self, + self, InlineCtxt(span) => span.data(), InlineParent(span) => span.data(), PartiallyInterned(span) => span.data(), @@ -304,7 +304,7 @@ impl Span { // update doesn't change format. All non-inline or format changing scenarios require accessing // interner and can fall back to `Span::new`. #[inline] - pub fn update_ctxt(&mut self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) { + pub fn map_ctxt(self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) -> Span { let (updated_ctxt32, data); match_span_kind! { self, @@ -313,8 +313,7 @@ impl Span { update(SyntaxContext::from_u32(span.ctxt as u32)).as_u32(); // Any small new context including zero will preserve the format. if updated_ctxt32 <= MAX_CTXT { - span.ctxt = updated_ctxt32 as u16; - return; + return InlineCtxt::span(span.lo, span.len, updated_ctxt32 as u16); } data = span.data(); }, @@ -323,7 +322,7 @@ impl Span { // Only if the new context is zero the format will be preserved. if updated_ctxt32 == 0 { // Do nothing. - return; + return self; } data = span.data(); }, @@ -332,8 +331,7 @@ impl Span { // Any small new context excluding zero will preserve the format. // Zero may change the format to `InlineParent` if parent and len are small enough. if updated_ctxt32 <= MAX_CTXT && updated_ctxt32 != 0 { - span.ctxt = updated_ctxt32 as u16; - return; + return PartiallyInterned::span(span.index, updated_ctxt32 as u16); } data = span.data(); }, @@ -344,15 +342,15 @@ impl Span { } // We could not keep the span in the same inline format, fall back to the complete logic. - *self = data.with_ctxt(SyntaxContext::from_u32(updated_ctxt32)); + data.with_ctxt(SyntaxContext::from_u32(updated_ctxt32)) } // Returns either syntactic context, if it can be retrieved without taking the interner lock, // or an index into the interner if it cannot. #[inline] - fn inline_ctxt(mut self) -> Result { + fn inline_ctxt(self) -> Result { match_span_kind! { - &mut self, + self, InlineCtxt(span) => Ok(SyntaxContext::from_u32(span.ctxt as u32)), InlineParent(_span) => Ok(SyntaxContext::root()), PartiallyInterned(span) => Ok(SyntaxContext::from_u32(span.ctxt as u32)), -- cgit 1.4.1-3-g733a5 From 57106e4a46648421de7b20c50483b21b58f48809 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 10 Apr 2024 16:44:10 -0700 Subject: Rename proc_macro::Literal tests from parse.rs to literal.rs This module contains tests not just of parse (FromStr) but also to_string (Display) for literals. --- tests/ui/proc-macro/auxiliary/api/literal.rs | 58 ++++++++++++++++++++++++++++ tests/ui/proc-macro/auxiliary/api/mod.rs | 4 +- tests/ui/proc-macro/auxiliary/api/parse.rs | 58 ---------------------------- 3 files changed, 60 insertions(+), 60 deletions(-) create mode 100644 tests/ui/proc-macro/auxiliary/api/literal.rs delete mode 100644 tests/ui/proc-macro/auxiliary/api/parse.rs diff --git a/tests/ui/proc-macro/auxiliary/api/literal.rs b/tests/ui/proc-macro/auxiliary/api/literal.rs new file mode 100644 index 00000000000..801c616c804 --- /dev/null +++ b/tests/ui/proc-macro/auxiliary/api/literal.rs @@ -0,0 +1,58 @@ +// ignore-tidy-linelength + +use proc_macro::Literal; + +pub fn test() { + test_display_literal(); + test_parse_literal(); +} + +fn test_display_literal() { + assert_eq!(Literal::isize_unsuffixed(-10).to_string(), "-10"); + assert_eq!(Literal::isize_suffixed(-10).to_string(), "-10isize"); + assert_eq!(Literal::f32_unsuffixed(-10.0).to_string(), "-10.0"); + assert_eq!(Literal::f32_suffixed(-10.0).to_string(), "-10f32"); + assert_eq!(Literal::f64_unsuffixed(-10.0).to_string(), "-10.0"); + assert_eq!(Literal::f64_suffixed(-10.0).to_string(), "-10f64"); + assert_eq!( + Literal::f64_unsuffixed(1e100).to_string(), + "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0", + ); + + assert_eq!(Literal::string("a \t ❤ ' \" \u{1}").to_string(), "\"a \\t ❤ ' \\\" \\u{1}\"",); + assert_eq!(Literal::c_string(c"\'\"\x7f\u{7fff}").to_string(), r#"c"\'\"\x7f\xe7\xbf\xbf""#); + assert_eq!(Literal::character('a').to_string(), "'a'"); + assert_eq!(Literal::character('\t').to_string(), "'\\t'"); + assert_eq!(Literal::character('❤').to_string(), "'❤'"); + assert_eq!(Literal::character('\'').to_string(), "'\\''"); + assert_eq!(Literal::character('"').to_string(), "'\"'"); + assert_eq!(Literal::character('\u{1}').to_string(), "'\\u{1}'"); + + assert_eq!(Literal::byte_character(b'a').to_string(), "b'a'"); + assert_eq!(Literal::byte_character(0).to_string(), "b'\\x00'"); +} + +fn test_parse_literal() { + assert_eq!("1".parse::().unwrap().to_string(), "1"); + assert_eq!("1.0".parse::().unwrap().to_string(), "1.0"); + assert_eq!("'a'".parse::().unwrap().to_string(), "'a'"); + assert_eq!("b'a'".parse::().unwrap().to_string(), "b'a'"); + assert_eq!("\"\n\"".parse::().unwrap().to_string(), "\"\n\""); + assert_eq!("b\"\"".parse::().unwrap().to_string(), "b\"\""); + assert_eq!("c\"\"".parse::().unwrap().to_string(), "c\"\""); + assert_eq!("r##\"\"##".parse::().unwrap().to_string(), "r##\"\"##"); + assert_eq!("10ulong".parse::().unwrap().to_string(), "10ulong"); + assert_eq!("-10ulong".parse::().unwrap().to_string(), "-10ulong"); + + assert!("true".parse::().is_err()); + assert!(".8".parse::().is_err()); + assert!("0 1".parse::().is_err()); + assert!("'a".parse::().is_err()); + assert!(" 0".parse::().is_err()); + assert!("0 ".parse::().is_err()); + assert!("/* comment */0".parse::().is_err()); + assert!("0/* comment */".parse::().is_err()); + assert!("0// comment".parse::().is_err()); + assert!("- 10".parse::().is_err()); + assert!("-'x'".parse::().is_err()); +} diff --git a/tests/ui/proc-macro/auxiliary/api/mod.rs b/tests/ui/proc-macro/auxiliary/api/mod.rs index 45ef6922d28..e0a381cb6c1 100644 --- a/tests/ui/proc-macro/auxiliary/api/mod.rs +++ b/tests/ui/proc-macro/auxiliary/api/mod.rs @@ -10,7 +10,7 @@ extern crate proc_macro; mod cmp; -mod parse; +mod literal; use proc_macro::TokenStream; @@ -19,7 +19,7 @@ pub fn run(input: TokenStream) -> TokenStream { assert!(input.is_empty()); cmp::test(); - parse::test(); + literal::test(); TokenStream::new() } diff --git a/tests/ui/proc-macro/auxiliary/api/parse.rs b/tests/ui/proc-macro/auxiliary/api/parse.rs deleted file mode 100644 index 801c616c804..00000000000 --- a/tests/ui/proc-macro/auxiliary/api/parse.rs +++ /dev/null @@ -1,58 +0,0 @@ -// ignore-tidy-linelength - -use proc_macro::Literal; - -pub fn test() { - test_display_literal(); - test_parse_literal(); -} - -fn test_display_literal() { - assert_eq!(Literal::isize_unsuffixed(-10).to_string(), "-10"); - assert_eq!(Literal::isize_suffixed(-10).to_string(), "-10isize"); - assert_eq!(Literal::f32_unsuffixed(-10.0).to_string(), "-10.0"); - assert_eq!(Literal::f32_suffixed(-10.0).to_string(), "-10f32"); - assert_eq!(Literal::f64_unsuffixed(-10.0).to_string(), "-10.0"); - assert_eq!(Literal::f64_suffixed(-10.0).to_string(), "-10f64"); - assert_eq!( - Literal::f64_unsuffixed(1e100).to_string(), - "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0", - ); - - assert_eq!(Literal::string("a \t ❤ ' \" \u{1}").to_string(), "\"a \\t ❤ ' \\\" \\u{1}\"",); - assert_eq!(Literal::c_string(c"\'\"\x7f\u{7fff}").to_string(), r#"c"\'\"\x7f\xe7\xbf\xbf""#); - assert_eq!(Literal::character('a').to_string(), "'a'"); - assert_eq!(Literal::character('\t').to_string(), "'\\t'"); - assert_eq!(Literal::character('❤').to_string(), "'❤'"); - assert_eq!(Literal::character('\'').to_string(), "'\\''"); - assert_eq!(Literal::character('"').to_string(), "'\"'"); - assert_eq!(Literal::character('\u{1}').to_string(), "'\\u{1}'"); - - assert_eq!(Literal::byte_character(b'a').to_string(), "b'a'"); - assert_eq!(Literal::byte_character(0).to_string(), "b'\\x00'"); -} - -fn test_parse_literal() { - assert_eq!("1".parse::().unwrap().to_string(), "1"); - assert_eq!("1.0".parse::().unwrap().to_string(), "1.0"); - assert_eq!("'a'".parse::().unwrap().to_string(), "'a'"); - assert_eq!("b'a'".parse::().unwrap().to_string(), "b'a'"); - assert_eq!("\"\n\"".parse::().unwrap().to_string(), "\"\n\""); - assert_eq!("b\"\"".parse::().unwrap().to_string(), "b\"\""); - assert_eq!("c\"\"".parse::().unwrap().to_string(), "c\"\""); - assert_eq!("r##\"\"##".parse::().unwrap().to_string(), "r##\"\"##"); - assert_eq!("10ulong".parse::().unwrap().to_string(), "10ulong"); - assert_eq!("-10ulong".parse::().unwrap().to_string(), "-10ulong"); - - assert!("true".parse::().is_err()); - assert!(".8".parse::().is_err()); - assert!("0 1".parse::().is_err()); - assert!("'a".parse::().is_err()); - assert!(" 0".parse::().is_err()); - assert!("0 ".parse::().is_err()); - assert!("/* comment */0".parse::().is_err()); - assert!("0/* comment */".parse::().is_err()); - assert!("0// comment".parse::().is_err()); - assert!("- 10".parse::().is_err()); - assert!("-'x'".parse::().is_err()); -} -- cgit 1.4.1-3-g733a5 From 2cc02849059a7efb7fd5f7a726a31a38ee732c1e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 10 Apr 2024 17:52:30 -0700 Subject: Add more Literal::to_string tests --- tests/ui/proc-macro/auxiliary/api/literal.rs | 47 +++++++++++++++++++++------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/tests/ui/proc-macro/auxiliary/api/literal.rs b/tests/ui/proc-macro/auxiliary/api/literal.rs index 801c616c804..a3519f5791a 100644 --- a/tests/ui/proc-macro/auxiliary/api/literal.rs +++ b/tests/ui/proc-macro/auxiliary/api/literal.rs @@ -19,17 +19,42 @@ fn test_display_literal() { "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0", ); - assert_eq!(Literal::string("a \t ❤ ' \" \u{1}").to_string(), "\"a \\t ❤ ' \\\" \\u{1}\"",); - assert_eq!(Literal::c_string(c"\'\"\x7f\u{7fff}").to_string(), r#"c"\'\"\x7f\xe7\xbf\xbf""#); - assert_eq!(Literal::character('a').to_string(), "'a'"); - assert_eq!(Literal::character('\t').to_string(), "'\\t'"); - assert_eq!(Literal::character('❤').to_string(), "'❤'"); - assert_eq!(Literal::character('\'').to_string(), "'\\''"); - assert_eq!(Literal::character('"').to_string(), "'\"'"); - assert_eq!(Literal::character('\u{1}').to_string(), "'\\u{1}'"); - - assert_eq!(Literal::byte_character(b'a').to_string(), "b'a'"); - assert_eq!(Literal::byte_character(0).to_string(), "b'\\x00'"); + assert_eq!(Literal::string("aA").to_string(), r#" "aA" "#.trim()); + assert_eq!(Literal::string("\t").to_string(), r#" "\t" "#.trim()); + assert_eq!(Literal::string("❤").to_string(), r#" "❤" "#.trim()); + assert_eq!(Literal::string("'").to_string(), r#" "'" "#.trim()); + assert_eq!(Literal::string("\"").to_string(), r#" "\"" "#.trim()); + assert_eq!(Literal::string("\0").to_string(), r#" "\0" "#.trim()); + assert_eq!(Literal::string("\u{1}").to_string(), r#" "\u{1}" "#.trim()); + + assert_eq!(Literal::byte_string(b"aA").to_string(), r#" b"aA" "#.trim()); + assert_eq!(Literal::byte_string(b"\t").to_string(), r#" b"\t" "#.trim()); + assert_eq!(Literal::byte_string(b"'").to_string(), r#" b"\'" "#.trim()); + assert_eq!(Literal::byte_string(b"\"").to_string(), r#" b"\"" "#.trim()); + assert_eq!(Literal::byte_string(b"\0").to_string(), r#" b"\x00" "#.trim()); + assert_eq!(Literal::byte_string(b"\x01").to_string(), r#" b"\x01" "#.trim()); + + assert_eq!(Literal::c_string(c"aA").to_string(), r#" c"aA" "#.trim()); + assert_eq!(Literal::c_string(c"\t").to_string(), r#" c"\t" "#.trim()); + assert_eq!(Literal::c_string(c"❤").to_string(), r#" c"\xe2\x9d\xa4" "#.trim()); + assert_eq!(Literal::c_string(c"\'").to_string(), r#" c"\'" "#.trim()); + assert_eq!(Literal::c_string(c"\"").to_string(), r#" c"\"" "#.trim()); + assert_eq!(Literal::c_string(c"\x7f\xff\xfe\u{333}").to_string(), r#" c"\x7f\xff\xfe\xcc\xb3" "#.trim()); + + assert_eq!(Literal::character('a').to_string(), r#" 'a' "#.trim()); + assert_eq!(Literal::character('\t').to_string(), r#" '\t' "#.trim()); + assert_eq!(Literal::character('❤').to_string(), r#" '❤' "#.trim()); + assert_eq!(Literal::character('\'').to_string(), r#" '\'' "#.trim()); + assert_eq!(Literal::character('"').to_string(), r#" '"' "#.trim()); + assert_eq!(Literal::character('\0').to_string(), r#" '\0' "#.trim()); + assert_eq!(Literal::character('\u{1}').to_string(), r#" '\u{1}' "#.trim()); + + assert_eq!(Literal::byte_character(b'a').to_string(), r#" b'a' "#.trim()); + assert_eq!(Literal::byte_character(b'\t').to_string(), r#" b'\t' "#.trim()); + assert_eq!(Literal::byte_character(b'\'').to_string(), r#" b'\'' "#.trim()); + assert_eq!(Literal::byte_character(b'"').to_string(), r#" b'\"' "#.trim()); + assert_eq!(Literal::byte_character(0).to_string(), r#" b'\x00' "#.trim()); + assert_eq!(Literal::byte_character(1).to_string(), r#" b'\x01' "#.trim()); } fn test_parse_literal() { -- cgit 1.4.1-3-g733a5 From 7ddc89e893ebb6c60af4fe92c439c4a60c9118dd Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 10 Apr 2024 20:55:59 -0700 Subject: Remove superfluous escaping from byte, byte str, and c str literals --- library/proc_macro/src/escape.rs | 57 ++++++++++++++++++++++++++++ library/proc_macro/src/lib.rs | 51 ++++++++++++++++++------- tests/ui/proc-macro/auxiliary/api/literal.rs | 14 +++---- 3 files changed, 101 insertions(+), 21 deletions(-) create mode 100644 library/proc_macro/src/escape.rs diff --git a/library/proc_macro/src/escape.rs b/library/proc_macro/src/escape.rs new file mode 100644 index 00000000000..87a4d1d50fd --- /dev/null +++ b/library/proc_macro/src/escape.rs @@ -0,0 +1,57 @@ +#[derive(Copy, Clone)] +pub(crate) struct EscapeOptions { + /// Produce \'. + pub escape_single_quote: bool, + /// Produce \". + pub escape_double_quote: bool, + /// Produce \x escapes for non-ASCII, and use \x rather than \u for ASCII + /// control characters. + pub escape_nonascii: bool, +} + +pub(crate) fn escape_bytes(bytes: &[u8], opt: EscapeOptions) -> String { + let mut repr = String::new(); + + if opt.escape_nonascii { + for &byte in bytes { + escape_single_byte(byte, opt, &mut repr); + } + } else { + let mut chunks = bytes.utf8_chunks(); + while let Some(chunk) = chunks.next() { + for ch in chunk.valid().chars() { + escape_single_char(ch, opt, &mut repr); + } + for &byte in chunk.invalid() { + escape_single_byte(byte, opt, &mut repr); + } + } + } + + repr +} + +fn escape_single_byte(byte: u8, opt: EscapeOptions, repr: &mut String) { + if byte == b'\0' { + repr.push_str("\\0"); + } else if (byte == b'\'' && !opt.escape_single_quote) + || (byte == b'"' && !opt.escape_double_quote) + { + repr.push(byte as char); + } else { + // Escapes \t, \r, \n, \\, \', \", and uses \x## for non-ASCII and + // for ASCII control characters. + repr.extend(byte.escape_ascii().map(char::from)); + } +} + +fn escape_single_char(ch: char, opt: EscapeOptions, repr: &mut String) { + if (ch == '\'' && !opt.escape_single_quote) || (ch == '"' && !opt.escape_double_quote) { + repr.push(ch); + } else { + // Escapes \0, \t, \r, \n, \\, \', \", and uses \u{...} for + // non-printable characters and for Grapheme_Extend characters, which + // includes things like U+0300 "Combining Grave Accent". + repr.extend(ch.escape_debug()); + } +} diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 3d7d36b27e5..581d7e3efe3 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -43,10 +43,12 @@ pub mod bridge; mod diagnostic; +mod escape; #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub use diagnostic::{Diagnostic, Level, MultiSpan}; +use crate::escape::{escape_bytes, EscapeOptions}; use std::ffi::CStr; use std::ops::{Range, RangeBounds}; use std::path::PathBuf; @@ -1356,40 +1358,61 @@ impl Literal { /// String literal. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn string(string: &str) -> Literal { - let quoted = format!("{:?}", string); - assert!(quoted.starts_with('"') && quoted.ends_with('"')); - let symbol = "ed[1..quoted.len() - 1]; - Literal::new(bridge::LitKind::Str, symbol, None) + let escape = EscapeOptions { + escape_single_quote: false, + escape_double_quote: true, + escape_nonascii: false, + }; + let repr = escape_bytes(string.as_bytes(), escape); + Literal::new(bridge::LitKind::Str, &repr, None) } /// Character literal. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn character(ch: char) -> Literal { - let quoted = format!("{:?}", ch); - assert!(quoted.starts_with('\'') && quoted.ends_with('\'')); - let symbol = "ed[1..quoted.len() - 1]; - Literal::new(bridge::LitKind::Char, symbol, None) + let escape = EscapeOptions { + escape_single_quote: true, + escape_double_quote: false, + escape_nonascii: false, + }; + let repr = escape_bytes(ch.encode_utf8(&mut [0u8; 4]).as_bytes(), escape); + Literal::new(bridge::LitKind::Char, &repr, None) } /// Byte character literal. #[stable(feature = "proc_macro_byte_character", since = "1.79.0")] pub fn byte_character(byte: u8) -> Literal { - let string = [byte].escape_ascii().to_string(); - Literal::new(bridge::LitKind::Byte, &string, None) + let escape = EscapeOptions { + escape_single_quote: true, + escape_double_quote: false, + escape_nonascii: true, + }; + let repr = escape_bytes(&[byte], escape); + Literal::new(bridge::LitKind::Byte, &repr, None) } /// Byte string literal. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn byte_string(bytes: &[u8]) -> Literal { - let string = bytes.escape_ascii().to_string(); - Literal::new(bridge::LitKind::ByteStr, &string, None) + let escape = EscapeOptions { + escape_single_quote: false, + escape_double_quote: true, + escape_nonascii: true, + }; + let repr = escape_bytes(bytes, escape); + Literal::new(bridge::LitKind::ByteStr, &repr, None) } /// C string literal. #[stable(feature = "proc_macro_c_str_literals", since = "1.79.0")] pub fn c_string(string: &CStr) -> Literal { - let string = string.to_bytes().escape_ascii().to_string(); - Literal::new(bridge::LitKind::CStr, &string, None) + let escape = EscapeOptions { + escape_single_quote: false, + escape_double_quote: true, + escape_nonascii: false, + }; + let repr = escape_bytes(string.to_bytes(), escape); + Literal::new(bridge::LitKind::CStr, &repr, None) } /// Returns the span encompassing this literal. diff --git a/tests/ui/proc-macro/auxiliary/api/literal.rs b/tests/ui/proc-macro/auxiliary/api/literal.rs index a3519f5791a..7109340bb64 100644 --- a/tests/ui/proc-macro/auxiliary/api/literal.rs +++ b/tests/ui/proc-macro/auxiliary/api/literal.rs @@ -29,17 +29,17 @@ fn test_display_literal() { assert_eq!(Literal::byte_string(b"aA").to_string(), r#" b"aA" "#.trim()); assert_eq!(Literal::byte_string(b"\t").to_string(), r#" b"\t" "#.trim()); - assert_eq!(Literal::byte_string(b"'").to_string(), r#" b"\'" "#.trim()); + assert_eq!(Literal::byte_string(b"'").to_string(), r#" b"'" "#.trim()); assert_eq!(Literal::byte_string(b"\"").to_string(), r#" b"\"" "#.trim()); - assert_eq!(Literal::byte_string(b"\0").to_string(), r#" b"\x00" "#.trim()); + assert_eq!(Literal::byte_string(b"\0").to_string(), r#" b"\0" "#.trim()); assert_eq!(Literal::byte_string(b"\x01").to_string(), r#" b"\x01" "#.trim()); assert_eq!(Literal::c_string(c"aA").to_string(), r#" c"aA" "#.trim()); assert_eq!(Literal::c_string(c"\t").to_string(), r#" c"\t" "#.trim()); - assert_eq!(Literal::c_string(c"❤").to_string(), r#" c"\xe2\x9d\xa4" "#.trim()); - assert_eq!(Literal::c_string(c"\'").to_string(), r#" c"\'" "#.trim()); + assert_eq!(Literal::c_string(c"❤").to_string(), r#" c"❤" "#.trim()); + assert_eq!(Literal::c_string(c"\'").to_string(), r#" c"'" "#.trim()); assert_eq!(Literal::c_string(c"\"").to_string(), r#" c"\"" "#.trim()); - assert_eq!(Literal::c_string(c"\x7f\xff\xfe\u{333}").to_string(), r#" c"\x7f\xff\xfe\xcc\xb3" "#.trim()); + assert_eq!(Literal::c_string(c"\x7f\xff\xfe\u{333}").to_string(), r#" c"\u{7f}\xff\xfe\u{333}" "#.trim()); assert_eq!(Literal::character('a').to_string(), r#" 'a' "#.trim()); assert_eq!(Literal::character('\t').to_string(), r#" '\t' "#.trim()); @@ -52,8 +52,8 @@ fn test_display_literal() { assert_eq!(Literal::byte_character(b'a').to_string(), r#" b'a' "#.trim()); assert_eq!(Literal::byte_character(b'\t').to_string(), r#" b'\t' "#.trim()); assert_eq!(Literal::byte_character(b'\'').to_string(), r#" b'\'' "#.trim()); - assert_eq!(Literal::byte_character(b'"').to_string(), r#" b'\"' "#.trim()); - assert_eq!(Literal::byte_character(0).to_string(), r#" b'\x00' "#.trim()); + assert_eq!(Literal::byte_character(b'"').to_string(), r#" b'"' "#.trim()); + assert_eq!(Literal::byte_character(0).to_string(), r#" b'\0' "#.trim()); assert_eq!(Literal::byte_character(1).to_string(), r#" b'\x01' "#.trim()); } -- cgit 1.4.1-3-g733a5 From 220f3ec99fda594a67c549e3587e0e484ed655ba Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 13 Jun 2024 19:50:44 +0300 Subject: rustc_span: Remove transmutes from span encoding --- compiler/rustc_span/src/span_encoding.rs | 52 +++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 69d7b4ca8c2..9d5bc5b0512 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -4,10 +4,10 @@ use crate::SPAN_TRACK; use crate::{BytePos, SpanData}; use rustc_data_structures::fx::FxIndexSet; + // This code is very hot and uses lots of arithmetic, avoid overflow checks for performance. // See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727 use rustc_serialize::int_overflow::DebugStrictAdd; -use std::mem::transmute; /// A compressed span. /// @@ -105,15 +105,12 @@ struct InlineParent { #[derive(Clone, Copy)] struct PartiallyInterned { index: u32, - _marker1: u16, ctxt: u16, } #[derive(Clone, Copy)] struct Interned { index: u32, - _marker1: u16, - _marker2: u16, } impl InlineCtxt { @@ -130,7 +127,13 @@ impl InlineCtxt { } #[inline] fn span(lo: u32, len: u16, ctxt: u16) -> Span { - unsafe { transmute(InlineCtxt { lo, len, ctxt }) } + Span { lo_or_index: lo, len_with_tag_or_marker: len, ctxt_or_parent_or_marker: ctxt } + } + #[inline] + fn from_span(span: Span) -> InlineCtxt { + let (lo, len, ctxt) = + (span.lo_or_index, span.len_with_tag_or_marker, span.ctxt_or_parent_or_marker); + InlineCtxt { lo, len, ctxt } } } @@ -147,8 +150,16 @@ impl InlineParent { } } #[inline] - fn span(lo: u32, len_with_tag: u16, parent: u16) -> Span { - unsafe { transmute(InlineParent { lo, len_with_tag, parent }) } + fn span(lo: u32, len: u16, parent: u16) -> Span { + let (lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker) = + (lo, PARENT_TAG | len, parent); + Span { lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker } + } + #[inline] + fn from_span(span: Span) -> InlineParent { + let (lo, len_with_tag, parent) = + (span.lo_or_index, span.len_with_tag_or_marker, span.ctxt_or_parent_or_marker); + InlineParent { lo, len_with_tag, parent } } } @@ -162,7 +173,13 @@ impl PartiallyInterned { } #[inline] fn span(index: u32, ctxt: u16) -> Span { - unsafe { transmute(PartiallyInterned { index, _marker1: BASE_LEN_INTERNED_MARKER, ctxt }) } + let (lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker) = + (index, BASE_LEN_INTERNED_MARKER, ctxt); + Span { lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker } + } + #[inline] + fn from_span(span: Span) -> PartiallyInterned { + PartiallyInterned { index: span.lo_or_index, ctxt: span.ctxt_or_parent_or_marker } } } @@ -173,8 +190,13 @@ impl Interned { } #[inline] fn span(index: u32) -> Span { - let _marker1 = BASE_LEN_INTERNED_MARKER; - unsafe { transmute(Interned { index, _marker1, _marker2: CTXT_INTERNED_MARKER }) } + let (lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker) = + (index, BASE_LEN_INTERNED_MARKER, CTXT_INTERNED_MARKER); + Span { lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker } + } + #[inline] + fn from_span(span: Span) -> Interned { + Interned { index: span.lo_or_index } } } @@ -192,20 +214,20 @@ macro_rules! match_span_kind { if $span.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { if $span.len_with_tag_or_marker & PARENT_TAG == 0 { // Inline-context format. - let $span1: InlineCtxt = unsafe { transmute($span) }; + let $span1 = InlineCtxt::from_span($span); $arm1 } else { // Inline-parent format. - let $span2: InlineParent = unsafe { transmute($span) }; + let $span2 = InlineParent::from_span($span); $arm2 } } else if $span.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { // Partially-interned format. - let $span3: PartiallyInterned = unsafe { transmute($span) }; + let $span3 = PartiallyInterned::from_span($span); $arm3 } else { // Interned format. - let $span4: Interned = unsafe { transmute($span) }; + let $span4 = Interned::from_span($span); $arm4 } }; @@ -245,7 +267,7 @@ impl Span { && let parent32 = parent.local_def_index.as_u32() && parent32 <= MAX_CTXT { - return InlineParent::span(lo.0, PARENT_TAG | len as u16, parent32 as u16); + return InlineParent::span(lo.0, len as u16, parent32 as u16); } } -- cgit 1.4.1-3-g733a5 From a1667a98e8eda4e1043e731a392ca543858af44a Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Mon, 10 Jun 2024 20:49:52 +0200 Subject: Fix Miri sysroot for `x run` Miri no longer respects `MIRI_SYSROOT` and wants to be treated like a REAL rustc, with `--sysroot`. *pats Miri* sure Miri, just for you :3. --- src/bootstrap/src/core/build_steps/run.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 354eb2b6003..9268b335db7 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -149,12 +149,14 @@ impl Step for Miri { &[], ); miri.add_rustc_lib_path(builder); - // Forward arguments. miri.arg("--").arg("--target").arg(target.rustc_target_arg()); - miri.args(builder.config.args()); // miri tests need to know about the stage sysroot - miri.env("MIRI_SYSROOT", &miri_sysroot); + miri.arg("--sysroot").arg(miri_sysroot); + + // Forward arguments. This may contain further arguments to the program + // after another --, so this must be at the end. + miri.args(builder.config.args()); let mut miri = Command::from(miri); builder.run(&mut miri); -- cgit 1.4.1-3-g733a5 From b316033dd812f138b069b957cba443047cd71c3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Jun 2024 11:15:55 +0200 Subject: rename CompileTimeInterpreter -> CompileTimeMachine, CompileTimeEvalContext -> CompileTimeInterpCx to match the terms used in the shared interpreter infrastructure --- compiler/rustc_const_eval/src/const_eval/error.rs | 4 ++-- .../src/const_eval/eval_queries.rs | 22 +++++++++++----------- .../rustc_const_eval/src/const_eval/machine.rs | 12 ++++++------ .../rustc_const_eval/src/const_eval/valtrees.rs | 16 ++++++++-------- compiler/rustc_const_eval/src/interpret/intern.rs | 2 +- compiler/rustc_const_eval/src/interpret/util.rs | 6 +++--- .../rustc_const_eval/src/util/caller_location.rs | 4 ++-- .../src/util/check_validity_requirement.rs | 4 ++-- 8 files changed, 35 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 923b9ddf9af..94f4ae2556d 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{layout::LayoutError, ConstInt}; use rustc_span::{Span, Symbol}; -use super::CompileTimeInterpreter; +use super::CompileTimeMachine; use crate::errors::{self, FrameNote, ReportErrorExt}; use crate::interpret::{err_inval, err_machine_stop}; use crate::interpret::{ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType}; @@ -160,7 +160,7 @@ where // Even if this is unused, please don't remove it -- chances are we will need to emit a lint during const-eval again in the future! pub(super) fn lint<'tcx, L>( tcx: TyCtxtAt<'tcx>, - machine: &CompileTimeInterpreter<'tcx>, + machine: &CompileTimeMachine<'tcx>, lint: &'static rustc_session::lint::Lint, decorator: impl FnOnce(Vec) -> L, ) where 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 36f468d3308..88a1503ee89 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -17,7 +17,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{self, Abi}; -use super::{CanAccessMutGlobal, CompileTimeEvalContext, CompileTimeInterpreter}; +use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine}; use crate::const_eval::CheckAlignment; use crate::errors::ConstEvalError; use crate::errors::{self, DanglingPtrInFinal}; @@ -32,7 +32,7 @@ use crate::CTRL_C_RECEIVED; // Returns a pointer to where the result lives #[instrument(level = "trace", skip(ecx, body))] fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, cid: GlobalId<'tcx>, body: &'tcx mir::Body<'tcx>, ) -> InterpResult<'tcx, R> { @@ -139,13 +139,13 @@ pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>( root_span: Span, param_env: ty::ParamEnv<'tcx>, can_access_mut_global: CanAccessMutGlobal, -) -> CompileTimeEvalContext<'tcx> { +) -> CompileTimeInterpCx<'tcx> { debug!("mk_eval_cx: {:?}", param_env); InterpCx::new( tcx, root_span, param_env, - CompileTimeInterpreter::new(can_access_mut_global, CheckAlignment::No), + CompileTimeMachine::new(can_access_mut_global, CheckAlignment::No), ) } @@ -156,7 +156,7 @@ pub fn mk_eval_cx_for_const_val<'tcx>( param_env: ty::ParamEnv<'tcx>, val: mir::ConstValue<'tcx>, ty: Ty<'tcx>, -) -> Option<(CompileTimeEvalContext<'tcx>, OpTy<'tcx>)> { +) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> { let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No); let op = ecx.const_val_to_op(val, ty, None).ok()?; Some((ecx, op)) @@ -170,7 +170,7 @@ pub fn mk_eval_cx_for_const_val<'tcx>( /// encounter an `Indirect` they cannot handle. #[instrument(skip(ecx), level = "debug")] pub(super) fn op_to_const<'tcx>( - ecx: &CompileTimeEvalContext<'tcx>, + ecx: &CompileTimeInterpCx<'tcx>, op: &OpTy<'tcx>, for_diagnostics: bool, ) -> ConstValue<'tcx> { @@ -328,14 +328,14 @@ pub trait InterpretationResult<'tcx> { /// evaluation query. fn make_result( mplace: MPlaceTy<'tcx>, - ecx: &mut InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>, ) -> Self; } impl<'tcx> InterpretationResult<'tcx> for ConstAlloc<'tcx> { fn make_result( mplace: MPlaceTy<'tcx>, - _ecx: &mut InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + _ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>, ) -> Self { ConstAlloc { alloc_id: mplace.ptr().provenance.unwrap().alloc_id(), ty: mplace.layout.ty } } @@ -383,7 +383,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( // they do not have to behave "as if" they were evaluated at runtime. // For consts however we want to ensure they behave "as if" they were evaluated at runtime, // so we have to reject reading mutable global memory. - CompileTimeInterpreter::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error), + CompileTimeMachine::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error), ); let res = ecx.load_mir(cid.instance.def, cid.promoted); res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)).map_err(|error| { @@ -417,7 +417,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( #[inline(always)] fn const_validate_mplace<'tcx>( - ecx: &InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>, mplace: &MPlaceTy<'tcx>, cid: GlobalId<'tcx>, ) -> Result<(), ErrorHandled> { @@ -447,7 +447,7 @@ fn const_validate_mplace<'tcx>( #[inline(always)] fn report_validation_error<'tcx>( - ecx: &InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>, error: InterpErrorInfo<'tcx>, alloc_id: AllocId, ) -> ErrorHandled { diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 79a161d3f03..0dbb6a95376 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -44,7 +44,7 @@ const TINY_LINT_TERMINATOR_LIMIT: usize = 20; const PROGRESS_INDICATOR_START: usize = 4_000_000; /// Extra machine state for CTFE, and the Machine instance -pub struct CompileTimeInterpreter<'tcx> { +pub struct CompileTimeMachine<'tcx> { /// The number of terminators that have been evaluated. /// /// This is used to produce lints informing the user that the compiler is not stuck. @@ -89,12 +89,12 @@ impl From for CanAccessMutGlobal { } } -impl<'tcx> CompileTimeInterpreter<'tcx> { +impl<'tcx> CompileTimeMachine<'tcx> { pub(crate) fn new( can_access_mut_global: CanAccessMutGlobal, check_alignment: CheckAlignment, ) -> Self { - CompileTimeInterpreter { + CompileTimeMachine { num_evaluated_steps: 0, stack: Vec::new(), can_access_mut_global, @@ -163,7 +163,7 @@ impl interpret::AllocMap for FxIndexMap { } } -pub(crate) type CompileTimeEvalContext<'tcx> = InterpCx<'tcx, CompileTimeInterpreter<'tcx>>; +pub(crate) type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>; #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum MemoryKind { @@ -195,7 +195,7 @@ impl interpret::MayLeak for ! { } } -impl<'tcx> CompileTimeEvalContext<'tcx> { +impl<'tcx> CompileTimeInterpCx<'tcx> { fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) { let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); @@ -369,7 +369,7 @@ impl<'tcx> CompileTimeEvalContext<'tcx> { } } -impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> { +impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { compile_time_machine!(<'tcx>); type MemoryKind = MemoryKind; diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 66993476bef..2e8ad445cf5 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -9,7 +9,7 @@ use rustc_target::abi::{Abi, VariantIdx}; use tracing::{debug, instrument, trace}; use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const}; -use super::machine::CompileTimeEvalContext; +use super::machine::CompileTimeInterpCx; use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES}; use crate::const_eval::CanAccessMutGlobal; use crate::errors::MaxNumNodesInConstErr; @@ -21,7 +21,7 @@ use crate::interpret::{ #[instrument(skip(ecx), level = "debug")] fn branches<'tcx>( - ecx: &CompileTimeEvalContext<'tcx>, + ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, n: usize, variant: Option, @@ -59,7 +59,7 @@ fn branches<'tcx>( #[instrument(skip(ecx), level = "debug")] fn slice_branches<'tcx>( - ecx: &CompileTimeEvalContext<'tcx>, + ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, num_nodes: &mut usize, ) -> ValTreeCreationResult<'tcx> { @@ -77,7 +77,7 @@ fn slice_branches<'tcx>( #[instrument(skip(ecx), level = "debug")] fn const_to_valtree_inner<'tcx>( - ecx: &CompileTimeEvalContext<'tcx>, + ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, num_nodes: &mut usize, ) -> ValTreeCreationResult<'tcx> { @@ -219,7 +219,7 @@ fn reconstruct_place_meta<'tcx>( #[instrument(skip(ecx), level = "debug", ret)] fn create_valtree_place<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, layout: TyAndLayout<'tcx>, valtree: ty::ValTree<'tcx>, ) -> MPlaceTy<'tcx> { @@ -364,7 +364,7 @@ pub fn valtree_to_const_value<'tcx>( /// Put a valtree into memory and return a reference to that. fn valtree_to_ref<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, valtree: ty::ValTree<'tcx>, pointee_ty: Ty<'tcx>, ) -> Immediate { @@ -380,7 +380,7 @@ fn valtree_to_ref<'tcx>( #[instrument(skip(ecx), level = "debug")] fn valtree_into_mplace<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, valtree: ty::ValTree<'tcx>, ) { @@ -457,6 +457,6 @@ fn valtree_into_mplace<'tcx>( } } -fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx>, place: &MPlaceTy<'tcx>) { +fn dump_place<'tcx>(ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>) { trace!("{:?}", ecx.dump_place(&PlaceTy::from(place.clone()))); } diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 3066e0933d9..8b0a2afa4d6 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -45,7 +45,7 @@ pub trait HasStaticRootDefId { fn static_def_id(&self) -> Option; } -impl HasStaticRootDefId for const_eval::CompileTimeInterpreter<'_> { +impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> { fn static_def_id(&self) -> Option { Some(self.static_root_ids?.1) } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 10fd6399b9a..f6537ed6ea9 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,4 +1,4 @@ -use crate::const_eval::{CompileTimeEvalContext, CompileTimeInterpreter, InterpretationResult}; +use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult}; use rustc_hir::def_id::LocalDefId; use rustc_middle::mir; use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer}; @@ -84,7 +84,7 @@ where impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx> { fn make_result( mplace: MPlaceTy<'tcx>, - ecx: &mut InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>, ) -> Self { let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); let alloc = ecx.memory.alloc_map.swap_remove(&alloc_id).unwrap().1; @@ -93,7 +93,7 @@ impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx> } pub(crate) fn create_static_alloc<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, static_def_id: LocalDefId, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 62c5f8734a2..3b07bee2d9c 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -7,12 +7,12 @@ use rustc_middle::ty::{self, Mutability}; use rustc_span::symbol::Symbol; use tracing::trace; -use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeEvalContext}; +use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeInterpCx}; use crate::interpret::*; /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. fn alloc_caller_location<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, filename: Symbol, line: u32, col: u32, 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 68fb122a765..daf57285ebe 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -3,7 +3,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, Val use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt}; use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants}; -use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeInterpreter}; +use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeMachine}; use crate::interpret::{InterpCx, MemoryKind, OpTy}; /// Determines if this type permits "raw" initialization by just transmuting some memory into an @@ -45,7 +45,7 @@ fn might_permit_raw_init_strict<'tcx>( tcx: TyCtxt<'tcx>, kind: ValidityRequirement, ) -> Result> { - let machine = CompileTimeInterpreter::new(CanAccessMutGlobal::No, CheckAlignment::Error); + let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error); let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine); -- cgit 1.4.1-3-g733a5 From 54e24c15736e7602fe4d84641ac6d5c973397114 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Jun 2024 11:30:24 +0200 Subject: const-eval: make lint scope computation consistent --- compiler/rustc_const_eval/src/const_eval/error.rs | 12 ++-------- .../src/const_eval/eval_queries.rs | 2 +- .../rustc_const_eval/src/const_eval/machine.rs | 14 +++++++++-- .../rustc_const_eval/src/interpret/eval_context.rs | 27 ++++++++-------------- 4 files changed, 25 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 94f4ae2556d..b17dc7f3ddd 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -1,7 +1,6 @@ use std::mem; use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg}; -use rustc_hir::CRATE_HIR_ID; use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo}; use rustc_middle::mir::AssertKind; use rustc_middle::query::TyCtxtAt; @@ -156,7 +155,7 @@ where } } -/// Emit a lint from a const-eval situation. +/// Emit a lint from a const-eval situation, with a backtrace. // Even if this is unused, please don't remove it -- chances are we will need to emit a lint during const-eval again in the future! pub(super) fn lint<'tcx, L>( tcx: TyCtxtAt<'tcx>, @@ -168,12 +167,5 @@ pub(super) fn lint<'tcx, L>( { let (span, frames) = get_span_and_frames(tcx, &machine.stack); - tcx.emit_node_span_lint( - lint, - // We use the root frame for this so the crate that defines the const defines whether the - // lint is emitted. - machine.stack.first().and_then(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID), - span, - decorator(frames), - ); + tcx.emit_node_span_lint(lint, machine.best_lint_scope(*tcx), span, decorator(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 88a1503ee89..4b8145eb485 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -114,7 +114,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( let err_diag = errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }; ecx.tcx.emit_node_span_lint( lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE, - ecx.best_lint_scope(), + ecx.machine.best_lint_scope(*ecx.tcx), err_diag.span, err_diag, ) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 0dbb6a95376..4f6df857142 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -9,12 +9,13 @@ use rustc_data_structures::fx::IndexEntry; use rustc_hir::def_id::DefId; use rustc_hir::def_id::LocalDefId; use rustc_hir::LangItem; +use rustc_hir::{self as hir, CRATE_HIR_ID}; use rustc_middle::bug; use rustc_middle::mir; use rustc_middle::mir::AssertMessage; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty; use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::WRITES_THROUGH_IMMUTABLE_POINTER; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; @@ -369,6 +370,15 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { } } +impl<'tcx> CompileTimeMachine<'tcx> { + #[inline(always)] + /// Find the first stack frame that is within the current crate, if any. + /// Otherwise, return the crate's HirId + pub fn best_lint_scope(&self, tcx: TyCtxt<'tcx>) -> hir::HirId { + self.stack.iter().find_map(|frame| frame.lint_root(tcx)).unwrap_or(CRATE_HIR_ID) + } +} + impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { compile_time_machine!(<'tcx>); @@ -600,7 +610,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // By default, we stop after a million steps, but the user can disable this lint // to be able to run until the heat death of the universe or power loss, whichever // comes first. - let hir_id = ecx.best_lint_scope(); + let hir_id = ecx.machine.best_lint_scope(*ecx.tcx); let is_error = ecx .tcx .lint_level_at_node( diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 63572197508..4d93038a81e 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -4,7 +4,6 @@ use std::{fmt, mem}; use either::{Either, Left, Right}; use tracing::{debug, info, info_span, instrument, trace}; -use hir::CRATE_HIR_ID; use rustc_errors::DiagCtxt; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::IndexVec; @@ -271,13 +270,18 @@ impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> { } } - pub fn lint_root(&self) -> Option { - self.current_source_info().and_then(|source_info| { - match &self.body.source_scopes[source_info.scope].local_data { + pub fn lint_root(&self, tcx: TyCtxt<'tcx>) -> Option { + // We first try to get a HirId via the current source scope, + // and fall back to `body.source`. + self.current_source_info() + .and_then(|source_info| match &self.body.source_scopes[source_info.scope].local_data { mir::ClearCrossCrate::Set(data) => Some(data.lint_root), mir::ClearCrossCrate::Clear => None, - } - }) + }) + .or_else(|| { + let def_id = self.body.source.def_id().as_local(); + def_id.map(|def_id| tcx.local_def_id_to_hir_id(def_id)) + }) } /// Returns the address of the buffer where the locals are stored. This is used by `Place` as a @@ -509,17 +513,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.stack().last().map_or(self.tcx.span, |f| f.current_span()) } - /// Find the first stack frame that is within the current crate, if any; - /// otherwise return the crate's HirId. - #[inline(always)] - pub fn best_lint_scope(&self) -> hir::HirId { - self.stack() - .iter() - .find_map(|frame| frame.body.source.def_id().as_local()) - .map_or(CRATE_HIR_ID, |def_id| self.tcx.local_def_id_to_hir_id(def_id)) - } - - #[inline(always)] pub(crate) fn stack(&self) -> &[Frame<'tcx, M::Provenance, M::FrameExtra>] { M::stack(self) } -- cgit 1.4.1-3-g733a5 From 14014abf06712412b4e700b74c570148ac63de27 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Mon, 10 Jun 2024 18:32:31 +0000 Subject: Update fuchsia commit, and SDK to 21.20240610.2.1 This includes a fix to the race when publishing multiple packages at the same time. --- .../host-x86_64/x86_64-gnu-integration/Dockerfile | 28 +++++++++++----------- .../x86_64-gnu-integration/build-fuchsia.sh | 2 +- src/ci/docker/scripts/build-fuchsia-toolchain.sh | 8 +++---- src/ci/docker/scripts/fuchsia-test-runner.py | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile index d228dfc87eb..a944f370c6b 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile @@ -26,27 +26,27 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ # Duplicated in dist-various-2 Dockerfile. # FIXME: Move to canonical triple ENV \ - AR_x86_64_fuchsia=x86_64-unknown-fuchsia-ar \ - CC_x86_64_fuchsia=x86_64-unknown-fuchsia-clang \ - CFLAGS_x86_64_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \ - CXX_x86_64_fuchsia=x86_64-unknown-fuchsia-clang++ \ - CXXFLAGS_x86_64_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \ - LDFLAGS_x86_64_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib" + AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \ + CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \ + CFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \ + CXX_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang++ \ + CXXFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \ + LDFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib" WORKDIR /tmp COPY scripts/shared.sh /tmp/ COPY scripts/build-fuchsia-toolchain.sh /tmp/ RUN /tmp/build-fuchsia-toolchain.sh -ENV CARGO_TARGET_X86_64_FUCHSIA_AR /usr/local/bin/llvm-ar -ENV CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS \ +ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_AR /usr/local/bin/llvm-ar +ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS \ -C panic=abort \ -C force-unwind-tables=yes \ -C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot \ -Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot/lib \ -Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib -ENV TARGETS=x86_64-fuchsia +ENV TARGETS=x86_64-unknown-fuchsia ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnu ENV TARGETS=$TARGETS,wasm32-unknown-unknown @@ -69,11 +69,11 @@ ENV RUST_CONFIGURE_ARGS \ --llvm-libunwind=in-tree \ --enable-extended \ --disable-docs \ - --set target.x86_64-fuchsia.cc=/usr/local/bin/clang \ - --set target.x86_64-fuchsia.cxx=/usr/local/bin/clang++ \ - --set target.x86_64-fuchsia.ar=/usr/local/bin/llvm-ar \ - --set target.x86_64-fuchsia.ranlib=/usr/local/bin/llvm-ranlib \ - --set target.x86_64-fuchsia.linker=/usr/local/bin/ld.lld + --set target.x86_64-unknown-fuchsia.cc=/usr/local/bin/clang \ + --set target.x86_64-unknown-fuchsia.cxx=/usr/local/bin/clang++ \ + --set target.x86_64-unknown-fuchsia.ar=/usr/local/bin/llvm-ar \ + --set target.x86_64-unknown-fuchsia.ranlib=/usr/local/bin/llvm-ranlib \ + --set target.x86_64-unknown-fuchsia.linker=/usr/local/bin/ld.lld ENV SCRIPT \ python3 ../x.py install --target $TARGETS compiler/rustc library/std clippy && \ bash ../src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh b/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh index 913a0b0c09c..2bb1d0a6338 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh @@ -35,7 +35,7 @@ PICK_REFS=() # commit hash of fuchsia.git and some other repos in the "monorepo" checkout, in # addition to versions of prebuilts. It should be bumped regularly by the # Fuchsia team – we aim for every 1-2 months. -INTEGRATION_SHA=1011e3298775ee7cdf6f6dc73e808d6a86e33bd6 +INTEGRATION_SHA=737ebdd83afa47b742ca8325fad0176952fcefbd checkout=fuchsia jiri=.jiri_root/bin/jiri diff --git a/src/ci/docker/scripts/build-fuchsia-toolchain.sh b/src/ci/docker/scripts/build-fuchsia-toolchain.sh index 7a0d4fcffc1..027d412d250 100755 --- a/src/ci/docker/scripts/build-fuchsia-toolchain.sh +++ b/src/ci/docker/scripts/build-fuchsia-toolchain.sh @@ -4,13 +4,13 @@ set -ex source shared.sh FUCHSIA_SDK_URL=https://chrome-infra-packages.appspot.com/dl/fuchsia/sdk/core/linux-amd64 -FUCHSIA_SDK_ID=version:20.20240412.3.1 -FUCHSIA_SDK_SHA256=cc52f3497487dd813c89d9316e6967efcea89c7759edccf3e40fcf3662e53f19 +FUCHSIA_SDK_ID=version:21.20240610.2.1 +FUCHSIA_SDK_SHA256=2d2d057fc3f0404197cced2200f88cbcdaaf5fbf6475955045091f8676791ce7 FUCHSIA_SDK_USR_DIR=/usr/local/core-linux-amd64-fuchsia-sdk CLANG_DOWNLOAD_URL=\ https://chrome-infra-packages.appspot.com/dl/fuchsia/third_party/clang/linux-amd64 -CLANG_DOWNLOAD_ID=git_revision:c777c011a709dffd4fa5e79cad7947b7c3405d02 -CLANG_DOWNLOAD_SHA256=779167422ad73c292f049dcea5569f84577af9292189ed2749518b966a4d0844 +CLANG_DOWNLOAD_ID=git_revision:3809e20afc68d7d03821f0ec59b928dcf9befbf4 +CLANG_DOWNLOAD_SHA256=3c2c442b61cd9e8f1b567738f6d53cffe11b3fc820e7dae87a82a0859be8f204 install_clang() { mkdir -p clang_download diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 4f504341d52..d791550a8db 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -286,7 +286,7 @@ class TestEnvironment: # Look up the product bundle transfer manifest. self.log_info("Looking up the product bundle transfer manifest...") product_name = "minimal." + self.triple_to_arch(self.target) - fuchsia_version = "20.20240412.3.1" + fuchsia_version = "21.20240610.2.1" out = self.check_output( [ -- cgit 1.4.1-3-g733a5 From 5de8e6edfcc747930891a0adc8e90608776dbe54 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 12 Jun 2024 23:51:31 +0000 Subject: Tweak output of import suggestions When both `std::` and `core::` items are available, only suggest the `std::` ones. We ensure that in `no_std` crates we suggest `core::` items. Ensure that the list of items suggested to be imported are always in the order of local crate items, `std`/`core` items and finally foreign crate items. Tweak wording of import suggestion: if there are multiple items but they are all of the same kind, we use the kind name and not the generic "items". Fix #83564. --- compiler/rustc_resolve/src/diagnostics.rs | 46 ++++++++++++++++++---- src/tools/clippy/tests/ui/crashes/ice-6252.stderr | 4 +- tests/ui/const-generics/issues/issue-82956.stderr | 2 +- tests/ui/consts/const_refs_to_static-ice-121413.rs | 4 ++ .../consts/const_refs_to_static-ice-121413.stderr | 8 ++-- .../issue-56028-there-is-an-enum-variant.stderr | 2 +- .../extern-prelude-from-opaque-fail-2018.stderr | 7 +--- tests/ui/imports/cycle-import-in-std-1.stderr | 3 +- tests/ui/imports/cycle-import-in-std-2.stderr | 3 +- .../import-alias-issue-121168.edition2018.stderr | 2 +- .../import-alias-issue-121168.edition2021.stderr | 2 +- tests/ui/imports/issue-56125.stderr | 10 ++--- tests/ui/lint/use_suggestion_json.stderr | 4 +- tests/ui/namespace/namespace-mix.stderr | 8 ++-- tests/ui/resolve/issue-16058.stderr | 2 +- tests/ui/resolve/issue-21221-1.stderr | 12 +++--- tests/ui/resolve/issue-21221-2.stderr | 2 +- tests/ui/resolve/issue-50599.stderr | 2 +- tests/ui/resolve/issue-73427.stderr | 2 +- tests/ui/resolve/privacy-enum-ctor.stderr | 4 +- .../not-allowed.stderr | 4 +- .../rust-2018/issue-52202-use-suggestions.stderr | 2 +- .../core-std-import-order-issue-83564.no_std.fixed | 22 +++++++++++ ...core-std-import-order-issue-83564.no_std.stderr | 14 +++++++ .../core-std-import-order-issue-83564.rs | 12 +++++- .../core-std-import-order-issue-83564.std.fixed | 22 +++++++++++ .../core-std-import-order-issue-83564.std.stderr | 14 +++++++ .../core-std-import-order-issue-83564.stderr | 16 -------- tests/ui/suggestions/crate-or-module-typo.stderr | 4 +- .../suggestions/suggest-tryinto-edition-change.rs | 5 +-- .../suggest-tryinto-edition-change.stderr | 19 +++------ 31 files changed, 171 insertions(+), 92 deletions(-) create mode 100644 tests/ui/suggestions/core-std-import-order-issue-83564.no_std.fixed create mode 100644 tests/ui/suggestions/core-std-import-order-issue-83564.no_std.stderr create mode 100644 tests/ui/suggestions/core-std-import-order-issue-83564.std.fixed create mode 100644 tests/ui/suggestions/core-std-import-order-issue-83564.std.stderr delete mode 100644 tests/ui/suggestions/core-std-import-order-issue-83564.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d1541527cf5..8d470c6c61e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2783,33 +2783,65 @@ fn show_candidates( // by iterating through a hash map, so make sure they are ordered: for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] { path_strings.sort_by(|a, b| a.0.cmp(&b.0)); + path_strings.dedup_by(|a, b| a.0 == b.0); let core_path_strings = path_strings.extract_if(|p| p.0.starts_with("core::")).collect::>(); - path_strings.extend(core_path_strings); - path_strings.dedup_by(|a, b| a.0 == b.0); + let std_path_strings = + path_strings.extract_if(|p| p.0.starts_with("std::")).collect::>(); + let foreign_crate_path_strings = + path_strings.extract_if(|p| !p.0.starts_with("crate::")).collect::>(); + + // We list the `crate` local paths first. + // Then we list the `std`/`core` paths. + if std_path_strings.len() == core_path_strings.len() { + // Do not list `core::` paths if we are already listing the `std::` ones. + path_strings.extend(std_path_strings); + } else { + path_strings.extend(std_path_strings); + path_strings.extend(core_path_strings); + } + // List all paths from foreign crates last. + path_strings.extend(foreign_crate_path_strings); } - accessible_path_strings.sort(); if !accessible_path_strings.is_empty() { - let (determiner, kind, name, through) = + let (determiner, kind, s, name, through) = if let [(name, descr, _, _, via_import)] = &accessible_path_strings[..] { ( "this", *descr, + "", format!(" `{name}`"), if *via_import { " through its public re-export" } else { "" }, ) } else { - ("one of these", "items", String::new(), "") + // Get the unique item kinds and if there's only one, we use the right kind name + // instead of the more generic "items". + let mut kinds = accessible_path_strings + .iter() + .map(|(_, descr, _, _, _)| *descr) + .collect::>() + .into_iter(); + let kind = if let Some(kind) = kinds.next() + && let None = kinds.next() + { + kind + } else { + "item" + }; + let s = if kind.ends_with('s') { "es" } else { "s" }; + + ("one of these", kind, s, String::new(), "") }; let instead = if let Instead::Yes = instead { " instead" } else { "" }; let mut msg = if let DiagMode::Pattern = mode { format!( - "if you meant to match on {kind}{instead}{name}, use the full path in the pattern", + "if you meant to match on {kind}{s}{instead}{name}, use the full path in the \ + pattern", ) } else { - format!("consider importing {determiner} {kind}{through}{instead}") + format!("consider importing {determiner} {kind}{s}{through}{instead}") }; for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) { diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr index ce3b9495eb1..cd2031af1c6 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr @@ -4,9 +4,7 @@ error[E0412]: cannot find type `PhantomData` in this scope LL | _n: PhantomData, | ^^^^^^^^^^^ not found in this scope | -help: consider importing one of these items - | -LL + use core::marker::PhantomData; +help: consider importing this struct | LL + use std::marker::PhantomData; | diff --git a/tests/ui/const-generics/issues/issue-82956.stderr b/tests/ui/const-generics/issues/issue-82956.stderr index d0fc7112426..a956fc741f4 100644 --- a/tests/ui/const-generics/issues/issue-82956.stderr +++ b/tests/ui/const-generics/issues/issue-82956.stderr @@ -4,7 +4,7 @@ error[E0433]: failed to resolve: use of undeclared type `IntoIter` LL | let mut iter = IntoIter::new(self); | ^^^^^^^^ use of undeclared type `IntoIter` | -help: consider importing one of these items +help: consider importing one of these structs | LL + use std::array::IntoIter; | diff --git a/tests/ui/consts/const_refs_to_static-ice-121413.rs b/tests/ui/consts/const_refs_to_static-ice-121413.rs index 8a24fb799b6..8fc3912efd0 100644 --- a/tests/ui/consts/const_refs_to_static-ice-121413.rs +++ b/tests/ui/consts/const_refs_to_static-ice-121413.rs @@ -5,12 +5,16 @@ // ignore-tidy-linelength #![feature(const_refs_to_static)] const REF_INTERIOR_MUT: &usize = { + //~^ HELP consider importing this struct static FOO: Sync = AtomicUsize::new(0); //~^ ERROR failed to resolve: use of undeclared type `AtomicUsize` //~| WARN trait objects without an explicit `dyn` are deprecated //~| ERROR the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time //~| ERROR the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + //~| HELP if this is an object-safe trait, use `dyn` + //~| HELP the trait `Sized` is not implemented for `(dyn Sync + 'static)` + //~| HELP the trait `Sized` is not implemented for `(dyn Sync + 'static)` unsafe { &*(&FOO as *const _ as *const usize) } }; pub fn main() {} diff --git a/tests/ui/consts/const_refs_to_static-ice-121413.stderr b/tests/ui/consts/const_refs_to_static-ice-121413.stderr index c977c698a92..fbe32a70293 100644 --- a/tests/ui/consts/const_refs_to_static-ice-121413.stderr +++ b/tests/ui/consts/const_refs_to_static-ice-121413.stderr @@ -1,5 +1,5 @@ error[E0433]: failed to resolve: use of undeclared type `AtomicUsize` - --> $DIR/const_refs_to_static-ice-121413.rs:8:24 + --> $DIR/const_refs_to_static-ice-121413.rs:9:24 | LL | static FOO: Sync = AtomicUsize::new(0); | ^^^^^^^^^^^ use of undeclared type `AtomicUsize` @@ -10,7 +10,7 @@ LL + use std::sync::atomic::AtomicUsize; | warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/const_refs_to_static-ice-121413.rs:8:17 + --> $DIR/const_refs_to_static-ice-121413.rs:9:17 | LL | static FOO: Sync = AtomicUsize::new(0); | ^^^^ @@ -24,7 +24,7 @@ LL | static FOO: dyn Sync = AtomicUsize::new(0); | +++ error[E0277]: the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time - --> $DIR/const_refs_to_static-ice-121413.rs:8:17 + --> $DIR/const_refs_to_static-ice-121413.rs:9:17 | LL | static FOO: Sync = AtomicUsize::new(0); | ^^^^ doesn't have a size known at compile-time @@ -32,7 +32,7 @@ LL | static FOO: Sync = AtomicUsize::new(0); = help: the trait `Sized` is not implemented for `(dyn Sync + 'static)` error[E0277]: the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time - --> $DIR/const_refs_to_static-ice-121413.rs:8:24 + --> $DIR/const_refs_to_static-ice-121413.rs:9:24 | LL | static FOO: Sync = AtomicUsize::new(0); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time diff --git a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr index 5c610f36322..b1a15b8594a 100644 --- a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr +++ b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr @@ -22,7 +22,7 @@ error[E0425]: cannot find value `Set` in this scope LL | fn setup() -> Set { Set } | ^^^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these unit variants | LL + use AffixHeart::Set; | diff --git a/tests/ui/hygiene/extern-prelude-from-opaque-fail-2018.stderr b/tests/ui/hygiene/extern-prelude-from-opaque-fail-2018.stderr index 78e6376bca2..cc229764ad3 100644 --- a/tests/ui/hygiene/extern-prelude-from-opaque-fail-2018.stderr +++ b/tests/ui/hygiene/extern-prelude-from-opaque-fail-2018.stderr @@ -24,8 +24,7 @@ LL | fn f() { my_core::mem::drop(0); } LL | a!(); | ---- in this macro invocation | - = help: consider importing one of these items: - core::mem + = help: consider importing this module: std::mem = note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -35,9 +34,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `my_core` LL | fn f() { my_core::mem::drop(0); } | ^^^^^^^ use of undeclared crate or module `my_core` | -help: consider importing one of these items - | -LL + use core::mem; +help: consider importing this module | LL + use std::mem; | diff --git a/tests/ui/imports/cycle-import-in-std-1.stderr b/tests/ui/imports/cycle-import-in-std-1.stderr index d4e6f32cc10..a7dfc6231ba 100644 --- a/tests/ui/imports/cycle-import-in-std-1.stderr +++ b/tests/ui/imports/cycle-import-in-std-1.stderr @@ -4,8 +4,7 @@ error[E0432]: unresolved import `ops` LL | use ops::{self as std}; | ^^^^^^^^^^^ no external crate `ops` | - = help: consider importing one of these items instead: - core::ops + = help: consider importing this module instead: std::ops error: aborting due to 1 previous error diff --git a/tests/ui/imports/cycle-import-in-std-2.stderr b/tests/ui/imports/cycle-import-in-std-2.stderr index dc0270dffe4..8d94693cd51 100644 --- a/tests/ui/imports/cycle-import-in-std-2.stderr +++ b/tests/ui/imports/cycle-import-in-std-2.stderr @@ -4,8 +4,7 @@ error[E0432]: unresolved import `ops` LL | use ops::{self as std}; | ^^^^^^^^^^^ no external crate `ops` | - = help: consider importing one of these items instead: - core::ops + = help: consider importing this module instead: std::ops error: aborting due to 1 previous error diff --git a/tests/ui/imports/import-alias-issue-121168.edition2018.stderr b/tests/ui/imports/import-alias-issue-121168.edition2018.stderr index b61a0e3edd5..e14e700c33d 100644 --- a/tests/ui/imports/import-alias-issue-121168.edition2018.stderr +++ b/tests/ui/imports/import-alias-issue-121168.edition2018.stderr @@ -4,7 +4,7 @@ error[E0412]: cannot find type `Foo` in this scope LL | let _: Foo = todo!(); | ^^^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these structs | LL + use crate::nice_crate_name::Foo; | diff --git a/tests/ui/imports/import-alias-issue-121168.edition2021.stderr b/tests/ui/imports/import-alias-issue-121168.edition2021.stderr index b61a0e3edd5..e14e700c33d 100644 --- a/tests/ui/imports/import-alias-issue-121168.edition2021.stderr +++ b/tests/ui/imports/import-alias-issue-121168.edition2021.stderr @@ -4,7 +4,7 @@ error[E0412]: cannot find type `Foo` in this scope LL | let _: Foo = todo!(); | ^^^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these structs | LL + use crate::nice_crate_name::Foo; | diff --git a/tests/ui/imports/issue-56125.stderr b/tests/ui/imports/issue-56125.stderr index d2a0f436c42..0c4a569c7ea 100644 --- a/tests/ui/imports/issue-56125.stderr +++ b/tests/ui/imports/issue-56125.stderr @@ -4,16 +4,16 @@ error[E0432]: unresolved import `empty::issue_56125` LL | use empty::issue_56125; | ^^^^^^^^^^^^^^^^^^ no `issue_56125` in `m3::empty` | -help: consider importing one of these items instead +help: consider importing one of these modules instead | +LL | use crate::m3::last_segment::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | use crate::m3::non_last_segment::non_last_segment::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | use ::issue_56125::issue_56125; | ~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | use ::issue_56125::last_segment::issue_56125; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | use ::issue_56125::non_last_segment::non_last_segment::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | use crate::m3::last_segment::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ and 1 other candidate error[E0659]: `issue_56125` is ambiguous diff --git a/tests/ui/lint/use_suggestion_json.stderr b/tests/ui/lint/use_suggestion_json.stderr index acc36550642..4683e5dd8f3 100644 --- a/tests/ui/lint/use_suggestion_json.stderr +++ b/tests/ui/lint/use_suggestion_json.stderr @@ -95,7 +95,7 @@ mod foo { ], "children": [ { - "message": "consider importing one of these items", + "message": "consider importing one of these structs", "code": null, "level": "help", "spans": [ @@ -386,7 +386,7 @@ mod foo { \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m let x: Iter;\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m -\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: consider importing one of these items\u001b[0m +\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: consider importing one of these structs\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[38;5;10m+ use std::collections::binary_heap::Iter;\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m diff --git a/tests/ui/namespace/namespace-mix.stderr b/tests/ui/namespace/namespace-mix.stderr index 4eff08ead42..b80363fe8f8 100644 --- a/tests/ui/namespace/namespace-mix.stderr +++ b/tests/ui/namespace/namespace-mix.stderr @@ -12,7 +12,7 @@ help: a tuple struct with a similar name exists | LL | check(m1::TS); | ~~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use m2::S; | @@ -40,7 +40,7 @@ help: a tuple struct with a similar name exists | LL | check(xm1::TS); | ~~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use m2::S; | @@ -66,7 +66,7 @@ help: a tuple variant with a similar name exists | LL | check(m7::TV); | ~~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use m8::V; | @@ -94,7 +94,7 @@ help: a tuple variant with a similar name exists | LL | check(xm7::TV); | ~~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use m8::V; | diff --git a/tests/ui/resolve/issue-16058.stderr b/tests/ui/resolve/issue-16058.stderr index 914990c35ff..12b1ac8a5fb 100644 --- a/tests/ui/resolve/issue-16058.stderr +++ b/tests/ui/resolve/issue-16058.stderr @@ -4,7 +4,7 @@ error[E0574]: expected struct, variant or union type, found enum `Result` LL | Result { | ^^^^^^ not a struct, variant or union type | -help: consider importing one of these items instead +help: consider importing one of these type aliases instead | LL + use std::fmt::Result; | diff --git a/tests/ui/resolve/issue-21221-1.stderr b/tests/ui/resolve/issue-21221-1.stderr index a38116cd728..ccf03afaa19 100644 --- a/tests/ui/resolve/issue-21221-1.stderr +++ b/tests/ui/resolve/issue-21221-1.stderr @@ -4,14 +4,14 @@ error[E0405]: cannot find trait `Mul` in this scope LL | impl Mul for Foo { | ^^^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these traits + | +LL + use std::ops::Mul; | LL + use mul1::Mul; | LL + use mul2::Mul; | -LL + use std::ops::Mul; - | error[E0412]: cannot find type `Mul` in this scope --> $DIR/issue-21221-1.rs:58:16 @@ -19,14 +19,14 @@ error[E0412]: cannot find type `Mul` in this scope LL | fn getMul() -> Mul { | ^^^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these traits + | +LL + use std::ops::Mul; | LL + use mul1::Mul; | LL + use mul2::Mul; | -LL + use std::ops::Mul; - | error[E0405]: cannot find trait `ThisTraitReallyDoesntExistInAnyModuleReally` in this scope --> $DIR/issue-21221-1.rs:63:6 diff --git a/tests/ui/resolve/issue-21221-2.stderr b/tests/ui/resolve/issue-21221-2.stderr index 3bd4c1a5d13..5db327955eb 100644 --- a/tests/ui/resolve/issue-21221-2.stderr +++ b/tests/ui/resolve/issue-21221-2.stderr @@ -4,7 +4,7 @@ error[E0405]: cannot find trait `T` in this scope LL | impl T for Foo { } | ^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these traits | LL + use baz::T; | diff --git a/tests/ui/resolve/issue-50599.stderr b/tests/ui/resolve/issue-50599.stderr index e5eacd741fb..24fb3d580b8 100644 --- a/tests/ui/resolve/issue-50599.stderr +++ b/tests/ui/resolve/issue-50599.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find value `LOG10_2` in module `std::f64` LL | const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize; | ^^^^^^^ not found in `std::f64` | -help: consider importing one of these items +help: consider importing one of these constants | LL + use std::f128::consts::LOG10_2; | diff --git a/tests/ui/resolve/issue-73427.stderr b/tests/ui/resolve/issue-73427.stderr index c5e245d884b..0a9a504f79c 100644 --- a/tests/ui/resolve/issue-73427.stderr +++ b/tests/ui/resolve/issue-73427.stderr @@ -105,7 +105,7 @@ help: the following enum variant is available | LL | (E::TupleWithFields(/* fields */)).foo(); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use std::f128::consts::E; | diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr index 01c8a38d2a4..ee3aecddcc3 100644 --- a/tests/ui/resolve/privacy-enum-ctor.stderr +++ b/tests/ui/resolve/privacy-enum-ctor.stderr @@ -82,7 +82,7 @@ help: a function with a similar name exists | LL | let _: E = m::f; | ~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use std::f128::consts::E; | @@ -123,7 +123,7 @@ help: alternatively, the following enum variant is available | LL | let _: E = (E::Fn(/* fields */)); | ~~~~~~~~~~~~~~~~~~~~~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use std::f128::consts::E; | diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr index 7f989c15f1c..d0c084f7bd5 100644 --- a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr @@ -4,10 +4,8 @@ error[E0432]: unresolved import `alloc` LL | use alloc; | ^^^^^ no external crate `alloc` | -help: consider importing one of these items instead +help: consider importing this module instead | -LL | use core::alloc; - | ~~~~~~~~~~~ LL | use std::alloc; | ~~~~~~~~~~ diff --git a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr index 49736205f20..ee1a336ea98 100644 --- a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr +++ b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr @@ -4,7 +4,7 @@ error[E0422]: cannot find struct, variant or union type `Drain` in this scope LL | let _d = Drain {}; | ^^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these structs | LL + use crate::plumbing::Drain; | diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.fixed b/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.fixed new file mode 100644 index 00000000000..02d667d9844 --- /dev/null +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.fixed @@ -0,0 +1,22 @@ +//@ edition:2018 +// +// This is a regression test for #83564. +// For some reason, Rust 2018 or higher is required to reproduce the bug. +//@ run-rustfix +//@ revisions: no_std std +//@ [no_std]compile-flags: --cfg=no_std -C panic=abort +#![cfg_attr(no_std, no_std)] + +use core::num::NonZero; + +fn main() { + //~^ HELP consider importing this struct + let _x = NonZero::new(5u32).unwrap(); + //~^ ERROR failed to resolve: use of undeclared type `NonZero` +} + +#[allow(dead_code)] +#[cfg_attr(no_std, panic_handler)] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.stderr b/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.stderr new file mode 100644 index 00000000000..d73f613bf9c --- /dev/null +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.stderr @@ -0,0 +1,14 @@ +error[E0433]: failed to resolve: use of undeclared type `NonZero` + --> $DIR/core-std-import-order-issue-83564.rs:12:14 + | +LL | let _x = NonZero::new(5u32).unwrap(); + | ^^^^^^^ use of undeclared type `NonZero` + | +help: consider importing this struct + | +LL + use core::num::NonZero; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.rs b/tests/ui/suggestions/core-std-import-order-issue-83564.rs index 6f2bdd7a38a..5bb5bfe176b 100644 --- a/tests/ui/suggestions/core-std-import-order-issue-83564.rs +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.rs @@ -2,9 +2,19 @@ // // This is a regression test for #83564. // For some reason, Rust 2018 or higher is required to reproduce the bug. +//@ run-rustfix +//@ revisions: no_std std +//@ [no_std]compile-flags: --cfg=no_std -C panic=abort +#![cfg_attr(no_std, no_std)] fn main() { - //~^ HELP consider importing one of these items + //~^ HELP consider importing this struct let _x = NonZero::new(5u32).unwrap(); //~^ ERROR failed to resolve: use of undeclared type `NonZero` } + +#[allow(dead_code)] +#[cfg_attr(no_std, panic_handler)] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.std.fixed b/tests/ui/suggestions/core-std-import-order-issue-83564.std.fixed new file mode 100644 index 00000000000..3492b42c685 --- /dev/null +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.std.fixed @@ -0,0 +1,22 @@ +//@ edition:2018 +// +// This is a regression test for #83564. +// For some reason, Rust 2018 or higher is required to reproduce the bug. +//@ run-rustfix +//@ revisions: no_std std +//@ [no_std]compile-flags: --cfg=no_std -C panic=abort +#![cfg_attr(no_std, no_std)] + +use std::num::NonZero; + +fn main() { + //~^ HELP consider importing this struct + let _x = NonZero::new(5u32).unwrap(); + //~^ ERROR failed to resolve: use of undeclared type `NonZero` +} + +#[allow(dead_code)] +#[cfg_attr(no_std, panic_handler)] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.std.stderr b/tests/ui/suggestions/core-std-import-order-issue-83564.std.stderr new file mode 100644 index 00000000000..ebfe197b45d --- /dev/null +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.std.stderr @@ -0,0 +1,14 @@ +error[E0433]: failed to resolve: use of undeclared type `NonZero` + --> $DIR/core-std-import-order-issue-83564.rs:12:14 + | +LL | let _x = NonZero::new(5u32).unwrap(); + | ^^^^^^^ use of undeclared type `NonZero` + | +help: consider importing this struct + | +LL + use std::num::NonZero; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr b/tests/ui/suggestions/core-std-import-order-issue-83564.stderr deleted file mode 100644 index 8665cc6d87c..00000000000 --- a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0433]: failed to resolve: use of undeclared type `NonZero` - --> $DIR/core-std-import-order-issue-83564.rs:8:14 - | -LL | let _x = NonZero::new(5u32).unwrap(); - | ^^^^^^^ use of undeclared type `NonZero` - | -help: consider importing one of these items - | -LL + use core::num::NonZero; - | -LL + use std::num::NonZero; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/suggestions/crate-or-module-typo.stderr b/tests/ui/suggestions/crate-or-module-typo.stderr index 457d7790646..084d0408a8e 100644 --- a/tests/ui/suggestions/crate-or-module-typo.stderr +++ b/tests/ui/suggestions/crate-or-module-typo.stderr @@ -30,9 +30,7 @@ help: there is a crate or module with a similar name | LL | bar: std::cell::Cell | ~~~ -help: consider importing one of these items - | -LL + use core::cell; +help: consider importing this module | LL + use std::cell; | diff --git a/tests/ui/suggestions/suggest-tryinto-edition-change.rs b/tests/ui/suggestions/suggest-tryinto-edition-change.rs index 37321774874..f45670ae7c1 100644 --- a/tests/ui/suggestions/suggest-tryinto-edition-change.rs +++ b/tests/ui/suggestions/suggest-tryinto-edition-change.rs @@ -1,5 +1,5 @@ // Make sure that trying to access `TryInto`, `TryFrom`, `FromIterator` in pre-2021 mentions -// Edition 2021 change +// Edition 2021 change. //@ edition:2018 fn test() { @@ -11,19 +11,16 @@ fn test() { //~^ ERROR failed to resolve: use of undeclared type //~| NOTE use of undeclared type //~| NOTE 'std::convert::TryFrom' is included in the prelude starting in Edition 2021 - //~| NOTE 'core::convert::TryFrom' is included in the prelude starting in Edition 2021 let _i: i16 = TryInto::try_into(0_i32).unwrap(); //~^ ERROR failed to resolve: use of undeclared type //~| NOTE use of undeclared type //~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021 - //~| NOTE 'core::convert::TryInto' is included in the prelude starting in Edition 2021 let _v: Vec<_> = FromIterator::from_iter(&[1]); //~^ ERROR failed to resolve: use of undeclared type //~| NOTE use of undeclared type //~| NOTE 'std::iter::FromIterator' is included in the prelude starting in Edition 2021 - //~| NOTE 'core::iter::FromIterator' is included in the prelude starting in Edition 2021 } fn main() { diff --git a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr index db7c40101cd..5be55f75cd1 100644 --- a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr +++ b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr @@ -4,45 +4,36 @@ error[E0433]: failed to resolve: use of undeclared type `TryFrom` LL | let _i: i16 = TryFrom::try_from(0_i32).unwrap(); | ^^^^^^^ use of undeclared type `TryFrom` | - = note: 'core::convert::TryFrom' is included in the prelude starting in Edition 2021 = note: 'std::convert::TryFrom' is included in the prelude starting in Edition 2021 -help: consider importing one of these items - | -LL + use core::convert::TryFrom; +help: consider importing this trait | LL + use std::convert::TryFrom; | error[E0433]: failed to resolve: use of undeclared type `TryInto` - --> $DIR/suggest-tryinto-edition-change.rs:16:19 + --> $DIR/suggest-tryinto-edition-change.rs:15:19 | LL | let _i: i16 = TryInto::try_into(0_i32).unwrap(); | ^^^^^^^ use of undeclared type `TryInto` | - = note: 'core::convert::TryInto' is included in the prelude starting in Edition 2021 = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021 -help: consider importing one of these items - | -LL + use core::convert::TryInto; +help: consider importing this trait | LL + use std::convert::TryInto; | error[E0433]: failed to resolve: use of undeclared type `FromIterator` - --> $DIR/suggest-tryinto-edition-change.rs:22:22 + --> $DIR/suggest-tryinto-edition-change.rs:20:22 | LL | let _v: Vec<_> = FromIterator::from_iter(&[1]); | ^^^^^^^^^^^^ use of undeclared type `FromIterator` | - = note: 'core::iter::FromIterator' is included in the prelude starting in Edition 2021 = note: 'std::iter::FromIterator' is included in the prelude starting in Edition 2021 help: a trait with a similar name exists | LL | let _v: Vec<_> = IntoIterator::from_iter(&[1]); | ~~~~~~~~~~~~ -help: consider importing one of these items - | -LL + use core::iter::FromIterator; +help: consider importing this trait | LL + use std::iter::FromIterator; | -- cgit 1.4.1-3-g733a5 From 9e466d33613105b678fcb461df01b6dbc7cb179e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 14 Jun 2024 00:49:05 +0200 Subject: Remove failing GUI test to stop blocking CI until it is fixed --- tests/rustdoc-gui/help-page.goml | 69 ---------------------------------------- 1 file changed, 69 deletions(-) delete mode 100644 tests/rustdoc-gui/help-page.goml diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml deleted file mode 100644 index 09d33af139c..00000000000 --- a/tests/rustdoc-gui/help-page.goml +++ /dev/null @@ -1,69 +0,0 @@ -// This test ensures that opening the help page in its own tab works. -include: "utils.goml" -go-to: "file://" + |DOC_PATH| + "/help.html" -set-window-size: (1000, 1000) // Try desktop size first. -wait-for: "#help" -assert-css: ("#help", {"display": "block"}) -assert-css: ("#help dd", {"font-size": "16px"}) -click: "#help-button > a" -assert-css: ("#help", {"display": "block"}) -compare-elements-property: (".sub", "#help", ["offsetWidth"]) -compare-elements-position: (".sub", "#help", ["x"]) -set-window-size: (500, 1000) // Try mobile next. -assert-css: ("#help", {"display": "block"}) -compare-elements-property: (".sub", "#help", ["offsetWidth"]) -compare-elements-position: (".sub", "#help", ["x"]) - -// Checking the color of the elements of the help menu. -show-text: true -define-function: ( - "check-colors", - [theme, color, background, box_shadow], - block { - call-function: ("switch-theme", {"theme": |theme|}) - assert-css: ("#help kbd", { - "color": |color|, - "background-color": |background|, - "box-shadow": |box_shadow| + " 0px -1px 0px 0px inset", - }, ALL) - }, -) - -call-function: ("check-colors", { - "theme": "ayu", - "color": "#c5c5c5", - "background": "#314559", - "box_shadow": "#5c6773", -}) -call-function: ("check-colors", { - "theme": "dark", - "color": "#000", - "background": "#fafbfc", - "box_shadow": "#c6cbd1", -}) -call-function: ("check-colors", { - "theme": "light", - "color": "#000", - "background": "#fafbfc", - "box_shadow": "#c6cbd1", -}) - -// This test ensures that opening the help popover without switching pages works. -go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -set-window-size: (1000, 1000) // Only supported on desktop. -assert-false: "#help" -click: "#help-button > a" -assert-css: ("#help", {"display": "block"}) -assert-css: ("#help dd", {"font-size": "16px"}) -click: "#help-button > a" -assert-css: ("#help", {"display": "none"}) -compare-elements-property-false: (".sub", "#help", ["offsetWidth"]) -compare-elements-position-false: (".sub", "#help", ["x"]) - -// This test ensures that the "the rustdoc book" anchor link within the help popover works. -go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -set-window-size: (1000, 1000) // Popover only appears when the screen width is >700px. -assert-false: "#help" -click: "#help-button > a" -click: "//*[@id='help']//a[text()='the rustdoc book']" -wait-for-document-property: ({"URL": "https://doc.rust-lang.org/"}, STARTS_WITH) -- cgit 1.4.1-3-g733a5 From efbfcdd220a9f7ccdee235e0839e1848a554c4a5 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 14 Jun 2024 00:18:21 +0000 Subject: Fill out missing Windows support information --- src/doc/rustc/src/platform-support.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index c672cff7452..e55bb3bd155 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -259,7 +259,7 @@ target | std | host | notes [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD `aarch64-unknown-redox` | ? | | ARM64 Redox OS -`aarch64-uwp-windows-msvc` | ? | | +`aarch64-uwp-windows-msvc` | ✓ | | `aarch64-wrs-vxworks` | ? | | `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI) `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) @@ -300,8 +300,8 @@ target | std | host | notes [`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd [^x86_32-floats-return-ABI] [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2 [^x86_32-floats-return-ABI] [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD [^x86_32-floats-return-ABI] -`i686-uwp-windows-gnu` | ? | | [^x86_32-floats-return-ABI] -`i686-uwp-windows-msvc` | ? | | [^x86_32-floats-return-ABI] +`i686-uwp-windows-gnu` | ✓ | | [^x86_32-floats-return-ABI] +`i686-uwp-windows-msvc` | ✓ | | [^x86_32-floats-return-ABI] [`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] `i686-wrs-vxworks` | ? | | [^x86_32-floats-return-ABI] [`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | ? | | LoongArch64 Linux (LP64D ABI) with musl 1.2.3 @@ -362,7 +362,7 @@ target | std | host | notes [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64 [`thumbv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * | | Thumb-mode Bare Armv4T [`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Thumb-mode Bare Armv5TE -`thumbv7a-pc-windows-msvc` | ? | | +`thumbv7a-pc-windows-msvc` | ✓ | | `thumbv7a-uwp-windows-msvc` | ✓ | | `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode Armv7-A Linux with NEON, musl 1.2.3 [`wasm32-wasip2`](platform-support/wasm32-wasip2.md) | ✓ | | WebAssembly -- cgit 1.4.1-3-g733a5 From 4b82afb40c91fafdc9e4d84d4782573f848d84d9 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 13 Jun 2024 22:12:26 -0300 Subject: Add a new concat metavar expr --- compiler/rustc_expand/src/mbe/metavar_expr.rs | 93 ++++++++++++++++----- compiler/rustc_expand/src/mbe/quoted.rs | 25 ++++-- compiler/rustc_expand/src/mbe/transcribe.rs | 54 +++++++++++- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_span/src/symbol.rs | 1 + .../feature-gate-macro-metavar-expr-concat.rs | 9 ++ .../feature-gate-macro-metavar-expr-concat.stderr | 13 +++ .../allowed-operations.rs | 58 +++++++++++++ .../ui/macros/macro-metavar-expr-concat/hygiene.rs | 13 +++ .../macro-metavar-expr-concat/hygiene.stderr | 14 ++++ .../macro-metavar-expr-concat/raw-identifiers.rs | 81 ++++++++++++++++++ .../raw-identifiers.stderr | 95 ++++++++++++++++++++++ .../macro-metavar-expr-concat/syntax-errors.rs | 50 ++++++++++++ .../macro-metavar-expr-concat/syntax-errors.stderr | 68 ++++++++++++++++ .../rfc-3086-metavar-expr/syntax-errors.stderr | 4 +- 15 files changed, 551 insertions(+), 29 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.rs create mode 100644 tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.stderr create mode 100644 tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs create mode 100644 tests/ui/macros/macro-metavar-expr-concat/hygiene.rs create mode 100644 tests/ui/macros/macro-metavar-expr-concat/hygiene.stderr create mode 100644 tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs create mode 100644 tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr create mode 100644 tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs create mode 100644 tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index 128e9f48ff5..3295a91029e 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -8,9 +8,14 @@ use rustc_session::parse::ParseSess; use rustc_span::symbol::Ident; use rustc_span::Span; +pub(crate) const RAW_IDENT_ERR: &str = "`${concat(..)}` currently does not support raw identifiers"; + /// A meta-variable expression, for expansions based on properties of meta-variables. -#[derive(Debug, Clone, PartialEq, Encodable, Decodable)] +#[derive(Debug, PartialEq, Encodable, Decodable)] pub(crate) enum MetaVarExpr { + /// Unification of two or more identifiers. + Concat(Box<[MetaVarExprConcatElem]>), + /// The number of repetitions of an identifier. Count(Ident, usize), @@ -42,6 +47,31 @@ impl MetaVarExpr { check_trailing_token(&mut tts, psess)?; let mut iter = args.trees(); let rslt = match ident.as_str() { + "concat" => { + let mut result = Vec::new(); + loop { + let is_var = try_eat_dollar(&mut iter); + let element_ident = parse_ident(&mut iter, psess, outer_span)?; + let element = if is_var { + MetaVarExprConcatElem::Var(element_ident) + } else { + MetaVarExprConcatElem::Ident(element_ident) + }; + result.push(element); + if iter.look_ahead(0).is_none() { + break; + } + if !try_eat_comma(&mut iter) { + return Err(psess.dcx.struct_span_err(outer_span, "expected comma")); + } + } + if result.len() < 2 { + return Err(psess + .dcx + .struct_span_err(ident.span, "`concat` must have at least two elements")); + } + MetaVarExpr::Concat(result.into()) + } "count" => parse_count(&mut iter, psess, ident.span)?, "ignore" => { eat_dollar(&mut iter, psess, ident.span)?; @@ -68,11 +98,21 @@ impl MetaVarExpr { pub(crate) fn ident(&self) -> Option { match *self { MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident), - MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None, + MetaVarExpr::Concat { .. } | MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None, } } } +#[derive(Debug, Decodable, Encodable, PartialEq)] +pub(crate) enum MetaVarExprConcatElem { + /// There is NO preceding dollar sign, which means that this identifier should be interpreted + /// as a literal. + Ident(Ident), + /// There is a preceding dollar sign, which means that this identifier should be expanded + /// and interpreted as a variable. + Var(Ident), +} + // Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}` fn check_trailing_token<'psess>( iter: &mut RefTokenTreeCursor<'_>, @@ -138,26 +178,30 @@ fn parse_depth<'psess>( fn parse_ident<'psess>( iter: &mut RefTokenTreeCursor<'_>, psess: &'psess ParseSess, - span: Span, + fallback_span: Span, ) -> PResult<'psess, Ident> { - if let Some(tt) = iter.next() - && let TokenTree::Token(token, _) = tt - { - if let Some((elem, IdentIsRaw::No)) = token.ident() { - return Ok(elem); + let Some(tt) = iter.next() else { + return Err(psess.dcx.struct_span_err(fallback_span, "expected identifier")); + }; + let TokenTree::Token(token, _) = tt else { + return Err(psess.dcx.struct_span_err(tt.span(), "expected identifier")); + }; + if let Some((elem, is_raw)) = token.ident() { + if let IdentIsRaw::Yes = is_raw { + return Err(psess.dcx.struct_span_err(elem.span, RAW_IDENT_ERR)); } - let token_str = pprust::token_to_string(token); - let mut err = - psess.dcx.struct_span_err(span, format!("expected identifier, found `{}`", &token_str)); - err.span_suggestion( - token.span, - format!("try removing `{}`", &token_str), - "", - Applicability::MaybeIncorrect, - ); - return Err(err); + return Ok(elem); } - Err(psess.dcx.struct_span_err(span, "expected identifier")) + let token_str = pprust::token_to_string(token); + let mut err = + psess.dcx.struct_span_err(token.span, format!("expected identifier, found `{token_str}`")); + err.span_suggestion( + token.span, + format!("try removing `{token_str}`"), + "", + Applicability::MaybeIncorrect, + ); + Err(err) } /// Tries to move the iterator forward returning `true` if there is a comma. If not, then the @@ -170,6 +214,17 @@ fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool { false } +/// Tries to move the iterator forward returning `true` if there is a dollar sign. If not, then the +/// iterator is not modified and the result is `false`. +fn try_eat_dollar(iter: &mut RefTokenTreeCursor<'_>) -> bool { + if let Some(TokenTree::Token(token::Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0) + { + let _ = iter.next(); + return true; + } + false +} + /// Expects that the next item is a dollar sign. fn eat_dollar<'psess>( iter: &mut RefTokenTreeCursor<'_>, diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 8ad7cb15c92..74f78c0ef78 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -155,6 +155,13 @@ fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &Session, sp } } +fn maybe_emit_macro_metavar_expr_concat_feature(features: &Features, sess: &Session, span: Span) { + if !features.macro_metavar_expr_concat { + let msg = "the `concat` meta-variable expression is unstable"; + feature_err(sess, sym::macro_metavar_expr_concat, span, msg).emit(); + } +} + /// Takes a `tokenstream::TokenTree` and returns a `self::TokenTree`. Specifically, this takes a /// generic `TokenTree`, such as is used in the rest of the compiler, and returns a `TokenTree` /// for use in parsing a macro. @@ -217,11 +224,19 @@ fn parse_tree<'a>( return TokenTree::token(token::Dollar, dollar_span); } Ok(elem) => { - maybe_emit_macro_metavar_expr_feature( - features, - sess, - delim_span.entire(), - ); + if let MetaVarExpr::Concat(_) = elem { + maybe_emit_macro_metavar_expr_concat_feature( + features, + sess, + delim_span.entire(), + ); + } else { + maybe_emit_macro_metavar_expr_feature( + features, + sess, + delim_span.entire(), + ); + } return TokenTree::MetaVarExpr(delim_span, elem); } } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 25e961d6009..445255e933d 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -3,18 +3,19 @@ use crate::errors::{ NoSyntaxVarsExprRepeat, VarStillRepeating, }; use crate::mbe::macro_parser::{NamedMatch, NamedMatch::*}; +use crate::mbe::metavar_expr::{MetaVarExprConcatElem, RAW_IDENT_ERR}; use crate::mbe::{self, KleeneOp, MetaVarExpr}; use rustc_ast::mut_visit::{self, MutVisitor}; +use rustc_ast::token::IdentIsRaw; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, Diag, DiagCtxt, PResult}; use rustc_parse::parser::ParseNtResult; +use rustc_session::parse::ParseSess; use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent}; -use rustc_span::{with_metavar_spans, Span, SyntaxContext}; - -use rustc_session::parse::ParseSess; +use rustc_span::{with_metavar_spans, Span, Symbol, SyntaxContext}; use smallvec::{smallvec, SmallVec}; use std::mem; @@ -675,6 +676,23 @@ fn transcribe_metavar_expr<'a>( span }; match *expr { + MetaVarExpr::Concat(ref elements) => { + let mut concatenated = String::new(); + for element in elements.into_iter() { + let string = match element { + MetaVarExprConcatElem::Ident(ident) => ident.to_string(), + MetaVarExprConcatElem::Var(ident) => extract_ident(dcx, *ident, interp)?, + }; + concatenated.push_str(&string); + } + // The current implementation marks the span as coming from the macro regardless of + // contexts of the concatenated identifiers but this behavior may change in the + // future. + result.push(TokenTree::Token( + Token::from_ast_ident(Ident::new(Symbol::intern(&concatenated), visited_span())), + Spacing::Alone, + )); + } MetaVarExpr::Count(original_ident, depth) => { let matched = matched_from_ident(dcx, original_ident, interp)?; let count = count_repetitions(dcx, depth, matched, repeats, sp)?; @@ -709,3 +727,33 @@ fn transcribe_metavar_expr<'a>( } Ok(()) } + +/// Extracts an identifier that can be originated from a `$var:ident` variable or from a token tree. +fn extract_ident<'a>( + dcx: &'a DiagCtxt, + ident: Ident, + interp: &FxHashMap, +) -> PResult<'a, String> { + if let NamedMatch::MatchedSingle(pnr) = matched_from_ident(dcx, ident, interp)? { + if let ParseNtResult::Ident(nt_ident, is_raw) = pnr { + if let IdentIsRaw::Yes = is_raw { + return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR)); + } + return Ok(nt_ident.to_string()); + } + if let ParseNtResult::Tt(TokenTree::Token( + Token { kind: TokenKind::Ident(token_ident, is_raw), .. }, + _, + )) = pnr + { + if let IdentIsRaw::Yes = is_raw { + return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR)); + } + return Ok(token_ident.to_string()); + } + } + Err(dcx.struct_span_err( + ident.span, + "`${concat(..)}` currently only accepts identifiers or meta-variables as parameters", + )) +} diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 2410019868a..ebe6aff8d13 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -516,6 +516,8 @@ declare_features! ( (unstable, lint_reasons, "1.31.0", Some(54503)), /// Give access to additional metadata about declarative macro meta-variables. (unstable, macro_metavar_expr, "1.61.0", Some(83527)), + /// Provides a way to concatenate identifiers using metavariable expressions. + (unstable, macro_metavar_expr_concat, "CURRENT_RUSTC_VERSION", Some(124225)), /// Allows `#[marker]` on certain traits allowing overlapping implementations. (unstable, marker_trait_attr, "1.30.0", Some(29864)), /// Allows exhaustive pattern matching on types that contain uninhabited types in cases that are diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e245dfb9f5d..bc1c1eca942 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1116,6 +1116,7 @@ symbols! { macro_lifetime_matcher, macro_literal_matcher, macro_metavar_expr, + macro_metavar_expr_concat, macro_reexport, macro_use, macro_vis_matcher, diff --git a/tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.rs b/tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.rs new file mode 100644 index 00000000000..e700999ae4b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.rs @@ -0,0 +1,9 @@ +macro_rules! join { + ($lhs:ident, $rhs:ident) => { + let ${concat($lhs, $rhs)}: () = (); + //~^ ERROR the `concat` meta-variable expression is unstable + }; +} + +fn main() { +} diff --git a/tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.stderr b/tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.stderr new file mode 100644 index 00000000000..5b2589d8c89 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.stderr @@ -0,0 +1,13 @@ +error[E0658]: the `concat` meta-variable expression is unstable + --> $DIR/feature-gate-macro-metavar-expr-concat.rs:3:14 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #124225 for more information + = help: add `#![feature(macro_metavar_expr_concat)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs b/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs new file mode 100644 index 00000000000..e44eeffb01b --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs @@ -0,0 +1,58 @@ +//@ run-pass + +#![allow(dead_code, non_camel_case_types, non_upper_case_globals)] +#![feature(macro_metavar_expr_concat)] + +macro_rules! create_things { + ($lhs:ident) => { + struct ${concat($lhs, _separated_idents_in_a_struct)} { + foo: i32, + ${concat($lhs, _separated_idents_in_a_field)}: i32, + } + + mod ${concat($lhs, _separated_idents_in_a_module)} { + pub const FOO: () = (); + } + + fn ${concat($lhs, _separated_idents_in_a_fn)}() {} + }; +} + +macro_rules! many_idents { + ($a:ident, $c:ident) => { + const ${concat($a, B, $c, D)}: i32 = 1; + }; +} + +macro_rules! valid_tts { + ($_0:tt, $_1:tt) => { + const ${concat($_0, $_1)}: i32 = 1; + } +} + +macro_rules! without_dollar_sign_is_an_ident { + ($ident:ident) => { + const ${concat(VAR, ident)}: i32 = 1; + const ${concat(VAR, $ident)}: i32 = 2; + }; +} + +fn main() { + create_things!(behold); + behold_separated_idents_in_a_fn(); + let _ = behold_separated_idents_in_a_module::FOO; + let _ = behold_separated_idents_in_a_struct { + foo: 1, + behold_separated_idents_in_a_field: 2, + }; + + many_idents!(A, C); + assert_eq!(ABCD, 1); + + valid_tts!(X, YZ); + assert_eq!(XYZ, 1); + + without_dollar_sign_is_an_ident!(_123); + assert_eq!(VARident, 1); + assert_eq!(VAR_123, 2); +} diff --git a/tests/ui/macros/macro-metavar-expr-concat/hygiene.rs b/tests/ui/macros/macro-metavar-expr-concat/hygiene.rs new file mode 100644 index 00000000000..24b0e36498a --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/hygiene.rs @@ -0,0 +1,13 @@ +#![feature(macro_metavar_expr_concat)] + +macro_rules! join { + ($lhs:ident, $rhs:ident) => { + ${concat($lhs, $rhs)} + //~^ ERROR cannot find value `abcdef` in this scope + }; +} + +fn main() { + let abcdef = 1; + let _another = join!(abc, def); +} diff --git a/tests/ui/macros/macro-metavar-expr-concat/hygiene.stderr b/tests/ui/macros/macro-metavar-expr-concat/hygiene.stderr new file mode 100644 index 00000000000..ef2326dce85 --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/hygiene.stderr @@ -0,0 +1,14 @@ +error[E0425]: cannot find value `abcdef` in this scope + --> $DIR/hygiene.rs:5:10 + | +LL | ${concat($lhs, $rhs)} + | ^^^^^^^^^^^^^^^^^^^^ not found in this scope +... +LL | let _another = join!(abc, def); + | --------------- in this macro invocation + | + = note: this error originates in the macro `join` (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 E0425`. diff --git a/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs new file mode 100644 index 00000000000..f72b9baca89 --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs @@ -0,0 +1,81 @@ +#![feature(macro_metavar_expr_concat)] + +macro_rules! idents_01 { + ($rhs:ident) => { + let ${concat(abc, $rhs)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +macro_rules! idents_10 { + ($lhs:ident) => { + let ${concat($lhs, abc)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +macro_rules! idents_11 { + ($lhs:ident, $rhs:ident) => { + let ${concat($lhs, $rhs)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + //~| ERROR `${concat(..)}` currently does not support raw identifiers + //~| ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +macro_rules! no_params { + () => { + let ${concat(r#abc, abc)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + //~| ERROR expected pattern, found `$` + + let ${concat(abc, r#abc)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + + let ${concat(r#abc, r#abc)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +macro_rules! tts_01 { + ($rhs:tt) => { + let ${concat(abc, $rhs)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +macro_rules! tts_10 { + ($lhs:tt) => { + let ${concat($lhs, abc)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +macro_rules! tts_11 { + ($lhs:tt, $rhs:tt) => { + let ${concat($lhs, $rhs)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + //~| ERROR `${concat(..)}` currently does not support raw identifiers + //~| ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +fn main() { + idents_01!(r#_c); + + idents_10!(r#_c); + + idents_11!(r#_c, d); + idents_11!(_e, r#f); + idents_11!(r#_g, r#h); + + tts_01!(r#_c); + + tts_10!(r#_c); + + tts_11!(r#_c, d); + tts_11!(_e, r#f); + tts_11!(r#_g, r#h); + + no_params!(); +} diff --git a/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr new file mode 100644 index 00000000000..dd525cf0801 --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr @@ -0,0 +1,95 @@ +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:28:22 + | +LL | let ${concat(r#abc, abc)}: () = (); + | ^^^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:32:27 + | +LL | let ${concat(abc, r#abc)}: () = (); + | ^^^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:35:22 + | +LL | let ${concat(r#abc, r#abc)}: () = (); + | ^^^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:5:28 + | +LL | let ${concat(abc, $rhs)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:12:23 + | +LL | let ${concat($lhs, abc)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:19:23 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:19:29 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:19:23 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:42:28 + | +LL | let ${concat(abc, $rhs)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:49:23 + | +LL | let ${concat($lhs, abc)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:56:23 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:56:29 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:56:23 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected pattern, found `$` + --> $DIR/raw-identifiers.rs:28:13 + | +LL | let ${concat(r#abc, abc)}: () = (); + | ^ expected pattern +... +LL | no_params!(); + | ------------ in this macro invocation + | + = note: this error originates in the macro `no_params` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 14 previous errors + diff --git a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs new file mode 100644 index 00000000000..bf47442ea76 --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs @@ -0,0 +1,50 @@ +#![feature(macro_metavar_expr_concat)] + +macro_rules! wrong_concat_declarations { + ($ex:expr) => { + ${concat()} + //~^ ERROR expected identifier + + ${concat(aaaa)} + //~^ ERROR `concat` must have at least two elements + + ${concat(aaaa,)} + //~^ ERROR expected identifier + + ${concat(aaaa, 1)} + //~^ ERROR expected identifier + + ${concat(_, aaaa)} + + ${concat(aaaa aaaa)} + //~^ ERROR expected comma + + ${concat($ex)} + //~^ ERROR `concat` must have at least two elements + + ${concat($ex, aaaa)} + //~^ ERROR `${concat(..)}` currently only accepts identifiers + + ${concat($ex, aaaa 123)} + //~^ ERROR expected comma + + ${concat($ex, aaaa,)} + //~^ ERROR expected identifier + + ${concat($ex, aaaa, 123)} + //~^ ERROR expected identifier + }; +} + +macro_rules! dollar_sign_without_referenced_ident { + ($ident:ident) => { + const ${concat(FOO, $foo)}: i32 = 2; + //~^ ERROR variable `foo` is not recognized in meta-variable expression + }; +} + +fn main() { + wrong_concat_declarations!(1); + + dollar_sign_without_referenced_ident!(VAR); +} diff --git a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr new file mode 100644 index 00000000000..b216a86d59a --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr @@ -0,0 +1,68 @@ +error: expected identifier + --> $DIR/syntax-errors.rs:5:10 + | +LL | ${concat()} + | ^^^^^^^^^^ + +error: `concat` must have at least two elements + --> $DIR/syntax-errors.rs:8:11 + | +LL | ${concat(aaaa)} + | ^^^^^^ + +error: expected identifier + --> $DIR/syntax-errors.rs:11:10 + | +LL | ${concat(aaaa,)} + | ^^^^^^^^^^^^^^^ + +error: expected identifier, found `1` + --> $DIR/syntax-errors.rs:14:24 + | +LL | ${concat(aaaa, 1)} + | ^ help: try removing `1` + +error: expected comma + --> $DIR/syntax-errors.rs:19:10 + | +LL | ${concat(aaaa aaaa)} + | ^^^^^^^^^^^^^^^^^^^ + +error: `concat` must have at least two elements + --> $DIR/syntax-errors.rs:22:11 + | +LL | ${concat($ex)} + | ^^^^^^ + +error: expected comma + --> $DIR/syntax-errors.rs:28:10 + | +LL | ${concat($ex, aaaa 123)} + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected identifier + --> $DIR/syntax-errors.rs:31:10 + | +LL | ${concat($ex, aaaa,)} + | ^^^^^^^^^^^^^^^^^^^^ + +error: expected identifier, found `123` + --> $DIR/syntax-errors.rs:34:29 + | +LL | ${concat($ex, aaaa, 123)} + | ^^^ help: try removing `123` + +error: `${concat(..)}` currently only accepts identifiers or meta-variables as parameters + --> $DIR/syntax-errors.rs:25:19 + | +LL | ${concat($ex, aaaa)} + | ^^ + +error: variable `foo` is not recognized in meta-variable expression + --> $DIR/syntax-errors.rs:41:30 + | +LL | const ${concat(FOO, $foo)}: i32 = 2; + | ^^^ + +error: aborting due to 11 previous errors + diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr index 3fa3839bae2..8e4ba192d79 100644 --- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr +++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr @@ -191,10 +191,10 @@ LL | ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } }; | ^^^^^^^^^^^^^^ help: supported expressions are count, ignore, index and len error: expected identifier - --> $DIR/syntax-errors.rs:118:31 + --> $DIR/syntax-errors.rs:118:33 | LL | ( $( $i:ident ),* ) => { ${ {} } }; - | ^^^^^^ + | ^^ error: `count` can not be placed inside the inner-most repetition --> $DIR/syntax-errors.rs:12:24 -- cgit 1.4.1-3-g733a5 From fdd90db5283467d4d4539b17367005af732ab5ba Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 21:42:46 -0400 Subject: Point out exactly what obligation will fail --- compiler/rustc_hir_typeck/messages.ftl | 1 + compiler/rustc_hir_typeck/src/errors.rs | 8 ++++++-- compiler/rustc_hir_typeck/src/fallback.rs | 12 ++++++++---- tests/ui/delegation/not-supported.stderr | 10 ++++++++++ tests/ui/editions/never-type-fallback-breaking.e2021.stderr | 10 ++++++++++ tests/ui/never_type/defaulted-never-note.nofallback.stderr | 5 +++++ tests/ui/never_type/dependency-on-fallback-to-unit.stderr | 10 ++++++++++ .../diverging-fallback-control-flow.nofallback.stderr | 10 ++++++++++ .../never_type/diverging-fallback-no-leak.nofallback.stderr | 5 +++++ ...diverging-fallback-unconstrained-return.nofallback.stderr | 5 +++++ tests/ui/never_type/fallback-closure-ret.nofallback.stderr | 5 +++++ tests/ui/never_type/impl_trait_fallback.stderr | 5 +++++ 12 files changed, 80 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 3ab319a037b..d6f3f4d640b 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -45,6 +45,7 @@ hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to ` hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private hir_typeck_dependency_on_unit_never_type_fallback = this function depends on never type fallback being `()` + .note = in edition 2024, the requirement `{$obligation}` will fail .help = specify the types explicitly hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty` diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 6dd34024fd1..24f039b8e90 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -7,7 +7,7 @@ use rustc_errors::{ SubdiagMessageOp, Subdiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{self, Ty}; use rustc_span::{ edition::{Edition, LATEST_STABLE_EDITION}, symbol::Ident, @@ -186,7 +186,11 @@ pub enum NeverTypeFallbackFlowingIntoUnsafe { #[derive(LintDiagnostic)] #[help] #[diag(hir_typeck_dependency_on_unit_never_type_fallback)] -pub struct DependencyOnUnitNeverTypeFallback {} +pub struct DependencyOnUnitNeverTypeFallback<'tcx> { + #[note] + pub obligation_span: Span, + pub obligation: ty::Predicate<'tcx>, +} #[derive(Subdiagnostic)] #[multipart_suggestion( diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index b7937f458b3..3cecbfd4275 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -488,7 +488,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let remaining_errors_if_fallback_to = |fallback| { self.probe(|_| { let obligations = self.fulfillment_cx.borrow().pending_obligations(); - let ocx = ObligationCtxt::new(&self.infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&self.infcx); ocx.register_obligations(obligations.iter().cloned()); for &diverging_vid in diverging_vids { @@ -506,14 +506,18 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // then this code will be broken by the never type fallback change.qba let unit_errors = remaining_errors_if_fallback_to(self.tcx.types.unit); if unit_errors.is_empty() - && let never_errors = remaining_errors_if_fallback_to(self.tcx.types.never) - && !never_errors.is_empty() + && let mut never_errors = remaining_errors_if_fallback_to(self.tcx.types.never) + && let [ref mut never_error, ..] = never_errors.as_mut_slice() { + self.adjust_fulfillment_error_for_expr_obligation(never_error); self.tcx.emit_node_span_lint( lint::builtin::DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, self.tcx.local_def_id_to_hir_id(self.body_id), self.tcx.def_span(self.body_id), - errors::DependencyOnUnitNeverTypeFallback {}, + errors::DependencyOnUnitNeverTypeFallback { + obligation_span: never_error.obligation.cause.span, + obligation: never_error.obligation.predicate, + }, ) } } diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr index 339a8418b33..4ce01fd5d88 100644 --- a/tests/ui/delegation/not-supported.stderr +++ b/tests/ui/delegation/not-supported.stderr @@ -124,6 +124,11 @@ LL | fn opaque_ret() -> impl Trait { unimplemented!() } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #123748 = help: specify the types explicitly +note: in edition 2024, the requirement `!: opaque::Trait` will fail + --> $DIR/not-supported.rs:80:28 + | +LL | fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` @@ -154,6 +159,11 @@ LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #123748 = help: specify the types explicitly +note: in edition 2024, the requirement `!: opaque::Trait` will fail + --> $DIR/not-supported.rs:72:32 + | +LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^ error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` --> $DIR/not-supported.rs:90:24 diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr index 92c233a0d9c..134fd098b7e 100644 --- a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr +++ b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr @@ -7,6 +7,11 @@ LL | fn m() { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #123748 = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/never-type-fallback-breaking.rs:19:17 + | +LL | true => Default::default(), + | ^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default warning: this function depends on never type fallback being `()` @@ -18,6 +23,11 @@ LL | fn q() -> Option<()> { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #123748 = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/never-type-fallback-breaking.rs:34:5 + | +LL | deserialize()?; + | ^^^^^^^^^^^^^ warning: 2 warnings emitted diff --git a/tests/ui/never_type/defaulted-never-note.nofallback.stderr b/tests/ui/never_type/defaulted-never-note.nofallback.stderr index b69b8dda8f1..d88615186dd 100644 --- a/tests/ui/never_type/defaulted-never-note.nofallback.stderr +++ b/tests/ui/never_type/defaulted-never-note.nofallback.stderr @@ -7,6 +7,11 @@ LL | fn smeg() { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #123748 = help: specify the types explicitly +note: in edition 2024, the requirement `!: ImplementedForUnitButNotNever` will fail + --> $DIR/defaulted-never-note.rs:32:9 + | +LL | foo(_x); + | ^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default warning: 1 warning emitted diff --git a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr index 36c82b6d1bf..ec49137ba79 100644 --- a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr +++ b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr @@ -7,6 +7,11 @@ LL | fn def() { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #123748 = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/dependency-on-fallback-to-unit.rs:12:19 + | +LL | false => <_>::default(), + | ^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default warning: this function depends on never type fallback being `()` @@ -18,6 +23,11 @@ LL | fn question_mark() -> Result<(), ()> { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #123748 = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/dependency-on-fallback-to-unit.rs:22:5 + | +LL | deserialize()?; + | ^^^^^^^^^^^^^ warning: 2 warnings emitted diff --git a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr index 5fbdc04ed3b..2a3c5edc218 100644 --- a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr +++ b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr @@ -7,6 +7,11 @@ LL | fn assignment() { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #123748 = help: specify the types explicitly +note: in edition 2024, the requirement `!: UnitDefault` will fail + --> $DIR/diverging-fallback-control-flow.rs:36:13 + | +LL | x = UnitDefault::default(); + | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default warning: this function depends on never type fallback being `()` @@ -18,6 +23,11 @@ LL | fn assignment_rev() { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #123748 = help: specify the types explicitly +note: in edition 2024, the requirement `!: UnitDefault` will fail + --> $DIR/diverging-fallback-control-flow.rs:50:13 + | +LL | x = UnitDefault::default(); + | ^^^^^^^^^^^^^^^^^^^^^^ warning: 2 warnings emitted diff --git a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr index d11097323b3..11245cc7aab 100644 --- a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr +++ b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr @@ -7,6 +7,11 @@ LL | fn main() { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #123748 = help: specify the types explicitly +note: in edition 2024, the requirement `!: Test` will fail + --> $DIR/diverging-fallback-no-leak.rs:20:23 + | +LL | unconstrained_arg(return); + | ^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default warning: 1 warning emitted diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr index 750bcfb7f89..b485c94df4d 100644 --- a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr +++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr @@ -7,6 +7,11 @@ LL | fn main() { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #123748 = help: specify the types explicitly +note: in edition 2024, the requirement `!: UnitReturn` will fail + --> $DIR/diverging-fallback-unconstrained-return.rs:39:23 + | +LL | let _ = if true { unconstrained_return() } else { panic!() }; + | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default warning: 1 warning emitted diff --git a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr index 9f0b9f6daea..3fb5536dee7 100644 --- a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr +++ b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr @@ -7,6 +7,11 @@ LL | fn main() { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #123748 = help: specify the types explicitly +note: in edition 2024, the requirement `!: Bar` will fail + --> $DIR/fallback-closure-ret.rs:24:5 + | +LL | foo(|| panic!()); + | ^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default warning: 1 warning emitted diff --git a/tests/ui/never_type/impl_trait_fallback.stderr b/tests/ui/never_type/impl_trait_fallback.stderr index 87638940332..4496746e018 100644 --- a/tests/ui/never_type/impl_trait_fallback.stderr +++ b/tests/ui/never_type/impl_trait_fallback.stderr @@ -7,6 +7,11 @@ LL | fn should_ret_unit() -> impl T { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #123748 = help: specify the types explicitly +note: in edition 2024, the requirement `!: T` will fail + --> $DIR/impl_trait_fallback.rs:8:25 + | +LL | fn should_ret_unit() -> impl T { + | ^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default warning: 1 warning emitted -- cgit 1.4.1-3-g733a5 From 5330ccdb345b24be57f051c6659cd3b33a65fdca Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 16 Mar 2024 17:02:30 +1100 Subject: Use `-Zno-profiler-runtime` instead of `//@ needs-profiler-support` For PGO/coverage tests that don't need to build or run an actual artifact, we can use `-Zno-profiler-runtime` to run the test even when the profiler runtime is not available. --- tests/codegen/instrument-coverage/instrument-coverage-off.rs | 1 + tests/codegen/instrument-coverage/instrument-coverage.rs | 6 +++--- tests/codegen/instrument-coverage/testprog.rs | 2 +- tests/codegen/naked-fn/naked-nocoverage.rs | 2 +- tests/codegen/pgo-counter-bias.rs | 2 +- tests/codegen/pgo-instrumentation.rs | 2 +- tests/run-make/pgo-gen-no-imp-symbols/Makefile | 4 +--- tests/ui/instrument-coverage/coverage-options.rs | 3 +-- tests/ui/instrument-coverage/on-values.rs | 2 +- 9 files changed, 11 insertions(+), 13 deletions(-) diff --git a/tests/codegen/instrument-coverage/instrument-coverage-off.rs b/tests/codegen/instrument-coverage/instrument-coverage-off.rs index 616e3295e5b..e44d6c65874 100644 --- a/tests/codegen/instrument-coverage/instrument-coverage-off.rs +++ b/tests/codegen/instrument-coverage/instrument-coverage-off.rs @@ -1,5 +1,6 @@ // Test that `-Cinstrument-coverage=off` does not add coverage instrumentation to LLVM IR. +//@ compile-flags: -Zno-profiler-runtime //@ revisions: n no off false_ zero //@ [n] compile-flags: -Cinstrument-coverage=n //@ [no] compile-flags: -Cinstrument-coverage=no diff --git a/tests/codegen/instrument-coverage/instrument-coverage.rs b/tests/codegen/instrument-coverage/instrument-coverage.rs index 65fa437d250..23d23651c72 100644 --- a/tests/codegen/instrument-coverage/instrument-coverage.rs +++ b/tests/codegen/instrument-coverage/instrument-coverage.rs @@ -1,6 +1,6 @@ // Test that `-Cinstrument-coverage` creates expected __llvm_profile_filename symbol in LLVM IR. -//@ needs-profiler-support +//@ compile-flags: -Zno-profiler-runtime //@ revisions: default y yes on true_ all //@ [default] compile-flags: -Cinstrument-coverage //@ [y] compile-flags: -Cinstrument-coverage=y @@ -9,8 +9,8 @@ //@ [true_] compile-flags: -Cinstrument-coverage=true //@ [all] compile-flags: -Cinstrument-coverage=all -// CHECK: @__llvm_profile_filename = {{.*}}"default_%m_%p.profraw\00"{{.*}} -// CHECK: @__llvm_coverage_mapping +// CHECK-DAG: @__llvm_coverage_mapping +// CHECK-DAG: @__llvm_profile_filename = {{.*}}"default_%m_%p.profraw\00"{{.*}} #![crate_type = "lib"] diff --git a/tests/codegen/instrument-coverage/testprog.rs b/tests/codegen/instrument-coverage/testprog.rs index acc4f35d905..eea4d9cb3cf 100644 --- a/tests/codegen/instrument-coverage/testprog.rs +++ b/tests/codegen/instrument-coverage/testprog.rs @@ -1,5 +1,5 @@ //@ edition: 2021 -//@ needs-profiler-support +//@ compile-flags: -Zno-profiler-runtime //@ compile-flags: -Cinstrument-coverage -Copt-level=0 //@ revisions: LINUX DARWIN WINDOWS diff --git a/tests/codegen/naked-fn/naked-nocoverage.rs b/tests/codegen/naked-fn/naked-nocoverage.rs index e8d3b5834fa..d73c5b7fd26 100644 --- a/tests/codegen/naked-fn/naked-nocoverage.rs +++ b/tests/codegen/naked-fn/naked-nocoverage.rs @@ -2,7 +2,7 @@ // Regression test for issue #105170. // //@ needs-asm-support -//@ needs-profiler-support +//@ compile-flags: -Zno-profiler-runtime //@ compile-flags: -Cinstrument-coverage #![crate_type = "lib"] #![feature(naked_functions)] diff --git a/tests/codegen/pgo-counter-bias.rs b/tests/codegen/pgo-counter-bias.rs index 87d31073d5a..48e815dda04 100644 --- a/tests/codegen/pgo-counter-bias.rs +++ b/tests/codegen/pgo-counter-bias.rs @@ -2,7 +2,7 @@ //@ ignore-apple -runtime-counter-relocation not honored on Mach-O //@ compile-flags: -Cprofile-generate -Cllvm-args=-runtime-counter-relocation -Clto=fat -//@ needs-profiler-support +//@ compile-flags: -Zno-profiler-runtime //@ no-prefer-dynamic // CHECK: @__llvm_profile_counter_bias = {{.*}}global diff --git a/tests/codegen/pgo-instrumentation.rs b/tests/codegen/pgo-instrumentation.rs index b1906c145c6..a8f12ccce1c 100644 --- a/tests/codegen/pgo-instrumentation.rs +++ b/tests/codegen/pgo-instrumentation.rs @@ -1,6 +1,6 @@ // Test that `-Cprofile-generate` creates expected instrumentation artifacts in LLVM IR. -//@ needs-profiler-support +//@ compile-flags: -Zno-profiler-runtime //@ compile-flags: -Cprofile-generate -Ccodegen-units=1 // CHECK: @__llvm_profile_raw_version = diff --git a/tests/run-make/pgo-gen-no-imp-symbols/Makefile b/tests/run-make/pgo-gen-no-imp-symbols/Makefile index 7f72b11b611..d2baa145ba5 100644 --- a/tests/run-make/pgo-gen-no-imp-symbols/Makefile +++ b/tests/run-make/pgo-gen-no-imp-symbols/Makefile @@ -1,8 +1,6 @@ -# needs-profiler-support - include ../tools.mk -COMPILE_FLAGS=-O -Ccodegen-units=1 -Cprofile-generate="$(TMPDIR)" +COMPILE_FLAGS=-O -Ccodegen-units=1 -Cprofile-generate="$(TMPDIR)" -Zno-profiler-runtime all: $(RUSTC) $(COMPILE_FLAGS) --emit=llvm-ir test.rs diff --git a/tests/ui/instrument-coverage/coverage-options.rs b/tests/ui/instrument-coverage/coverage-options.rs index 8f523a5fd11..7615a0fb275 100644 --- a/tests/ui/instrument-coverage/coverage-options.rs +++ b/tests/ui/instrument-coverage/coverage-options.rs @@ -1,6 +1,5 @@ -//@ needs-profiler-support //@ revisions: block branch condition mcdc bad -//@ compile-flags -Cinstrument-coverage +//@ compile-flags -Cinstrument-coverage -Zno-profiler-runtime //@ [block] check-pass //@ [block] compile-flags: -Zcoverage-options=block diff --git a/tests/ui/instrument-coverage/on-values.rs b/tests/ui/instrument-coverage/on-values.rs index a6793b2c304..53b149fd39c 100644 --- a/tests/ui/instrument-coverage/on-values.rs +++ b/tests/ui/instrument-coverage/on-values.rs @@ -1,5 +1,5 @@ //@ check-pass -//@ needs-profiler-support +//@ compile-flags: -Zno-profiler-runtime //@ revisions: default y yes on true_ all //@ [default] compile-flags: -Cinstrument-coverage //@ [y] compile-flags: -Cinstrument-coverage=y -- cgit 1.4.1-3-g733a5 From 3f3b8bb1ca3fc4106fdbdc5106f3924db441a51a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 17 Mar 2024 12:06:00 +1100 Subject: Don't build a known-broken profiler runtime in `x86_64-mingw` --- src/ci/github-actions/jobs.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 010e1b8fd51..ce7ca8a6b4d 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -390,9 +390,7 @@ auto: - image: x86_64-mingw env: SCRIPT: make ci-mingw - RUST_CONFIGURE_ARGS: >- - --build=x86_64-pc-windows-gnu - --enable-profiler + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 -- cgit 1.4.1-3-g733a5 From 2646db92fe210df64f48a09d5eab3793f41dc9ce Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 17 Mar 2024 12:12:38 +1100 Subject: Remove `//@ ignore-windows-gnu` from tests that need the profiler The profiler runtime is no longer built in mingw test jobs, so these tests should naturally be skipped by `//@ needs-profiler-support`. --- src/tools/compiletest/src/header.rs | 3 --- tests/run-make/optimization-remarks-dir-pgo/Makefile | 4 ---- tests/run-make/pgo-branch-weights/rmake.rs | 4 ---- tests/run-make/pgo-gen-lto/Makefile | 4 ---- tests/run-make/pgo-gen/Makefile | 4 ---- tests/run-make/pgo-indirect-call-promotion/Makefile | 4 ---- tests/run-make/pgo-use/Makefile | 4 ---- tests/run-make/track-pgo-dep-info/Makefile | 1 - 8 files changed, 28 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index cc972223f6d..65436a8a440 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -1023,9 +1023,6 @@ fn iter_header( if mode == Mode::CoverageRun { let extra_directives: &[&str] = &[ "needs-profiler-support", - // FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works - // properly. Since we only have GCC on the CI ignore the test for now. - "ignore-windows-gnu", // FIXME(pietroalbini): this test currently does not work on cross-compiled // targets because remote-test is not capable of sending back the *.profraw // files generated by the LLVM instrumentation. diff --git a/tests/run-make/optimization-remarks-dir-pgo/Makefile b/tests/run-make/optimization-remarks-dir-pgo/Makefile index 3bc3d7d1428..57ffd6e70f0 100644 --- a/tests/run-make/optimization-remarks-dir-pgo/Makefile +++ b/tests/run-make/optimization-remarks-dir-pgo/Makefile @@ -1,10 +1,6 @@ # needs-profiler-support -# ignore-windows-gnu # ignore-cross-compile -# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works -# properly. Since we only have GCC on the CI ignore the test for now. - include ../tools.mk PROFILE_DIR=$(TMPDIR)/profiles diff --git a/tests/run-make/pgo-branch-weights/rmake.rs b/tests/run-make/pgo-branch-weights/rmake.rs index 55f6e7e56c5..d3cb79c39af 100644 --- a/tests/run-make/pgo-branch-weights/rmake.rs +++ b/tests/run-make/pgo-branch-weights/rmake.rs @@ -10,10 +10,6 @@ //@ needs-profiler-support //@ ignore-cross-compile -// FIXME(Oneirical): This test has problems generating profdata on mingw. -// For more information, see https://github.com/rust-lang/rust/pull/122613 -//@ ignore-windows-gnu - use run_make_support::{fs_wrapper, llvm_filecheck, llvm_profdata, run_with_args, rustc}; use std::path::Path; diff --git a/tests/run-make/pgo-gen-lto/Makefile b/tests/run-make/pgo-gen-lto/Makefile index 8b647846af3..54164c99522 100644 --- a/tests/run-make/pgo-gen-lto/Makefile +++ b/tests/run-make/pgo-gen-lto/Makefile @@ -1,10 +1,6 @@ # needs-profiler-support -# ignore-windows-gnu # ignore-cross-compile -# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works -# properly. Since we only have GCC on the CI ignore the test for now. - include ../tools.mk COMPILE_FLAGS=-Copt-level=3 -Clto=fat -Cprofile-generate="$(TMPDIR)" diff --git a/tests/run-make/pgo-gen/Makefile b/tests/run-make/pgo-gen/Makefile index bf32cfdb802..c1d456986fb 100644 --- a/tests/run-make/pgo-gen/Makefile +++ b/tests/run-make/pgo-gen/Makefile @@ -1,10 +1,6 @@ # needs-profiler-support -# ignore-windows-gnu # ignore-cross-compile -# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works -# properly. Since we only have GCC on the CI ignore the test for now. - include ../tools.mk COMPILE_FLAGS=-g -Cprofile-generate="$(TMPDIR)" diff --git a/tests/run-make/pgo-indirect-call-promotion/Makefile b/tests/run-make/pgo-indirect-call-promotion/Makefile index 542eb244d39..8d1e69c4aba 100644 --- a/tests/run-make/pgo-indirect-call-promotion/Makefile +++ b/tests/run-make/pgo-indirect-call-promotion/Makefile @@ -1,10 +1,6 @@ # needs-profiler-support -# ignore-windows-gnu # ignore-cross-compile -# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works -# properly. Since we only have GCC on the CI ignore the test for now. - include ../tools.mk all: diff --git a/tests/run-make/pgo-use/Makefile b/tests/run-make/pgo-use/Makefile index 9f440118dae..92098a4019c 100644 --- a/tests/run-make/pgo-use/Makefile +++ b/tests/run-make/pgo-use/Makefile @@ -1,10 +1,6 @@ # needs-profiler-support -# ignore-windows-gnu # ignore-cross-compile -# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works -# properly. Since we only have GCC on the CI ignore the test for now. - include ../tools.mk # This test makes sure that PGO profiling data leads to cold functions being diff --git a/tests/run-make/track-pgo-dep-info/Makefile b/tests/run-make/track-pgo-dep-info/Makefile index 6c7f67d0f0a..3afe3662fa7 100644 --- a/tests/run-make/track-pgo-dep-info/Makefile +++ b/tests/run-make/track-pgo-dep-info/Makefile @@ -1,5 +1,4 @@ # needs-profiler-support -# ignore-windows-gnu include ../tools.mk -- cgit 1.4.1-3-g733a5 From 186d94dc6be108d7e507e4a5129375335149cd23 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 17 Mar 2024 12:18:53 +1100 Subject: Remove broken/untested `--enable-profiler` from mingw dist builds --- src/ci/github-actions/jobs.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index ce7ca8a6b4d..4366a92fbcd 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -438,7 +438,6 @@ auto: RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-gnu --enable-full-tools - --enable-profiler # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 @@ -452,7 +451,6 @@ auto: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-gnu --enable-full-tools - --enable-profiler # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 -- cgit 1.4.1-3-g733a5 From a6907100de23e51ba979ead543fcd5975d62d248 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Jun 2024 21:01:00 +0200 Subject: const validation: fix ICE on dangling ZST reference --- compiler/rustc_const_eval/src/interpret/validity.rs | 16 +++++++++++----- tests/ui/consts/dangling-alloc-id-ice.rs | 2 +- tests/ui/consts/dangling-alloc-id-ice.stderr | 10 ++++++++-- tests/ui/consts/dangling-zst-ice-issue-126393.rs | 15 +++++++++++++++ tests/ui/consts/dangling-zst-ice-issue-126393.stderr | 14 ++++++++++++++ 5 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 tests/ui/consts/dangling-zst-ice-issue-126393.rs create mode 100644 tests/ui/consts/dangling-zst-ice-issue-126393.stderr diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 6f75bc2af4e..ca8b9884933 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -29,7 +29,7 @@ use rustc_target::abi::{ use std::hash::Hash; use super::{ - err_ub, format_interp_error, machine::AllocMap, throw_ub, AllocId, CheckInAllocMsg, + err_ub, format_interp_error, machine::AllocMap, throw_ub, AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Pointer, Projectable, Scalar, ValueVisitor, }; @@ -413,8 +413,6 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds { ptr_kind }, - // This cannot happen during const-eval (because interning already detects - // dangling pointers), but it can happen in Miri. Ub(PointerUseAfterFree(..)) => DanglingPtrUseAfterFree { ptr_kind, }, @@ -493,9 +491,17 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } } - // Mutability check. + // Dangling and Mutability check. + let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id); + if alloc_kind == AllocKind::Dead { + // This can happen for zero-sized references. We can't have *any* references to non-existing + // allocations though, interning rejects them all as the rest of rustc isn't happy with them... + // so we throw an error, even though this isn't really UB. + // A potential future alternative would be to resurrect this as a zero-sized allocation + // (which codegen will then compile to an aligned dummy pointer anyway). + throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind }); + } // If this allocation has size zero, there is no actual mutability here. - let (size, _align, _alloc_kind) = self.ecx.get_alloc_info(alloc_id); if size != Size::ZERO { let alloc_actual_mutbl = mutability(self.ecx, alloc_id); // Mutable pointer to immutable memory is no good. diff --git a/tests/ui/consts/dangling-alloc-id-ice.rs b/tests/ui/consts/dangling-alloc-id-ice.rs index 6b07b8b3cc8..76d6f33baf3 100644 --- a/tests/ui/consts/dangling-alloc-id-ice.rs +++ b/tests/ui/consts/dangling-alloc-id-ice.rs @@ -10,7 +10,7 @@ union Foo<'a> { } const FOO: &() = { - //~^ ERROR encountered dangling pointer + //~^ ERROR it is undefined behavior to use this value let y = (); unsafe { Foo { y: &y }.long_live_the_unit } }; diff --git a/tests/ui/consts/dangling-alloc-id-ice.stderr b/tests/ui/consts/dangling-alloc-id-ice.stderr index de31acf9fa4..881c0b162ed 100644 --- a/tests/ui/consts/dangling-alloc-id-ice.stderr +++ b/tests/ui/consts/dangling-alloc-id-ice.stderr @@ -1,8 +1,14 @@ -error: encountered dangling pointer in final value of constant +error[E0080]: it is undefined behavior to use this value --> $DIR/dangling-alloc-id-ice.rs:12:1 | LL | const FOO: &() = { - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free) + | + = 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. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/dangling-zst-ice-issue-126393.rs b/tests/ui/consts/dangling-zst-ice-issue-126393.rs new file mode 100644 index 00000000000..917aa0572fc --- /dev/null +++ b/tests/ui/consts/dangling-zst-ice-issue-126393.rs @@ -0,0 +1,15 @@ +// Strip out raw byte dumps to make comparison platform-independent: +//@ normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" +//@ normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" +//@ normalize-stderr-test "HEX_DUMP\s*\n\s*HEX_DUMP" -> "HEX_DUMP" + +pub struct Wrapper; +pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { +//~^ERROR: it is undefined behavior to use this value + std::mem::transmute(&{ + let y = 42; + y + }) +}; + +fn main() {} diff --git a/tests/ui/consts/dangling-zst-ice-issue-126393.stderr b/tests/ui/consts/dangling-zst-ice-issue-126393.stderr new file mode 100644 index 00000000000..d32b427f14e --- /dev/null +++ b/tests/ui/consts/dangling-zst-ice-issue-126393.stderr @@ -0,0 +1,14 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/dangling-zst-ice-issue-126393.rs:7:1 + | +LL | pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free) + | + = 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. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. -- cgit 1.4.1-3-g733a5 From 5c8bb678d07da4fe64e0595e7ace7b993fc0f000 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 14 Jun 2024 09:40:44 +0000 Subject: Use a consistent way to filter out bounds instead of splitting it into three places --- .../src/traits/select/candidate_assembly.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) 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 6db5fa0e4e5..cb5a9da2caa 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -239,24 +239,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(()); } - let all_bounds = stack + let bounds = stack .obligation .param_env .caller_bounds() .iter() .filter(|p| !p.references_error()) - .filter_map(|p| p.as_trait_clause()); - - // Micro-optimization: filter out predicates relating to different traits. - let matching_bounds = - all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); + .filter_map(|p| p.as_trait_clause()) + // Micro-optimization: filter out predicates relating to different traits. + .filter(|p| p.def_id() == stack.obligation.predicate.def_id()) + .filter(|p| p.polarity() == stack.obligation.predicate.polarity()); // Keep only those bounds which may apply, and propagate overflow if it occurs. - for bound in matching_bounds { - if bound.skip_binder().polarity != stack.obligation.predicate.skip_binder().polarity { - continue; - } - + for bound in bounds { // FIXME(oli-obk): it is suspicious that we are dropping the constness and // polarity here. let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?; -- cgit 1.4.1-3-g733a5 From 669a40006bf3494b0d320fb77bf39cc19a6c5bc4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 14 Jun 2024 11:28:18 +0200 Subject: MIR Shl/Shr: the offset can be computed with rem_euclid --- compiler/rustc_const_eval/src/interpret/operator.rs | 19 +++++++------------ compiler/rustc_middle/src/mir/syntax.rs | 6 ++++-- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index a6eef9f5662..4d0f35618ef 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -112,25 +112,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Shift ops can have an RHS with a different numeric type. if matches!(bin_op, Shl | ShlUnchecked | Shr | ShrUnchecked) { - let size = left.layout.size.bits(); + let l_bits = left.layout.size.bits(); // Compute the equivalent shift modulo `size` that is in the range `0..size`. (This is // the one MIR operator that does *not* directly map to a single LLVM operation.) let (shift_amount, overflow) = if right.layout.abi.is_signed() { let shift_amount = r_signed(); - let overflow = shift_amount < 0 || shift_amount >= i128::from(size); - // Deliberately wrapping `as` casts: shift_amount *can* be negative, but the result - // of the `as` will be equal modulo `size` (since it is a power of two). - let masked_amount = (shift_amount as u128) % u128::from(size); - assert_eq!(overflow, shift_amount != i128::try_from(masked_amount).unwrap()); - (masked_amount, overflow) + let rem = shift_amount.rem_euclid(l_bits.into()); + // `rem` is guaranteed positive, so the `unwrap` cannot fail + (u128::try_from(rem).unwrap(), rem != shift_amount) } else { let shift_amount = r_unsigned(); - let overflow = shift_amount >= u128::from(size); - let masked_amount = shift_amount % u128::from(size); - assert_eq!(overflow, shift_amount != masked_amount); - (masked_amount, overflow) + let rem = shift_amount.rem_euclid(l_bits.into()); + (rem, rem != shift_amount) }; - let shift_amount = u32::try_from(shift_amount).unwrap(); // we masked so this will always fit + let shift_amount = u32::try_from(shift_amount).unwrap(); // we brought this in the range `0..size` so this will always fit // Compute the shifted result. let result = if left.layout.abi.is_signed() { let l = l_signed(); diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index ebe77a1abfd..3edc5fe36cd 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1490,7 +1490,8 @@ pub enum BinOp { BitOr, /// The `<<` operator (shift left) /// - /// The offset is (uniquely) determined as follows: + /// The offset is given by `RHS.rem_euclid(LHS::BITS)`. + /// In other words, it is (uniquely) determined as follows: /// - it is "equal modulo LHS::BITS" to the RHS /// - it is in the range `0..LHS::BITS` Shl, @@ -1498,7 +1499,8 @@ pub enum BinOp { ShlUnchecked, /// The `>>` operator (shift right) /// - /// The offset is (uniquely) determined as follows: + /// The offset is given by `RHS.rem_euclid(LHS::BITS)`. + /// In other words, it is (uniquely) determined as follows: /// - it is "equal modulo LHS::BITS" to the RHS /// - it is in the range `0..LHS::BITS` /// -- cgit 1.4.1-3-g733a5 From ad787c10346fad514b3d9e87225a5a040c41a050 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 14 Jun 2024 12:46:39 +0300 Subject: build `libcxx-version` only when it doesn't exist Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/tool.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 6cf31f2e61e..e0a9674ae5a 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -823,19 +823,29 @@ impl Step for LibcxxVersionTool { fn run(self, builder: &Builder<'_>) -> LibcxxVersion { let out_dir = builder.out.join(self.target.to_string()).join("libcxx-version"); - let _ = fs::remove_dir_all(&out_dir); - t!(fs::create_dir_all(&out_dir)); + let executable = out_dir.join(exe("libcxx-version", self.target)); - let compiler = builder.cxx(self.target).unwrap(); - let mut cmd = Command::new(compiler); + // This is a sanity-check specific step, which means it is frequently called (when using + // CI LLVM), and compiling `src/tools/libcxx-version/main.cpp` at the beginning of the bootstrap + // invocation adds a fair amount of overhead to the process (see https://github.com/rust-lang/rust/issues/126423). + // Therefore, we want to avoid recompiling this file unnecessarily. + if !executable.exists() { + if !out_dir.exists() { + t!(fs::create_dir_all(&out_dir)); + } - let executable = out_dir.join(exe("libcxx-version", self.target)); - cmd.arg("-o").arg(&executable).arg(builder.src.join("src/tools/libcxx-version/main.cpp")); + let compiler = builder.cxx(self.target).unwrap(); + let mut cmd = Command::new(compiler); - builder.run_cmd(&mut cmd); + cmd.arg("-o") + .arg(&executable) + .arg(builder.src.join("src/tools/libcxx-version/main.cpp")); - if !executable.exists() { - panic!("Something went wrong. {} is not present", executable.display()); + builder.run_cmd(&mut cmd); + + if !executable.exists() { + panic!("Something went wrong. {} is not present", executable.display()); + } } let version_output = output(&mut Command::new(executable)); -- cgit 1.4.1-3-g733a5 From e2e1afaf6d273f66b5c08a1c2efb16be311f4db7 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 14 Jun 2024 13:10:04 +0300 Subject: update libstdc++ compatibility error log Signed-off-by: onur-ozkan --- src/bootstrap/src/core/sanity.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index b5f17b9f54e..4d09c42c8ab 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -128,6 +128,9 @@ pub fn check(build: &mut Build) { eprintln!( "Consider upgrading libstdc++ or disabling the `llvm.download-ci-llvm` option." ); + eprintln!( + "If you choose to upgrade libstdc++, run `x clean` or delete `build/host/libcxx-version` manually after the upgrade." + ); } } tool::LibcxxVersion::Llvm(_) => { -- cgit 1.4.1-3-g733a5 From 7999dbbd3e62dfd1cf65e19ea1949e41935b997c Mon Sep 17 00:00:00 2001 From: DianQK Date: Fri, 14 Jun 2024 08:05:20 +0800 Subject: Regenerate `requirements.txt` by Python 3.9 --- src/tools/tidy/config/requirements.in | 6 ++--- src/tools/tidy/config/requirements.txt | 47 ++++------------------------------ 2 files changed, 8 insertions(+), 45 deletions(-) diff --git a/src/tools/tidy/config/requirements.in b/src/tools/tidy/config/requirements.in index 882e09dae45..047617c6559 100644 --- a/src/tools/tidy/config/requirements.in +++ b/src/tools/tidy/config/requirements.in @@ -1,10 +1,10 @@ # requirements.in This is the source file for our pinned version requirements # file "requirements.txt" To regenerate that file, pip-tools is required -# (`python -m pip install pip-tools`). Once installed, run: `pip-compile -# --generate-hashes src/tools/tidy/config/requirements.in` +# (`python -m pip install pip-tools==7.4.1`). Once installed, run: `pip-compile +# --generate-hashes --strip-extras src/tools/tidy/config/requirements.in` # # Note: this generation step should be run with the oldest supported python -# version (currently 3.7) to ensure backward compatibility +# version (currently 3.9) to ensure backward compatibility black==23.3.0 ruff==0.0.272 diff --git a/src/tools/tidy/config/requirements.txt b/src/tools/tidy/config/requirements.txt index 9fd617ad621..a53c98cac7a 100644 --- a/src/tools/tidy/config/requirements.txt +++ b/src/tools/tidy/config/requirements.txt @@ -1,8 +1,8 @@ # -# This file is autogenerated by pip-compile with Python 3.11 +# This file is autogenerated by pip-compile with Python 3.9 # by the following command: # -# pip-compile --generate-hashes src/tools/tidy/config/requirements.in +# pip-compile --generate-hashes --strip-extras src/tools/tidy/config/requirements.in # black==23.3.0 \ --hash=sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5 \ @@ -35,10 +35,6 @@ click==8.1.3 \ --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48 # via black -importlib-metadata==6.7.0 \ - --hash=sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4 \ - --hash=sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5 - # via click mypy-extensions==1.0.0 \ --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \ --hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782 @@ -78,40 +74,7 @@ tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f # via black -typed-ast==1.5.4 \ - --hash=sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2 \ - --hash=sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1 \ - --hash=sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6 \ - --hash=sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62 \ - --hash=sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac \ - --hash=sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d \ - --hash=sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc \ - --hash=sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2 \ - --hash=sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97 \ - --hash=sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35 \ - --hash=sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6 \ - --hash=sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1 \ - --hash=sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4 \ - --hash=sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c \ - --hash=sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e \ - --hash=sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec \ - --hash=sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f \ - --hash=sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72 \ - --hash=sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47 \ - --hash=sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72 \ - --hash=sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe \ - --hash=sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6 \ - --hash=sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3 \ - --hash=sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66 +typing-extensions==4.12.2 \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 # via black -typing-extensions==4.6.3 \ - --hash=sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26 \ - --hash=sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5 - # via - # black - # importlib-metadata - # platformdirs -zipp==3.15.0 \ - --hash=sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b \ - --hash=sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556 - # via importlib-metadata -- cgit 1.4.1-3-g733a5 From ab7fc60a7389667f6e7eee952c4e1101f1746b3d Mon Sep 17 00:00:00 2001 From: DianQK Date: Fri, 14 Jun 2024 08:08:57 +0800 Subject: End support for Python 3.8 in tidy --- src/tools/tidy/src/ext_tool_checks.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index fb626cac3fa..995ad58cb62 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -24,9 +24,8 @@ use std::io; use std::path::{Path, PathBuf}; use std::process::Command; -/// Minimum python revision is 3.7 for ruff -const MIN_PY_REV: (u32, u32) = (3, 7); -const MIN_PY_REV_STR: &str = "≥3.7"; +const MIN_PY_REV: (u32, u32) = (3, 9); +const MIN_PY_REV_STR: &str = "≥3.9"; /// Path to find the python executable within a virtual environment #[cfg(target_os = "windows")] @@ -223,17 +222,8 @@ fn get_or_create_venv(venv_path: &Path, src_reqs_path: &Path) -> Result Result<(), Error> { /// Preferred python versions in order. Newest to oldest then current /// development versions - const TRY_PY: &[&str] = &[ - "python3.11", - "python3.10", - "python3.9", - "python3.8", - "python3.7", - "python3", - "python", - "python3.12", - "python3.13", - ]; + const TRY_PY: &[&str] = + &["python3.11", "python3.10", "python3.9", "python3", "python", "python3.12", "python3.13"]; let mut sys_py = None; let mut found = Vec::new(); -- cgit 1.4.1-3-g733a5 From 267ba9ade20c151f5c51aad5db15bb9ba3914713 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 14 Jun 2024 13:50:17 +0200 Subject: Migrate `run-make/codegen-options-parsing` to `rmake.rs` --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/codegen-options-parsing/Makefile | 34 -------------- tests/run-make/codegen-options-parsing/rmake.rs | 56 +++++++++++++++++++++++ 3 files changed, 56 insertions(+), 35 deletions(-) delete mode 100644 tests/run-make/codegen-options-parsing/Makefile create mode 100644 tests/run-make/codegen-options-parsing/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 14d7bfe9ad4..9621eff70c1 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -12,7 +12,6 @@ run-make/c-unwind-abi-catch-panic/Makefile run-make/cat-and-grep-sanity-check/Makefile run-make/cdylib-dylib-linkage/Makefile run-make/cdylib-fewer-symbols/Makefile -run-make/codegen-options-parsing/Makefile run-make/comment-section/Makefile run-make/compiler-lookup-paths-2/Makefile run-make/compiler-lookup-paths/Makefile diff --git a/tests/run-make/codegen-options-parsing/Makefile b/tests/run-make/codegen-options-parsing/Makefile deleted file mode 100644 index beaf233502b..00000000000 --- a/tests/run-make/codegen-options-parsing/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -# This test intentionally feeds invalid inputs to codegen and checks if the error message outputs contain specific helpful indications. - -# ignore-cross-compile -include ../tools.mk - -all: - #Option taking a number - $(RUSTC) -C codegen-units dummy.rs 2>&1 | \ - $(CGREP) 'codegen option `codegen-units` requires a number' - $(RUSTC) -C codegen-units= dummy.rs 2>&1 | \ - $(CGREP) 'incorrect value `` for codegen option `codegen-units` - a number was expected' - $(RUSTC) -C codegen-units=foo dummy.rs 2>&1 | \ - $(CGREP) 'incorrect value `foo` for codegen option `codegen-units` - a number was expected' - $(RUSTC) -C codegen-units=1 dummy.rs - #Option taking a string - $(RUSTC) -C extra-filename dummy.rs 2>&1 | \ - $(CGREP) 'codegen option `extra-filename` requires a string' - $(RUSTC) -C extra-filename= dummy.rs 2>&1 - $(RUSTC) -C extra-filename=foo dummy.rs 2>&1 - #Option taking no argument - $(RUSTC) -C lto= dummy.rs 2>&1 | \ - $(CGREP) 'codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted' - $(RUSTC) -C lto=1 dummy.rs 2>&1 | \ - $(CGREP) 'codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted' - $(RUSTC) -C lto=foo dummy.rs 2>&1 | \ - $(CGREP) 'codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted' - $(RUSTC) -C lto dummy.rs - - # Should not link dead code... - $(RUSTC) --print link-args dummy.rs 2>&1 | \ - $(CGREP) -e '--gc-sections|-z[^ ]* [^ ]*|-dead_strip|/OPT:REF' - # ... unless you specifically ask to keep it - $(RUSTC) --print link-args -C link-dead-code dummy.rs 2>&1 | \ - $(CGREP) -ve '--gc-sections|-z[^ ]* [^ ]*|-dead_strip|/OPT:REF' diff --git a/tests/run-make/codegen-options-parsing/rmake.rs b/tests/run-make/codegen-options-parsing/rmake.rs new file mode 100644 index 00000000000..c78b41a88dc --- /dev/null +++ b/tests/run-make/codegen-options-parsing/rmake.rs @@ -0,0 +1,56 @@ +// This test intentionally feeds invalid inputs to codegen and checks if the error message outputs +// contain specific helpful indications. + +//@ ignore-cross-compile + +use run_make_support::regex::Regex; +use run_make_support::rustc; + +fn main() { + // Option taking a number. + rustc() + .input("dummy.rs") + .arg("-Ccodegen-units") + .run_fail() + .assert_stderr_contains("codegen option `codegen-units` requires a number"); + rustc().input("dummy.rs").arg("-Ccodegen-units=").run_fail().assert_stderr_contains( + "incorrect value `` for codegen option `codegen-units` - a number was expected", + ); + rustc().input("dummy.rs").arg("-Ccodegen-units=foo").run_fail().assert_stderr_contains( + "incorrect value `foo` for codegen option `codegen-units` - a number was expected", + ); + rustc().input("dummy.rs").arg("-Ccodegen-units=1").run(); + + // Option taking a string. + rustc() + .input("dummy.rs") + .arg("-Cextra-filename") + .run_fail() + .assert_stderr_contains("codegen option `extra-filename` requires a string"); + rustc().input("dummy.rs").arg("-Cextra-filename=").run(); + rustc().input("dummy.rs").arg("-Cextra-filename=foo").run(); + + // Option taking no argument. + rustc().input("dummy.rs").arg("-Clto=").run_fail().assert_stderr_contains( + "codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \ + `fat`, or omitted", + ); + rustc().input("dummy.rs").arg("-Clto=1").run_fail().assert_stderr_contains( + "codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \ + `fat`, or omitted", + ); + rustc().input("dummy.rs").arg("-Clto=foo").run_fail().assert_stderr_contains( + "codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \ + `fat`, or omitted", + ); + rustc().input("dummy.rs").arg("-Clto").run(); + + let regex = Regex::new("--gc-sections|-z[^ ]* [^ ]*|-dead_strip|/OPT:REF").unwrap(); + // Should not link dead code... + let stdout = rustc().input("dummy.rs").print("link-args").run().stdout_utf8(); + assert!(regex.is_match(&stdout)); + // ... unless you specifically ask to keep it + let stdout = + rustc().input("dummy.rs").print("link-args").arg("-Clink-dead-code").run().stdout_utf8(); + assert!(!regex.is_match(&stdout)); +} -- cgit 1.4.1-3-g733a5 From b4df72aae2a7f9ac13d4497e03f0681b6fec2010 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 14 Jun 2024 15:49:09 +0200 Subject: Do not enable `llvm-bitcode-linker` in most default bootstrap profiles --- config.example.toml | 4 ++-- src/bootstrap/defaults/config.compiler.toml | 2 -- src/bootstrap/defaults/config.dist.toml | 2 +- src/bootstrap/defaults/config.library.toml | 2 -- src/bootstrap/defaults/config.tools.toml | 2 -- 5 files changed, 3 insertions(+), 9 deletions(-) diff --git a/config.example.toml b/config.example.toml index fb45493ec4a..76541ee4e9e 100644 --- a/config.example.toml +++ b/config.example.toml @@ -657,7 +657,7 @@ # whether to set it as rustc's default linker on `x86_64-unknown-linux-gnu`. This will also only be # when *not* building an external LLVM (so only when using `download-ci-llvm` or building LLVM from # the in-tree source): setting `llvm-config` in the `[target.x86_64-unknown-linux-gnu]` section will -# make this default to false. +# make this default to false. #lld = false in all cases, except on `x86_64-unknown-linux-gnu` as described above, where it is true # Indicates whether LLD will be used to link Rust crates during bootstrap on @@ -676,7 +676,7 @@ #llvm-tools = true # Indicates whether the `self-contained` llvm-bitcode-linker, will be made available -# in the sysroot +# in the sysroot. It is required for running nvptx tests. #llvm-bitcode-linker = false # Whether to deny warnings in crates diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml index fd2da246990..789586b58f7 100644 --- a/src/bootstrap/defaults/config.compiler.toml +++ b/src/bootstrap/defaults/config.compiler.toml @@ -19,8 +19,6 @@ lto = "off" # Forces frame pointers to be used with `-Cforce-frame-pointers`. # This can be helpful for profiling at a small performance cost. frame-pointers = true -# Build the llvm-bitcode-linker as it is required for running nvptx tests -llvm-bitcode-linker = true [llvm] # Having this set to true disrupts compiler development workflows for people who use `llvm.download-ci-llvm = true` diff --git a/src/bootstrap/defaults/config.dist.toml b/src/bootstrap/defaults/config.dist.toml index f3c6ffc9bd5..d06930f2b9d 100644 --- a/src/bootstrap/defaults/config.dist.toml +++ b/src/bootstrap/defaults/config.dist.toml @@ -16,7 +16,7 @@ download-ci-llvm = false # Make sure they don't get set when installing from source. channel = "nightly" download-rustc = false -# Build the llvm-bitcode-linker as it is required for running nvptx tests +# Build the llvm-bitcode-linker llvm-bitcode-linker = true [dist] diff --git a/src/bootstrap/defaults/config.library.toml b/src/bootstrap/defaults/config.library.toml index 4a1a49b7275..087544397f5 100644 --- a/src/bootstrap/defaults/config.library.toml +++ b/src/bootstrap/defaults/config.library.toml @@ -10,8 +10,6 @@ bench-stage = 0 incremental = true # Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown. lto = "off" -# Build the llvm-bitcode-linker as it is required for running nvptx tests -llvm-bitcode-linker = true [llvm] # Will download LLVM from CI if available on your platform. diff --git a/src/bootstrap/defaults/config.tools.toml b/src/bootstrap/defaults/config.tools.toml index 94c8b724cbf..6e6c3660027 100644 --- a/src/bootstrap/defaults/config.tools.toml +++ b/src/bootstrap/defaults/config.tools.toml @@ -12,8 +12,6 @@ incremental = true # Using these defaults will download the stage2 compiler (see `download-rustc` # setting) and the stage2 toolchain should therefore be used for these defaults. download-rustc = "if-unchanged" -# Build the llvm-bitcode-linker as it is required for running nvptx tests -llvm-bitcode-linker = true [build] # Document with the in-tree rustdoc by default, since `download-rustc` makes it quick to compile. -- cgit 1.4.1-3-g733a5 From 04af37170cc6a608f87b48706d49be3504585f58 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 13 Jun 2024 20:42:12 +0200 Subject: Also sort `crt-static` in `--print target-features` output I didn't find `crt-static` at first (for `x86_64-unknown-linux-gnu`), because it was put at the bottom the large and otherwise sorted list. Fully sort the list before we print it. Note that `llvm_target_features` starts out sorted and does not need to be sorted an extra time. --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 53b9b530e9b..7e0f264a4ae 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -394,10 +394,15 @@ fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &ll (*feature, desc) }) .collect::>(); + + // Since we add this at the end ... rustc_target_features.extend_from_slice(&[( "crt-static", "Enables C Run-time Libraries to be statically linked", )]); + // ... we need to sort the list again. + rustc_target_features.sort(); + llvm_target_features.retain(|(f, _d)| !known_llvm_target_features.contains(f)); let max_feature_len = llvm_target_features -- cgit 1.4.1-3-g733a5 From c906d2e428b9d20d1d73ec587bff75a6d25efed7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 13 Jun 2024 08:11:16 -0500 Subject: Enable const evaluation for `f16` and `f128` This excludes casting, which needs more tests. --- compiler/rustc_const_eval/src/interpret/operator.rs | 10 ++++++++-- compiler/rustc_middle/src/mir/interpret/value.rs | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index a6eef9f5662..a6924371632 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -362,14 +362,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let left = left.to_scalar(); let right = right.to_scalar(); Ok(match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => { + self.binary_float_op(bin_op, layout, left.to_f16()?, right.to_f16()?) + } FloatTy::F32 => { self.binary_float_op(bin_op, layout, left.to_f32()?, right.to_f32()?) } FloatTy::F64 => { self.binary_float_op(bin_op, layout, left.to_f64()?, right.to_f64()?) } - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => { + self.binary_float_op(bin_op, layout, left.to_f128()?, right.to_f128()?) + } }) } _ if left.layout.ty.is_integral() => { @@ -431,8 +435,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let val = val.to_scalar(); // No NaN adjustment here, `-` is a bitwise operation! let res = match (un_op, fty) { + (Neg, FloatTy::F16) => Scalar::from_f16(-val.to_f16()?), (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?), (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), + (Neg, FloatTy::F128) => Scalar::from_f128(-val.to_f128()?), _ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op), }; Ok(ImmTy::from_scalar(res, layout)) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 70e5ad0635b..a84a4c583ed 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -69,6 +69,13 @@ impl fmt::LowerHex for Scalar { } } +impl From for Scalar { + #[inline(always)] + fn from(f: Half) -> Self { + Scalar::from_f16(f) + } +} + impl From for Scalar { #[inline(always)] fn from(f: Single) -> Self { @@ -83,6 +90,13 @@ impl From for Scalar { } } +impl From for Scalar { + #[inline(always)] + fn from(f: Quad) -> Self { + Scalar::from_f128(f) + } +} + impl From for Scalar { #[inline(always)] fn from(ptr: ScalarInt) -> Self { -- cgit 1.4.1-3-g733a5 From eab5e8e9d95439adb4b63cd631dd24dae90cd9ad Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 13 Jun 2024 08:29:38 -0500 Subject: Make the unary operator `FloatTy` check exhaustive Add a spot that was missed in . --- compiler/rustc_const_eval/src/interpret/operator.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index a6924371632..2175f051a19 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -433,13 +433,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } ty::Float(fty) => { let val = val.to_scalar(); + if un_op != Neg { + span_bug!(self.cur_span(), "Invalid float op {:?}", un_op); + } + // No NaN adjustment here, `-` is a bitwise operation! - let res = match (un_op, fty) { - (Neg, FloatTy::F16) => Scalar::from_f16(-val.to_f16()?), - (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?), - (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), - (Neg, FloatTy::F128) => Scalar::from_f128(-val.to_f128()?), - _ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op), + let res = match fty { + FloatTy::F16 => Scalar::from_f16(-val.to_f16()?), + FloatTy::F32 => Scalar::from_f32(-val.to_f32()?), + FloatTy::F64 => Scalar::from_f64(-val.to_f64()?), + FloatTy::F128 => Scalar::from_f128(-val.to_f128()?), }; Ok(ImmTy::from_scalar(res, layout)) } -- cgit 1.4.1-3-g733a5 From 5cb58ad50327774ab8b4705e4249e20785445840 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 13 Jun 2024 13:04:16 -0500 Subject: Add `f16` and `f128` support to Miri --- src/tools/miri/src/helpers.rs | 8 +- src/tools/miri/tests/pass/float.rs | 149 +++++++++++++------------------------ 2 files changed, 56 insertions(+), 101 deletions(-) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 87b53d87ac8..843aff02495 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -7,7 +7,7 @@ use std::time::Duration; use rand::RngCore; -use rustc_apfloat::ieee::{Double, Single}; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::Float; use rustc_hir::{ def::{DefKind, Namespace}, @@ -1201,12 +1201,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let (val, status) = match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => + float_to_int_inner::(this, src.to_scalar().to_f16()?, cast_to, round), FloatTy::F32 => float_to_int_inner::(this, src.to_scalar().to_f32()?, cast_to, round), FloatTy::F64 => float_to_int_inner::(this, src.to_scalar().to_f64()?, cast_to, round), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => + float_to_int_inner::(this, src.to_scalar().to_f128()?, cast_to, round), }; if status.intersects( diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 8aea9b3e6f9..5464627fa14 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -1,6 +1,8 @@ #![feature(stmt_expr_attributes)] #![feature(float_gamma)] #![feature(core_intrinsics)] +#![feature(f128)] +#![feature(f16)] #![allow(arithmetic_overflow)] use std::fmt::Debug; @@ -41,103 +43,23 @@ trait FloatToInt: Copy { unsafe fn cast_unchecked(self) -> Int; } -impl FloatToInt for f32 { - fn cast(self) -> i8 { - self as _ - } - unsafe fn cast_unchecked(self) -> i8 { - self.to_int_unchecked() - } -} -impl FloatToInt for f32 { - fn cast(self) -> i32 { - self as _ - } - unsafe fn cast_unchecked(self) -> i32 { - self.to_int_unchecked() - } -} -impl FloatToInt for f32 { - fn cast(self) -> u32 { - self as _ - } - unsafe fn cast_unchecked(self) -> u32 { - self.to_int_unchecked() - } -} -impl FloatToInt for f32 { - fn cast(self) -> i64 { - self as _ - } - unsafe fn cast_unchecked(self) -> i64 { - self.to_int_unchecked() - } -} -impl FloatToInt for f32 { - fn cast(self) -> u64 { - self as _ - } - unsafe fn cast_unchecked(self) -> u64 { - self.to_int_unchecked() - } +macro_rules! float_to_int { + ($fty:ty => $($ity:ty),+ $(,)?) => { + $( + impl FloatToInt<$ity> for $fty { + fn cast(self) -> $ity { + self as _ + } + unsafe fn cast_unchecked(self) -> $ity { + self.to_int_unchecked() + } + } + )* + }; } -impl FloatToInt for f64 { - fn cast(self) -> i8 { - self as _ - } - unsafe fn cast_unchecked(self) -> i8 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> i32 { - self as _ - } - unsafe fn cast_unchecked(self) -> i32 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> u32 { - self as _ - } - unsafe fn cast_unchecked(self) -> u32 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> i64 { - self as _ - } - unsafe fn cast_unchecked(self) -> i64 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> u64 { - self as _ - } - unsafe fn cast_unchecked(self) -> u64 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> i128 { - self as _ - } - unsafe fn cast_unchecked(self) -> i128 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> u128 { - self as _ - } - unsafe fn cast_unchecked(self) -> u128 { - self.to_int_unchecked() - } -} +float_to_int!(f32 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); +float_to_int!(f64 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); /// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). #[track_caller] @@ -153,18 +75,29 @@ where fn basic() { // basic arithmetic + assert_eq(6.0_f16 * 6.0_f16, 36.0_f16); assert_eq(6.0_f32 * 6.0_f32, 36.0_f32); assert_eq(6.0_f64 * 6.0_f64, 36.0_f64); + assert_eq(6.0_f128 * 6.0_f128, 36.0_f128); + assert_eq(-{ 5.0_f16 }, -5.0_f16); assert_eq(-{ 5.0_f32 }, -5.0_f32); assert_eq(-{ 5.0_f64 }, -5.0_f64); + assert_eq(-{ 5.0_f128 }, -5.0_f128); + // infinities, NaN + // FIXME(f16_f128): add when constants and `is_infinite` are available assert!((5.0_f32 / 0.0).is_infinite()); assert_ne!({ 5.0_f32 / 0.0 }, { -5.0_f32 / 0.0 }); assert!((5.0_f64 / 0.0).is_infinite()); assert_ne!({ 5.0_f64 / 0.0 }, { 5.0_f64 / -0.0 }); assert_ne!(f32::NAN, f32::NAN); assert_ne!(f64::NAN, f64::NAN); + // negative zero + let posz = 0.0f16; + let negz = -0.0f16; + assert_eq(posz, negz); + assert_ne!(posz.to_bits(), negz.to_bits()); let posz = 0.0f32; let negz = -0.0f32; assert_eq(posz, negz); @@ -173,15 +106,30 @@ fn basic() { let negz = -0.0f64; assert_eq(posz, negz); assert_ne!(posz.to_bits(), negz.to_bits()); + let posz = 0.0f128; + let negz = -0.0f128; + assert_eq(posz, negz); + assert_ne!(posz.to_bits(), negz.to_bits()); + // byte-level transmute - let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; - let y: f64 = unsafe { std::mem::transmute(x) }; - assert_eq(y, 42.0_f64); + let x: u16 = unsafe { std::mem::transmute(42.0_f16) }; + let y: f16 = unsafe { std::mem::transmute(x) }; + assert_eq(y, 42.0_f16); let x: u32 = unsafe { std::mem::transmute(42.0_f32) }; let y: f32 = unsafe { std::mem::transmute(x) }; assert_eq(y, 42.0_f32); + let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; + let y: f64 = unsafe { std::mem::transmute(x) }; + assert_eq(y, 42.0_f64); + let x: u128 = unsafe { std::mem::transmute(42.0_f128) }; + let y: f128 = unsafe { std::mem::transmute(x) }; + assert_eq(y, 42.0_f128); // `%` sign behavior, some of this used to be buggy + assert!((black_box(1.0f16) % 1.0).is_sign_positive()); + assert!((black_box(1.0f16) % -1.0).is_sign_positive()); + assert!((black_box(-1.0f16) % 1.0).is_sign_negative()); + assert!((black_box(-1.0f16) % -1.0).is_sign_negative()); assert!((black_box(1.0f32) % 1.0).is_sign_positive()); assert!((black_box(1.0f32) % -1.0).is_sign_positive()); assert!((black_box(-1.0f32) % 1.0).is_sign_negative()); @@ -190,7 +138,12 @@ fn basic() { assert!((black_box(1.0f64) % -1.0).is_sign_positive()); assert!((black_box(-1.0f64) % 1.0).is_sign_negative()); assert!((black_box(-1.0f64) % -1.0).is_sign_negative()); + assert!((black_box(1.0f128) % 1.0).is_sign_positive()); + assert!((black_box(1.0f128) % -1.0).is_sign_positive()); + assert!((black_box(-1.0f128) % 1.0).is_sign_negative()); + assert!((black_box(-1.0f128) % -1.0).is_sign_negative()); + // FIXME(f16_f128): add when `abs` is available assert_eq!((-1.0f32).abs(), 1.0f32); assert_eq!(34.2f64.abs(), 34.2f64); } -- cgit 1.4.1-3-g733a5 From e649042316ec3f832cfe120d04068b6e3e6c1791 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 14 Jun 2024 12:41:07 -0500 Subject: Remove f16 const eval crash test Const eval negation was added. This test is now covered by Miri tests, and merged into an existing UI test. Fixes --- tests/crashes/124583.rs | 5 ----- tests/ui/numbers-arithmetic/f16-f128-lit.rs | 4 ++++ 2 files changed, 4 insertions(+), 5 deletions(-) delete mode 100644 tests/crashes/124583.rs diff --git a/tests/crashes/124583.rs b/tests/crashes/124583.rs deleted file mode 100644 index ffd9d7521ad..00000000000 --- a/tests/crashes/124583.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: rust-lang/rust#124583 - -fn main() { - let _ = -(-0.0f16); -} diff --git a/tests/ui/numbers-arithmetic/f16-f128-lit.rs b/tests/ui/numbers-arithmetic/f16-f128-lit.rs index 762436edb16..7fd20d91d82 100644 --- a/tests/ui/numbers-arithmetic/f16-f128-lit.rs +++ b/tests/ui/numbers-arithmetic/f16-f128-lit.rs @@ -1,3 +1,5 @@ +// Make sure negation happens correctly. Also included: +// issue: rust-lang/rust#124583 //@ run-pass #![feature(f16)] @@ -8,9 +10,11 @@ fn main() { assert_eq!((-0.0_f16).to_bits(), 0x8000); assert_eq!(10.0_f16.to_bits(), 0x4900); assert_eq!((-10.0_f16).to_bits(), 0xC900); + assert_eq!((-(-0.0f16)).to_bits(), 0x0000); assert_eq!(0.0_f128.to_bits(), 0x0000_0000_0000_0000_0000_0000_0000_0000); assert_eq!((-0.0_f128).to_bits(), 0x8000_0000_0000_0000_0000_0000_0000_0000); assert_eq!(10.0_f128.to_bits(), 0x4002_4000_0000_0000_0000_0000_0000_0000); assert_eq!((-10.0_f128).to_bits(), 0xC002_4000_0000_0000_0000_0000_0000_0000); + assert_eq!((-(-0.0f128)).to_bits(), 0x0000_0000_0000_0000_0000_0000_0000_0000); } -- cgit 1.4.1-3-g733a5 From 78d4802448307369d81c953c290f5043c004a8fe Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 14 Jun 2024 18:42:02 +0000 Subject: Use `std::path::absolute` in bootstrap --- src/bootstrap/src/core/config/config.rs | 4 +- src/bootstrap/src/utils/helpers.rs | 109 ------------------------------- src/bootstrap/src/utils/helpers/tests.rs | 21 ------ 3 files changed, 2 insertions(+), 132 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 36b44d0169c..6024896b065 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -10,7 +10,7 @@ use std::env; use std::fmt::{self, Display}; use std::fs; use std::io::IsTerminal; -use std::path::{Path, PathBuf}; +use std::path::{absolute, Path, PathBuf}; use std::process::Command; use std::str::FromStr; use std::sync::OnceLock; @@ -1437,7 +1437,7 @@ impl Config { // To avoid writing to random places on the file system, `config.out` needs to be an absolute path. if !config.out.is_absolute() { // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead. - config.out = crate::utils::helpers::absolute(&config.out); + config.out = absolute(&config.out).expect("can't make empty path absolute"); } config.initial_rustc = if let Some(rustc) = rustc { diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 278359cb08e..1df34323535 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -331,115 +331,6 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { }) } -/// Copied from `std::path::absolute` until it stabilizes. -/// -/// FIXME: this shouldn't exist. -pub(crate) fn absolute(path: &Path) -> PathBuf { - if path.as_os_str().is_empty() { - panic!("can't make empty path absolute"); - } - #[cfg(unix)] - { - t!(absolute_unix(path), format!("could not make path absolute: {}", path.display())) - } - #[cfg(windows)] - { - t!(absolute_windows(path), format!("could not make path absolute: {}", path.display())) - } - #[cfg(not(any(unix, windows)))] - { - println!("WARNING: bootstrap is not supported on non-unix platforms"); - t!(std::fs::canonicalize(t!(std::env::current_dir()))).join(path) - } -} - -#[cfg(unix)] -/// Make a POSIX path absolute without changing its semantics. -fn absolute_unix(path: &Path) -> io::Result { - // This is mostly a wrapper around collecting `Path::components`, with - // exceptions made where this conflicts with the POSIX specification. - // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017 - // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13 - - use std::os::unix::prelude::OsStrExt; - let mut components = path.components(); - let path_os = path.as_os_str().as_bytes(); - - let mut normalized = if path.is_absolute() { - // "If a pathname begins with two successive characters, the - // first component following the leading characters may be - // interpreted in an implementation-defined manner, although more than - // two leading characters shall be treated as a single - // character." - if path_os.starts_with(b"//") && !path_os.starts_with(b"///") { - components.next(); - PathBuf::from("//") - } else { - PathBuf::new() - } - } else { - env::current_dir()? - }; - normalized.extend(components); - - // "Interfaces using pathname resolution may specify additional constraints - // when a pathname that does not name an existing directory contains at - // least one non- character and contains one or more trailing - // characters". - // A trailing is also meaningful if "a symbolic link is - // encountered during pathname resolution". - - if path_os.ends_with(b"/") { - normalized.push(""); - } - - Ok(normalized) -} - -#[cfg(windows)] -fn absolute_windows(path: &std::path::Path) -> std::io::Result { - use std::ffi::OsString; - use std::io::Error; - use std::os::windows::ffi::{OsStrExt, OsStringExt}; - use std::ptr::null_mut; - #[link(name = "kernel32")] - extern "system" { - fn GetFullPathNameW( - lpFileName: *const u16, - nBufferLength: u32, - lpBuffer: *mut u16, - lpFilePart: *mut *const u16, - ) -> u32; - } - - unsafe { - // encode the path as UTF-16 - let path: Vec = path.as_os_str().encode_wide().chain([0]).collect(); - let mut buffer = Vec::new(); - // Loop until either success or failure. - loop { - // Try to get the absolute path - let len = GetFullPathNameW( - path.as_ptr(), - buffer.len().try_into().unwrap(), - buffer.as_mut_ptr(), - null_mut(), - ); - match len as usize { - // Failure - 0 => return Err(Error::last_os_error()), - // Buffer is too small, resize. - len if len > buffer.len() => buffer.resize(len, 0), - // Success! - len => { - buffer.truncate(len); - return Ok(OsString::from_wide(&buffer).into()); - } - } - } - } -} - /// Adapted from /// /// When `clang-cl` is used with instrumentation, we need to add clang's runtime library resource diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs index 9cfaa3eb67b..2ab3952ae5a 100644 --- a/src/bootstrap/src/utils/helpers/tests.rs +++ b/src/bootstrap/src/utils/helpers/tests.rs @@ -25,27 +25,6 @@ fn test_make() { } } -#[cfg(unix)] -#[test] -fn test_absolute_unix() { - use crate::utils::helpers::absolute_unix; - - // Test an absolute path - let path = PathBuf::from("/home/user/file.txt"); - assert_eq!(absolute_unix(&path).unwrap(), PathBuf::from("/home/user/file.txt")); - - // Test an absolute path with double leading slashes - let path = PathBuf::from("//root//file.txt"); - assert_eq!(absolute_unix(&path).unwrap(), PathBuf::from("//root/file.txt")); - - // Test a relative path - let path = PathBuf::from("relative/path"); - assert_eq!( - absolute_unix(&path).unwrap(), - std::env::current_dir().unwrap().join("relative/path") - ); -} - #[test] fn test_beta_rev_parsing() { // single digit revision -- cgit 1.4.1-3-g733a5 From 8a8bbc0c17cbd6c0e25e878921b1ad69c95bb20d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jun 2024 15:59:47 -0400 Subject: Make Candidate generic over interner --- .../src/solve/assembly/mod.rs | 99 +++++++++++----------- .../src/solve/eval_ctxt/probe.rs | 2 +- .../src/solve/normalizes_to/mod.rs | 48 +++++------ .../rustc_trait_selection/src/solve/trait_goals.rs | 64 +++++++------- 4 files changed, 107 insertions(+), 106 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index b51efd339c4..7615af201ef 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -1,20 +1,20 @@ //! Code shared by trait and projection goals for candidate assembly. +use derivative::Derivative; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::bug; use rustc_middle::traits::solve::inspect::ProbeKind; -use rustc_middle::traits::solve::{ - CandidateSource, CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult, -}; +use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause, QueryResult}; use rustc_middle::traits::BuiltinImplSource; use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{fast_reject, TypeFoldable}; use rustc_middle::ty::{TypeVisitableExt, Upcast}; use rustc_span::{ErrorGuaranteed, DUMMY_SP}; -use std::fmt::Debug; +use rustc_type_ir::solve::{CandidateSource, CanonicalResponse}; +use rustc_type_ir::Interner; use crate::solve::GoalSource; use crate::solve::{EvalCtxt, SolverMode}; @@ -25,10 +25,11 @@ pub(super) mod structural_traits; /// /// It consists of both the `source`, which describes how that goal would be proven, /// and the `result` when using the given `source`. -#[derive(Debug, Clone)] -pub(super) struct Candidate<'tcx> { - pub(super) source: CandidateSource<'tcx>, - pub(super) result: CanonicalResponse<'tcx>, +#[derive(Derivative)] +#[derivative(Debug(bound = ""), Clone(bound = ""))] +pub(super) struct Candidate { + pub(super) source: CandidateSource, + pub(super) result: CanonicalResponse, } /// Methods used to assemble candidates for either trait or projection goals. @@ -49,22 +50,22 @@ pub(super) trait GoalKind<'tcx>: /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]). fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - source: CandidateSource<'tcx>, + source: CandidateSource>, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// Consider a clause, which consists of a "assumption" and some "requirements", /// to satisfy a goal. If the requirements hold, then attempt to satisfy our /// goal by equating it with the assumption. fn probe_and_consider_implied_clause( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - parent_source: CandidateSource<'tcx>, + parent_source: CandidateSource>, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, requirements: impl IntoIterator>)>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { Self::probe_and_match_goal_against_assumption(ecx, parent_source, goal, assumption, |ecx| { for (nested_source, goal) in requirements { ecx.add_goal(nested_source, goal); @@ -78,10 +79,10 @@ pub(super) trait GoalKind<'tcx>: /// since they're not implied by the well-formedness of the object type. fn probe_and_consider_object_bound_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - source: CandidateSource<'tcx>, + source: CandidateSource>, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| { let tcx = ecx.interner(); let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { @@ -104,7 +105,7 @@ pub(super) trait GoalKind<'tcx>: ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, impl_def_id: DefId, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// If the predicate contained an error, we want to avoid emitting unnecessary trait /// errors but still want to emit errors for other trait goals. We have some special @@ -115,7 +116,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_error_guaranteed_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, guar: ErrorGuaranteed, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A type implements an `auto trait` if its components do as well. /// @@ -124,13 +125,13 @@ pub(super) trait GoalKind<'tcx>: fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A trait alias holds if the RHS traits and `where` clauses hold. fn consider_trait_alias_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A type is `Sized` if its tail component is `Sized`. /// @@ -139,7 +140,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. /// @@ -148,20 +149,20 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A type is `PointerLike` if we can compute its layout, and that layout /// matches the layout of `usize`. fn consider_builtin_pointer_like_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A type is a `FnPtr` if it is of `FnPtr` type. fn consider_builtin_fn_ptr_trait_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn` /// family of traits where `A` is given by the signature of the type. @@ -169,7 +170,7 @@ pub(super) trait GoalKind<'tcx>: ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, kind: ty::ClosureKind, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// An async closure is known to implement the `AsyncFn` family of traits /// where `A` is given by the signature of the type. @@ -177,7 +178,7 @@ pub(super) trait GoalKind<'tcx>: ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, kind: ty::ClosureKind, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which /// is used internally to delay computation for async closures until after @@ -185,13 +186,13 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_async_fn_kind_helper_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// `Tuple` is implemented if the `Self` type is a tuple. fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// `Pointee` is always implemented. /// @@ -201,7 +202,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_pointee_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A coroutine (that comes from an `async` desugaring) is known to implement /// `Future`, where `O` is given by the coroutine's return type @@ -209,7 +210,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_future_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A coroutine (that comes from a `gen` desugaring) is known to implement /// `Iterator`, where `O` is given by the generator's yield type @@ -217,19 +218,19 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A coroutine (that comes from a `gen` desugaring) is known to implement /// `FusedIterator` fn consider_builtin_fused_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to /// implement `Coroutine`, given the resume, yield, @@ -237,27 +238,27 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_coroutine_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; fn consider_builtin_discriminant_kind_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; fn consider_builtin_async_destruct_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; fn consider_builtin_destruct_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; fn consider_builtin_transmute_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// Consider (possibly several) candidates to upcast or unsize a type to another /// type, excluding the coercion of a sized type into a `dyn Trait`. @@ -269,14 +270,14 @@ pub(super) trait GoalKind<'tcx>: fn consider_structural_builtin_unsize_candidates( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Vec>; + ) -> Vec>>; } impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn assemble_and_evaluate_candidates>( &mut self, goal: Goal<'tcx, G>, - ) -> Vec> { + ) -> Vec>> { let Ok(normalized_self_ty) = self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty()) else { @@ -323,7 +324,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn forced_ambiguity( &mut self, cause: MaybeCause, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { // This may fail if `try_evaluate_added_goals` overflows because it // fails to reach a fixpoint but ends up getting an error after // running for some additional step. @@ -339,7 +340,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_non_blanket_impl_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let tcx = self.interner(); let self_ty = goal.predicate.self_ty(); @@ -455,7 +456,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_blanket_impl_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let tcx = self.interner(); let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); @@ -478,7 +479,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_builtin_impl_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let tcx = self.interner(); let lang_items = tcx.lang_items(); @@ -552,7 +553,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_param_env_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() { candidates.extend(G::probe_and_consider_implied_clause( @@ -569,7 +570,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_alias_bound_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates); @@ -589,7 +590,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, self_ty: Ty<'tcx>, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let (kind, alias_ty) = match *self_ty.kind() { ty::Bool @@ -673,7 +674,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_object_bound_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let tcx = self.interner(); if !tcx.trait_def(goal.predicate.trait_def_id(tcx)).implement_via_object { @@ -764,7 +765,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_coherence_unknowable_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let tcx = self.interner(); @@ -793,7 +794,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn discard_impls_shadowed_by_env>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let tcx = self.interner(); let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> = @@ -841,7 +842,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "debug", skip(self), ret)] pub(super) fn merge_candidates( &mut self, - candidates: Vec>, + candidates: Vec>>, ) -> QueryResult<'tcx> { // First try merging all candidates. This is complete and fully sound. let responses = candidates.iter().map(|c| c.result).collect::>(); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs index 1748c9be927..7b912e93dc8 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs @@ -65,7 +65,7 @@ where pub(in crate::solve) fn enter( self, f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result }) } } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 50253d81528..a8be1517a44 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -103,7 +103,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { let tcx = ecx.interner(); @@ -140,7 +140,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, NormalizesTo<'tcx>>, impl_def_id: DefId, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = ecx.interner(); let goal_trait_ref = goal.predicate.alias.trait_ref(tcx); @@ -267,14 +267,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_error_guaranteed_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, _guar: ErrorGuaranteed, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { Err(NoSolution) } fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { ecx.interner().dcx().span_delayed_bug( ecx.interner().def_span(goal.predicate.def_id()), "associated types not allowed on auto traits", @@ -285,35 +285,35 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_trait_alias_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("trait aliases do not have associated types: {:?}", goal); } fn consider_builtin_sized_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`Sized` does not have an associated type: {:?}", goal); } fn consider_builtin_copy_clone_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal); } fn consider_builtin_pointer_like_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`PointerLike` does not have an associated type: {:?}", goal); } fn consider_builtin_fn_ptr_trait_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`FnPtr` does not have an associated type: {:?}", goal); } @@ -321,7 +321,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = ecx.interner(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( @@ -364,7 +364,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = ecx.interner(); let env_region = match goal_kind { @@ -454,7 +454,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_async_fn_kind_helper_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let [ closure_fn_kind_ty, goal_kind_ty, @@ -501,14 +501,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_tuple_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`Tuple` does not have an associated type: {:?}", goal); } fn consider_builtin_pointee_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = ecx.interner(); let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); assert_eq!(metadata_def_id, goal.predicate.def_id()); @@ -590,7 +590,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_future_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); let ty::Coroutine(def_id, args) = *self_ty.kind() else { return Err(NoSolution); @@ -626,7 +626,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); let ty::Coroutine(def_id, args) = *self_ty.kind() else { return Err(NoSolution); @@ -662,14 +662,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_fused_iterator_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`FusedIterator` does not have an associated type: {:?}", goal); } fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); let ty::Coroutine(def_id, args) = *self_ty.kind() else { return Err(NoSolution); @@ -705,7 +705,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_coroutine_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); let ty::Coroutine(def_id, args) = *self_ty.kind() else { return Err(NoSolution); @@ -753,14 +753,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_structural_builtin_unsize_candidates( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Vec> { + ) -> Vec>> { bug!("`Unsize` does not have an associated type: {:?}", goal); } fn consider_builtin_discriminant_kind_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); let discriminant_ty = match *self_ty.kind() { ty::Bool @@ -812,7 +812,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_async_destruct_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); let async_destructor_ty = match *self_ty.kind() { ty::Bool @@ -865,14 +865,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_destruct_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`Destruct` does not have an associated type: {:?}", goal); } fn consider_builtin_transmute_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index a741f488901..5cff34c09c8 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -39,7 +39,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, TraitPredicate<'tcx>>, impl_def_id: DefId, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = ecx.interner(); let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); @@ -94,7 +94,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_error_guaranteed_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, _guar: ErrorGuaranteed, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { // FIXME: don't need to enter a probe here. ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) @@ -106,7 +106,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if let Some(trait_clause) = assumption.as_trait_clause() { if trait_clause.def_id() == goal.predicate.def_id() && trait_clause.polarity() == goal.predicate.polarity @@ -131,7 +131,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -174,7 +174,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_trait_alias_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -197,7 +197,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -212,7 +212,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -227,7 +227,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_pointer_like_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -257,7 +257,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_fn_ptr_trait_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); match goal.predicate.polarity { // impl FnPtr for FnPtr {} @@ -289,7 +289,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -330,7 +330,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -380,7 +380,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_async_fn_kind_helper_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else { bug!(); }; @@ -407,7 +407,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -423,7 +423,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_pointee_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -435,7 +435,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_future_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -461,7 +461,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -487,7 +487,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_fused_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -511,7 +511,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -537,7 +537,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_coroutine_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -569,7 +569,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_discriminant_kind_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -582,7 +582,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_async_destruct_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -595,7 +595,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_destruct_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -611,7 +611,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_transmute_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -652,7 +652,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_structural_builtin_unsize_candidates( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Vec> { + ) -> Vec>> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return vec![]; } @@ -738,7 +738,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { a_region: ty::Region<'tcx>, b_data: &'tcx ty::List>, b_region: ty::Region<'tcx>, - ) -> Vec> { + ) -> Vec>> { let tcx = self.interner(); let Goal { predicate: (a_ty, _b_ty), .. } = goal; @@ -784,7 +784,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, b_data: &'tcx ty::List>, b_region: ty::Region<'tcx>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = self.interner(); let Goal { predicate: (a_ty, _), .. } = goal; @@ -826,7 +826,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { b_data: &'tcx ty::List>, b_region: ty::Region<'tcx>, upcast_principal: Option>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let param_env = goal.param_env; // We may upcast to auto traits that are either explicitly listed in @@ -929,7 +929,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, a_elem_ty: Ty<'tcx>, b_elem_ty: Ty<'tcx>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { self.eq(goal.param_env, a_elem_ty, b_elem_ty)?; self.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) @@ -954,7 +954,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { def: ty::AdtDef<'tcx>, a_args: ty::GenericArgsRef<'tcx>, b_args: ty::GenericArgsRef<'tcx>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = self.interner(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; @@ -1015,7 +1015,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, a_tys: &'tcx ty::List>, b_tys: &'tcx ty::List>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = self.interner(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; @@ -1050,7 +1050,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn disqualify_auto_trait_candidate_due_to_possible_impl( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, - ) -> Option, NoSolution>> { + ) -> Option>, NoSolution>> { let self_ty = goal.predicate.self_ty(); match *self_ty.kind() { // Stall int and float vars until they are resolved to a concrete @@ -1155,7 +1155,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &EvalCtxt<'_, InferCtxt<'tcx>>, Ty<'tcx>, ) -> Result>>, NoSolution>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { self.probe_trait_candidate(source).enter(|ecx| { ecx.add_goals( GoalSource::ImplWhereBound, -- cgit 1.4.1-3-g733a5 From c2e416c471123f7227506512ff191b6e15690674 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jun 2024 16:04:45 -0400 Subject: Make proof tree probing generic --- compiler/rustc_infer/src/infer/mod.rs | 4 ++ .../src/solve/eval_ctxt/probe.rs | 83 ++++++++++++---------- compiler/rustc_type_ir/src/infcx.rs | 2 + 3 files changed, 51 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index dcf415e720f..9447ea06fdd 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -471,6 +471,10 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { { self.resolve_vars_if_possible(value) } + + fn probe(&self, probe: impl FnOnce() -> T) -> T { + self.probe(|_| probe()) + } } /// See the `error_reporting` module for more details. diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs index 7b912e93dc8..ad6fdd2707d 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs @@ -1,27 +1,29 @@ use crate::solve::assembly::Candidate; use super::EvalCtxt; -use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::BuiltinImplSource; -use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::solve::{inspect, CandidateSource, QueryResult}; -use rustc_middle::ty::TyCtxt; +use rustc_next_trait_solver::solve::{ + inspect, BuiltinImplSource, CandidateSource, NoSolution, QueryResult, +}; +use rustc_type_ir::{InferCtxtLike, Interner}; use std::marker::PhantomData; -pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> { - ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>, +pub(in crate::solve) struct ProbeCtxt<'me, 'a, Infcx, I, F, T> +where + Infcx: InferCtxtLike, + I: Interner, +{ + ecx: &'me mut EvalCtxt<'a, Infcx, I>, probe_kind: F, _result: PhantomData, } -impl<'tcx, F, T> ProbeCtxt<'_, '_, 'tcx, F, T> +impl ProbeCtxt<'_, '_, Infcx, I, F, T> where - F: FnOnce(&T) -> inspect::ProbeKind>, + F: FnOnce(&T) -> inspect::ProbeKind, + Infcx: InferCtxtLike, + I: Interner, { - pub(in crate::solve) fn enter( - self, - f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> T, - ) -> T { + pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> T) -> T { let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self; let infcx = outer_ecx.infcx; @@ -38,7 +40,7 @@ where tainted: outer_ecx.tainted, inspect: outer_ecx.inspect.take_and_enter_probe(), }; - let r = nested_ecx.infcx.probe(|_| { + let r = nested_ecx.infcx.probe(|| { let r = f(&mut nested_ecx); nested_ecx.inspect.probe_final_state(infcx, max_input_universe); r @@ -52,30 +54,43 @@ where } } -pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, 'tcx, F> { - cx: ProbeCtxt<'me, 'a, 'tcx, F, QueryResult<'tcx>>, - source: CandidateSource<'tcx>, +pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, Infcx, I, F> +where + Infcx: InferCtxtLike, + I: Interner, +{ + cx: ProbeCtxt<'me, 'a, Infcx, I, F, QueryResult>, + source: CandidateSource, } -impl<'tcx, F> TraitProbeCtxt<'_, '_, 'tcx, F> +impl TraitProbeCtxt<'_, '_, Infcx, I, F> where - F: FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind>, + Infcx: InferCtxtLike, + I: Interner, + F: FnOnce(&QueryResult) -> inspect::ProbeKind, { #[instrument(level = "debug", skip_all, fields(source = ?self.source))] pub(in crate::solve) fn enter( self, - f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result>, NoSolution> { + f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult, + ) -> Result, NoSolution> { self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result }) } } -impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { +impl<'a, Infcx, I> EvalCtxt<'a, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ /// `probe_kind` is only called when proof tree building is enabled so it can be /// as expensive as necessary to output the desired information. - pub(in crate::solve) fn probe(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, 'tcx, F, T> + pub(in crate::solve) fn probe( + &mut self, + probe_kind: F, + ) -> ProbeCtxt<'_, 'a, Infcx, I, F, T> where - F: FnOnce(&T) -> inspect::ProbeKind>, + F: FnOnce(&T) -> inspect::ProbeKind, { ProbeCtxt { ecx: self, probe_kind, _result: PhantomData } } @@ -83,28 +98,20 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { pub(in crate::solve) fn probe_builtin_trait_candidate( &mut self, source: BuiltinImplSource, - ) -> TraitProbeCtxt< - '_, - 'a, - 'tcx, - impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind>, - > { + ) -> TraitProbeCtxt<'_, 'a, Infcx, I, impl FnOnce(&QueryResult) -> inspect::ProbeKind> + { self.probe_trait_candidate(CandidateSource::BuiltinImpl(source)) } pub(in crate::solve) fn probe_trait_candidate( &mut self, - source: CandidateSource<'tcx>, - ) -> TraitProbeCtxt< - '_, - 'a, - 'tcx, - impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind>, - > { + source: CandidateSource, + ) -> TraitProbeCtxt<'_, 'a, Infcx, I, impl FnOnce(&QueryResult) -> inspect::ProbeKind> + { TraitProbeCtxt { cx: ProbeCtxt { ecx: self, - probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::TraitCandidate { + probe_kind: move |result: &QueryResult| inspect::ProbeKind::TraitCandidate { source, result: *result, }, diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs index 92a717a0d9e..4a5f34e3542 100644 --- a/compiler/rustc_type_ir/src/infcx.rs +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -72,4 +72,6 @@ pub trait InferCtxtLike: Sized { fn resolve_vars_if_possible(&self, value: T) -> T where T: TypeFoldable; + + fn probe(&self, probe: impl FnOnce() -> T) -> T; } -- cgit 1.4.1-3-g733a5 From 416888f05b996f74eb696ed46c4eb3359a616f72 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Thu, 13 Jun 2024 11:59:22 -0700 Subject: Polish `std::path::absolute` documentation. These changes bring it closer to other standard library documentation and, in particular, `std::fs::canonicalize`, which it will often be compared with. * Add `# Platform-specific behavior` section, with content moved from Examples section. * Create `# Errors` section. * Phrase error description to allow future platforms to have new syntactic errors, rather than only emptiness. * Add missing commas. * Indent example code 4 spaces. --- library/std/src/fs.rs | 2 +- library/std/src/path.rs | 65 +++++++++++++++++++++++++++++-------------------- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 0dcf554770c..2132097fde4 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2302,7 +2302,7 @@ pub fn read_link>(path: P) -> io::Result { /// /// This function currently corresponds to the `realpath` function on Unix /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows. -/// Note that, this [may change in the future][changes]. +/// Note that this [may change in the future][changes]. /// /// On Windows, this converts the path to use [extended length path][path] /// syntax, which allows your program to use longer path names, but means you diff --git a/library/std/src/path.rs b/library/std/src/path.rs index adbcdcd2e67..7b8caaa2684 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3345,14 +3345,33 @@ impl Error for StripPrefixError { /// Makes the path absolute without accessing the filesystem. /// /// If the path is relative, the current directory is used as the base directory. -/// All intermediate components will be resolved according to platforms-specific -/// rules but unlike [`canonicalize`][crate::fs::canonicalize] this does not +/// All intermediate components will be resolved according to platform-specific +/// rules, but unlike [`canonicalize`][crate::fs::canonicalize], this does not /// resolve symlinks and may succeed even if the path does not exist. /// /// If the `path` is empty or getting the -/// [current directory][crate::env::current_dir] fails then an error will be +/// [current directory][crate::env::current_dir] fails, then an error will be /// returned. /// +/// # Platform-specific behavior +/// +/// On POSIX platforms, the path is resolved using [POSIX semantics][posix-semantics], +/// except that it stops short of resolving symlinks. This means it will keep `..` +/// components and trailing slashes. +/// +/// On Windows, for verbatim paths, this will simply return the path as given. For other +/// paths, this is currently equivalent to calling +/// [`GetFullPathNameW`][windows-path]. +/// +/// Note that these [may change in the future][changes]. +/// +/// # Errors +/// +/// This function may return an error in the following situations: +/// +/// * If `path` is syntactically invalid; in particular, if it is empty. +/// * If getting the [current directory][crate::env::current_dir] fails. +/// /// # Examples /// /// ## POSIX paths @@ -3360,50 +3379,42 @@ impl Error for StripPrefixError { /// ``` /// # #[cfg(unix)] /// fn main() -> std::io::Result<()> { -/// use std::path::{self, Path}; +/// use std::path::{self, Path}; /// -/// // Relative to absolute -/// let absolute = path::absolute("foo/./bar")?; -/// assert!(absolute.ends_with("foo/bar")); +/// // Relative to absolute +/// let absolute = path::absolute("foo/./bar")?; +/// assert!(absolute.ends_with("foo/bar")); /// -/// // Absolute to absolute -/// let absolute = path::absolute("/foo//test/.././bar.rs")?; -/// assert_eq!(absolute, Path::new("/foo/test/../bar.rs")); -/// Ok(()) +/// // Absolute to absolute +/// let absolute = path::absolute("/foo//test/.././bar.rs")?; +/// assert_eq!(absolute, Path::new("/foo/test/../bar.rs")); +/// Ok(()) /// } /// # #[cfg(not(unix))] /// # fn main() {} /// ``` /// -/// The path is resolved using [POSIX semantics][posix-semantics] except that -/// it stops short of resolving symlinks. This means it will keep `..` -/// components and trailing slashes. -/// /// ## Windows paths /// /// ``` /// # #[cfg(windows)] /// fn main() -> std::io::Result<()> { -/// use std::path::{self, Path}; +/// use std::path::{self, Path}; /// -/// // Relative to absolute -/// let absolute = path::absolute("foo/./bar")?; -/// assert!(absolute.ends_with(r"foo\bar")); +/// // Relative to absolute +/// let absolute = path::absolute("foo/./bar")?; +/// assert!(absolute.ends_with(r"foo\bar")); /// -/// // Absolute to absolute -/// let absolute = path::absolute(r"C:\foo//test\..\./bar.rs")?; +/// // Absolute to absolute +/// let absolute = path::absolute(r"C:\foo//test\..\./bar.rs")?; /// -/// assert_eq!(absolute, Path::new(r"C:\foo\bar.rs")); -/// Ok(()) +/// assert_eq!(absolute, Path::new(r"C:\foo\bar.rs")); +/// Ok(()) /// } /// # #[cfg(not(windows))] /// # fn main() {} /// ``` /// -/// For verbatim paths this will simply return the path as given. For other -/// paths this is currently equivalent to calling -/// [`GetFullPathNameW`][windows-path]. -/// /// Note that this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior -- cgit 1.4.1-3-g733a5 From d5c48ebc71280cb523b23f9be25ef8a66916e75d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jun 2024 14:18:56 -0400 Subject: Add TyCtxt::is_lang_item --- compiler/rustc_middle/src/middle/lang_items.rs | 4 +++ compiler/rustc_monomorphize/src/collector.rs | 2 +- .../src/solve/assembly/mod.rs | 38 +++++++++++----------- .../src/solve/normalizes_to/mod.rs | 15 ++++----- .../rustc_trait_selection/src/solve/trait_goals.rs | 21 ++++++------ .../src/traits/select/confirmation.rs | 2 +- 6 files changed, 42 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 4fd1c1f4a1b..e76d7af6e4a 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -23,6 +23,10 @@ impl<'tcx> TyCtxt<'tcx> { }) } + pub fn is_lang_item(self, def_id: DefId, lang_item: LangItem) -> bool { + self.lang_items().get(lang_item) == Some(def_id) + } + /// Given a [`DefId`] of one of the [`Fn`], [`FnMut`] or [`FnOnce`] traits, /// returns a corresponding [`ty::ClosureKind`]. /// For any other [`DefId`] return `None`. diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 61680dbfaf5..43f92f8062d 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -945,7 +945,7 @@ fn visit_instance_use<'tcx>( // be lowered in codegen to nothing or a call to panic_nounwind. So if we encounter any // of those intrinsics, we need to include a mono item for panic_nounwind, else we may try to // codegen a call to that function without generating code for the function itself. - let def_id = tcx.lang_items().get(LangItem::PanicNounwind).unwrap(); + let def_id = tcx.require_lang_item(LangItem::PanicNounwind, None); let panic_instance = Instance::mono(tcx, def_id); if should_codegen_locally(tcx, panic_instance) { output.push(create_fn_mono_item(tcx, panic_instance, source)); diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index b51efd339c4..9c18366887b 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -1,6 +1,7 @@ //! Code shared by trait and projection goals for candidate assembly. use rustc_hir::def_id::DefId; +use rustc_hir::LangItem; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::bug; @@ -481,7 +482,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { candidates: &mut Vec>, ) { let tcx = self.interner(); - let lang_items = tcx.lang_items(); let trait_def_id = goal.predicate.trait_def_id(tcx); // N.B. When assembling built-in candidates for lang items that are also @@ -497,43 +497,43 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { G::consider_auto_trait_candidate(self, goal) } else if tcx.trait_is_alias(trait_def_id) { G::consider_trait_alias_candidate(self, goal) - } else if lang_items.sized_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Sized) { G::consider_builtin_sized_candidate(self, goal) - } else if lang_items.copy_trait() == Some(trait_def_id) - || lang_items.clone_trait() == Some(trait_def_id) + } else if tcx.is_lang_item(trait_def_id, LangItem::Copy) + || tcx.is_lang_item(trait_def_id, LangItem::Clone) { G::consider_builtin_copy_clone_candidate(self, goal) - } else if lang_items.pointer_like() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::PointerLike) { G::consider_builtin_pointer_like_candidate(self, goal) - } else if lang_items.fn_ptr_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::FnPtrTrait) { G::consider_builtin_fn_ptr_trait_candidate(self, goal) } else if let Some(kind) = self.interner().fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_fn_trait_candidates(self, goal, kind) } else if let Some(kind) = self.interner().async_fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_async_fn_trait_candidates(self, goal, kind) - } else if lang_items.async_fn_kind_helper() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncFnKindHelper) { G::consider_builtin_async_fn_kind_helper_candidate(self, goal) - } else if lang_items.tuple_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Tuple) { G::consider_builtin_tuple_candidate(self, goal) - } else if lang_items.pointee_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) { G::consider_builtin_pointee_candidate(self, goal) - } else if lang_items.future_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Future) { G::consider_builtin_future_candidate(self, goal) - } else if lang_items.iterator_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Iterator) { G::consider_builtin_iterator_candidate(self, goal) - } else if lang_items.fused_iterator_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::FusedIterator) { G::consider_builtin_fused_iterator_candidate(self, goal) - } else if lang_items.async_iterator_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncIterator) { G::consider_builtin_async_iterator_candidate(self, goal) - } else if lang_items.coroutine_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) { G::consider_builtin_coroutine_candidate(self, goal) - } else if lang_items.discriminant_kind_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) { G::consider_builtin_discriminant_kind_candidate(self, goal) - } else if lang_items.async_destruct_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncDestruct) { G::consider_builtin_async_destruct_candidate(self, goal) - } else if lang_items.destruct_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Destruct) { G::consider_builtin_destruct_candidate(self, goal) - } else if lang_items.transmute_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::TransmuteTrait) { G::consider_builtin_transmute_candidate(self, goal) } else { Err(NoSolution) @@ -543,7 +543,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // There may be multiple unsize candidates for a trait with several supertraits: // `trait Foo: Bar + Bar` and `dyn Foo: Unsize>` - if lang_items.unsize_trait() == Some(trait_def_id) { + if tcx.is_lang_item(trait_def_id, LangItem::Unsize) { candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal)); } } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 50253d81528..a7fac5fc3ba 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -392,9 +392,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { output_coroutine_ty, coroutine_return_ty, }| { - let lang_items = tcx.lang_items(); - let (projection_term, term) = if Some(goal.predicate.def_id()) - == lang_items.call_once_future() + let (projection_term, term) = if tcx + .is_lang_item(goal.predicate.def_id(), LangItem::CallOnceFuture) { ( ty::AliasTerm::new( @@ -404,7 +403,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ), output_coroutine_ty.into(), ) - } else if Some(goal.predicate.def_id()) == lang_items.call_ref_future() { + } else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CallRefFuture) { ( ty::AliasTerm::new( tcx, @@ -417,7 +416,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ), output_coroutine_ty.into(), ) - } else if Some(goal.predicate.def_id()) == lang_items.async_fn_once_output() { + } else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::AsyncFnOnceOutput) + { ( ty::AliasTerm::new( tcx, @@ -719,10 +719,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { let coroutine = args.as_coroutine(); - let lang_items = tcx.lang_items(); - let term = if Some(goal.predicate.def_id()) == lang_items.coroutine_return() { + let term = if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CoroutineReturn) { coroutine.return_ty().into() - } else if Some(goal.predicate.def_id()) == lang_items.coroutine_yield() { + } else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CoroutineYield) { coroutine.yield_ty().into() } else { bug!( diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index a741f488901..f631a21a82c 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -802,14 +802,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ); // The type must be `Sized` to be unsized. - if let Some(sized_def_id) = tcx.lang_items().sized_trait() { - ecx.add_goal( - GoalSource::ImplWhereBound, - goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])), - ); - } else { - return Err(NoSolution); - } + ecx.add_goal( + GoalSource::ImplWhereBound, + goal.with( + tcx, + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [a_ty]), + ), + ); // The type must outlive the lifetime of the `dyn` we're unsizing into. ecx.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region))); @@ -991,7 +990,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { tcx, ty::TraitRef::new( tcx, - tcx.lang_items().unsize_trait().unwrap(), + tcx.require_lang_item(LangItem::Unsize, None), [a_tail_ty, b_tail_ty], ), ), @@ -1034,7 +1033,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { tcx, ty::TraitRef::new( tcx, - tcx.lang_items().unsize_trait().unwrap(), + tcx.require_lang_item(LangItem::Unsize, None), [a_last_ty, b_last_ty], ), ), @@ -1076,7 +1075,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // takes precedence over the structural auto trait candidate being // assembled. ty::Coroutine(def_id, _) - if Some(goal.predicate.def_id()) == self.interner().lang_items().unpin_trait() => + if self.interner().is_lang_item(goal.predicate.def_id(), LangItem::Unpin) => { match self.interner().coroutine_movability(def_id) { Movability::Static => Some(Err(NoSolution)), diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 749081006f3..08524f625fe 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -338,7 +338,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let make_freeze_obl = |ty| { let trait_ref = ty::TraitRef::new( tcx, - tcx.lang_items().freeze_trait().unwrap(), + tcx.require_lang_item(LangItem::Freeze, None), [ty::GenericArg::from(ty)], ); Obligation::with_depth( -- cgit 1.4.1-3-g733a5 From 93ff86ed7c38b68644964d80155cff5e04bd5f42 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jun 2024 14:46:32 -0400 Subject: Use is_lang_item more aggressively --- .../src/diagnostics/conflict_errors.rs | 11 +++--- compiler/rustc_borrowck/src/diagnostics/mod.rs | 17 +++++---- compiler/rustc_codegen_cranelift/src/inline_asm.rs | 3 +- .../rustc_const_eval/src/check_consts/check.rs | 6 ++-- compiler/rustc_const_eval/src/check_consts/ops.rs | 2 +- .../rustc_const_eval/src/const_eval/machine.rs | 6 ++-- compiler/rustc_hir_analysis/src/bounds.rs | 2 +- .../rustc_hir_analysis/src/check/intrinsicck.rs | 4 +-- compiler/rustc_hir_analysis/src/coherence/mod.rs | 5 +-- compiler/rustc_hir_typeck/src/callee.rs | 4 +-- compiler/rustc_hir_typeck/src/expr.rs | 2 +- .../rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 4 +-- compiler/rustc_hir_typeck/src/method/suggest.rs | 8 ++--- compiler/rustc_hir_typeck/src/pat.rs | 4 +-- .../rustc_lint/src/deref_into_dyn_supertrait.rs | 4 +-- compiler/rustc_lint/src/non_fmt_panic.rs | 8 ++--- compiler/rustc_lint/src/traits.rs | 4 +-- compiler/rustc_lint/src/unused.rs | 4 +-- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_middle/src/ty/adt.rs | 10 +++--- compiler/rustc_middle/src/ty/instance.rs | 9 +++-- compiler/rustc_middle/src/ty/layout.rs | 5 +-- compiler/rustc_middle/src/ty/print/pretty.rs | 6 ++-- compiler/rustc_middle/src/util/call_kind.rs | 8 ++--- .../rustc_mir_build/src/build/expr/as_constant.rs | 3 +- compiler/rustc_mir_build/src/build/matches/test.rs | 2 +- compiler/rustc_mir_build/src/thir/constant.rs | 3 +- compiler/rustc_mir_dataflow/src/elaborate_drops.rs | 3 +- compiler/rustc_mir_transform/src/add_retag.rs | 3 +- .../src/shim/async_destructor_ctor.rs | 2 +- compiler/rustc_mir_transform/src/sroa.rs | 3 +- compiler/rustc_mir_transform/src/validate.rs | 3 +- compiler/rustc_monomorphize/src/collector.rs | 2 +- compiler/rustc_monomorphize/src/partitioning.rs | 3 +- .../src/cfi/typeid/itanium_cxx_abi/transform.rs | 2 +- compiler/rustc_smir/src/rustc_smir/context.rs | 3 +- .../src/traits/error_reporting/suggestions.rs | 14 ++++---- .../traits/error_reporting/type_err_ctxt_ext.rs | 26 +++++++------- .../rustc_trait_selection/src/traits/project.rs | 35 +++++++++---------- .../src/traits/query/dropck_outlives.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 40 +++++++++++----------- .../src/traits/select/confirmation.rs | 12 +++---- .../rustc_trait_selection/src/traits/select/mod.rs | 26 +++++++------- compiler/rustc_ty_utils/src/instance.rs | 12 +++---- 44 files changed, 171 insertions(+), 166 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8200a58f31f..9252bec6e4e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -284,7 +284,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { && let CallKind::FnCall { fn_trait_id, self_ty } = kind && let ty::Param(_) = self_ty.kind() && ty == self_ty - && Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() + && self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce) { // this is a type parameter `T: FnOnce()`, don't suggest `T: FnOnce() + Clone`. true @@ -708,9 +708,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() && pred.self_ty() == ty { - if Some(pred.def_id()) == tcx.lang_items().fn_trait() { + if tcx.is_lang_item(pred.def_id(), LangItem::Fn) { return Some(hir::Mutability::Not); - } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() { + } else if tcx.is_lang_item(pred.def_id(), LangItem::FnMut) { return Some(hir::Mutability::Mut); } } @@ -1832,7 +1832,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let hir::ExprKind::MethodCall(..) = ex.kind && let Some(method_def_id) = self.typeck_results.type_dependent_def_id(ex.hir_id) - && self.tcx.lang_items().clone_trait() == Some(self.tcx.parent(method_def_id)) + && self.tcx.is_lang_item(self.tcx.parent(method_def_id), LangItem::Clone) { self.clones.push(ex); } @@ -3159,8 +3159,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let is_format_arguments_item = if let Some(expr_ty) = expr_ty && let ty::Adt(adt, _) = expr_ty.kind() { - self.infcx.tcx.lang_items().get(LangItem::FormatArguments) - == Some(adt.did()) + self.infcx.tcx.is_lang_item(adt.did(), LangItem::FormatArguments) } else { false }; diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 1eb67ea367c..abb0b5afbd8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -6,9 +6,9 @@ use crate::session_diagnostics::{ }; use rustc_errors::{Applicability, Diag}; use rustc_errors::{DiagCtxt, MultiSpan}; -use rustc_hir as hir; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::CoroutineKind; +use rustc_hir::{self as hir, LangItem}; use rustc_index::IndexSlice; use rustc_infer::infer::BoundRegionConversionTime; use rustc_infer::traits::SelectionError; @@ -116,7 +116,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { { if let ty::FnDef(id, _) = *const_.ty().kind() { debug!("add_moved_or_invoked_closure_note: id={:?}", id); - if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() { + if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) { let closure = match args.first() { Some(Spanned { node: Operand::Copy(place) | Operand::Move(place), .. @@ -767,13 +767,12 @@ impl<'tcx> BorrowedContentSource<'tcx> { ty::FnDef(def_id, args) => { let trait_id = tcx.trait_of_item(def_id)?; - let lang_items = tcx.lang_items(); - if Some(trait_id) == lang_items.deref_trait() - || Some(trait_id) == lang_items.deref_mut_trait() + if tcx.is_lang_item(trait_id, LangItem::Deref) + || tcx.is_lang_item(trait_id, LangItem::DerefMut) { Some(BorrowedContentSource::OverloadedDeref(args.type_at(0))) - } else if Some(trait_id) == lang_items.index_trait() - || Some(trait_id) == lang_items.index_mut_trait() + } else if tcx.is_lang_item(trait_id, LangItem::Index) + || tcx.is_lang_item(trait_id, LangItem::IndexMut) { Some(BorrowedContentSource::OverloadedIndex(args.type_at(0))) } else { @@ -1041,7 +1040,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .unwrap_or_else(|| "value".to_owned()); match kind { CallKind::FnCall { fn_trait_id, self_ty } - if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() => + if self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce) => { err.subdiagnostic( self.dcx(), @@ -1268,7 +1267,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let ty = moved_place.ty(self.body, tcx).ty; if let ty::Adt(def, args) = ty.peel_refs().kind() - && Some(def.did()) == tcx.lang_items().pin_type() + && tcx.is_lang_item(def.did(), LangItem::Pin) && let ty::Ref(_, _, hir::Mutability::Mut) = args.type_at(0).kind() && let self_ty = self.infcx.instantiate_binder_with_fresh_vars( fn_call_span, diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 2de804f5e04..c6b26dd873b 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -4,6 +4,7 @@ use std::fmt::Write; use cranelift_codegen::isa::CallConv; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_hir::LangItem; use rustc_span::sym; use rustc_target::asm::*; use target_lexicon::BinaryFormat; @@ -927,7 +928,7 @@ fn call_inline_asm<'tcx>( fn asm_clif_type<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Option { match ty.kind() { // Adapted from https://github.com/rust-lang/rust/blob/f3c66088610c1b80110297c2d9a8b5f9265b013f/compiler/rustc_hir_analysis/src/check/intrinsicck.rs#L136-L151 - ty::Adt(adt, args) if Some(adt.did()) == fx.tcx.lang_items().maybe_uninit() => { + ty::Adt(adt, args) if fx.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => { let fields = &adt.non_enum_variant().fields; let ty = fields[FieldIdx::from_u32(1)].ty(fx.tcx, args); let ty::Adt(ty, args) = ty.kind() else { diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 9e01c59a96f..0818d9425e2 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -1,8 +1,8 @@ //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. use rustc_errors::{Diag, ErrorGuaranteed}; -use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, LangItem}; use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::ObligationCause; @@ -801,7 +801,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // const-eval. // const-eval of the `begin_panic` fn assumes the argument is `&str` - if Some(callee) == tcx.lang_items().begin_panic_fn() { + if tcx.is_lang_item(callee, LangItem::BeginPanic) { match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() { ty::Ref(_, ty, _) if ty.is_str() => return, _ => self.check_op(ops::PanicNonStr), @@ -819,7 +819,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } - if Some(callee) == tcx.lang_items().exchange_malloc_fn() { + if tcx.is_lang_item(callee, LangItem::ExchangeMalloc) { self.check_op(ops::HeapAllocation); return; } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index feab5b929ac..eb9a83fb9cf 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -218,7 +218,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { } else { let mut sugg = None; - if Some(trait_id) == ccx.tcx.lang_items().eq_trait() { + if ccx.tcx.is_lang_item(trait_id, LangItem::PartialEq) { match (args[0].unpack(), args[1].unpack()) { (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) if self_ty == rhs_ty diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 4f6df857142..d3631e0d723 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -230,7 +230,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { let def_id = instance.def_id(); if self.tcx.has_attr(def_id, sym::rustc_const_panic_str) - || Some(def_id) == self.tcx.lang_items().begin_panic_fn() + || self.tcx.is_lang_item(def_id, LangItem::BeginPanic) { let args = self.copy_fn_args(args); // &str or &&str @@ -245,7 +245,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { let span = self.find_closest_untracked_caller_location(); let (file, line, col) = self.location_triple_for_span(span); return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()); - } else if Some(def_id) == self.tcx.lang_items().panic_fmt() { + } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) { // For panic_fmt, call const_panic_fmt instead. let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None); let new_instance = ty::Instance::expect_resolve( @@ -256,7 +256,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { ); return Ok(Some(new_instance)); - } else if Some(def_id) == self.tcx.lang_items().align_offset_fn() { + } else if self.tcx.is_lang_item(def_id, LangItem::AlignOffset) { let args = self.copy_fn_args(args); // For align_offset, we replace the function call if the pointer has no address. match self.align_offset(instance, &args, dest, ret)? { diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 38ecd7dd082..7f0d72b3a8d 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -53,7 +53,7 @@ impl<'tcx> Bounds<'tcx> { span, ); // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands. - if tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { + if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) { self.clauses.insert(0, clause); } else { self.clauses.push(clause); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 2672614a895..5e62a5ced19 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -1,6 +1,6 @@ use rustc_ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxIndexSet; -use rustc_hir as hir; +use rustc_hir::{self as hir, LangItem}; use rustc_middle::bug; use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy}; use rustc_session::lint; @@ -134,7 +134,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // `!` is allowed for input but not for output (issue #87802) ty::Never if is_input => return None, _ if ty.references_error() => return None, - ty::Adt(adt, args) if Some(adt.did()) == self.tcx.lang_items().maybe_uninit() => { + ty::Adt(adt, args) if self.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => { let fields = &adt.non_enum_variant().fields; let ty = fields[FieldIdx::from_u32(1)].ty(self.tcx, args); // FIXME: Are we just trying to map to the `T` in `MaybeUninit`? diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index eae41d28e89..e9961d3ad08 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -8,6 +8,7 @@ use crate::errors; use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::LangItem; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_session::parse::feature_err; @@ -49,7 +50,7 @@ fn enforce_trait_manually_implementable( ) -> Result<(), ErrorGuaranteed> { let impl_header_span = tcx.def_span(impl_def_id); - if tcx.lang_items().freeze_trait() == Some(trait_def_id) { + if tcx.is_lang_item(trait_def_id, LangItem::Freeze) { if !tcx.features().freeze_impls { feature_err( &tcx.sess, @@ -75,7 +76,7 @@ fn enforce_trait_manually_implementable( // Maintain explicit error code for `Unsize`, since it has a useful // explanation about using `CoerceUnsized` instead. - if Some(trait_def_id) == tcx.lang_items().unsize_trait() { + if tcx.is_lang_item(trait_def_id, LangItem::Unsize) { err.code(E0328); } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 93222c18686..46c85515575 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -5,9 +5,9 @@ use super::{Expectation, FnCtxt, TupleArgumentsFlag}; use crate::errors; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey}; -use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, Namespace, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, LangItem}; use rustc_hir_analysis::autoderef::Autoderef; use rustc_infer::traits::ObligationCauseCode; use rustc_infer::{ @@ -41,7 +41,7 @@ pub fn check_legal_trait_for_method_call( trait_id: DefId, body_id: DefId, ) -> Result<(), ErrorGuaranteed> { - if tcx.lang_items().drop_trait() == Some(trait_id) + if tcx.is_lang_item(trait_id, LangItem::Drop) && tcx.lang_items().fallback_surface_drop_fn() != Some(body_id) { let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index c4e55d564a0..fe497498c4b 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3150,7 +3150,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error.obligation.predicate.kind().skip_binder(), ) { (ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)), _) - if self.tcx.lang_items().index_trait() == Some(predicate.trait_ref.def_id) => + if self.tcx.is_lang_item(predicate.trait_ref.def_id, LangItem::Index) => { seen_preds.insert(error.obligation.predicate.kind().skip_binder()); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 8a88e5a6ff4..9743dc7c69f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -489,7 +489,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); return true; } else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind() - && Some(adt.did()) == self.tcx.lang_items().string() + && self.tcx.is_lang_item(adt.did(), LangItem::String) && peeled.is_str() // `Result::map`, conversely, does not take ref of the error type. && error_tys.is_none_or(|(found, expected)| { @@ -3147,7 +3147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } if let ty::Adt(adt, _) = expected_ty.kind() - && self.tcx.lang_items().range_struct() == Some(adt.did()) + && self.tcx.is_lang_item(adt.did(), LangItem::Range) { return; } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 28d738c11c8..abbfe452f5f 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1102,7 +1102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unsatisfied_predicates.iter().any(|(pred, _, _)| { match pred.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { - Some(pred.def_id()) == self.tcx.lang_items().sized_trait() + self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) && pred.polarity == ty::PredicatePolarity::Positive } _ => false, @@ -1375,10 +1375,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty.is_str() || matches!( ty.kind(), - ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string() + ty::Adt(adt, _) if self.tcx.is_lang_item(adt.did(), LangItem::String) ) } - ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(), + ty::Adt(adt, _) => self.tcx.is_lang_item(adt.did(), LangItem::String), _ => false, }; if is_string_or_ref_str && item_name.name == sym::iter { @@ -2723,7 +2723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if tcx.is_diagnostic_item(sym::LocalKey, inner_id) { err.help("use `with` or `try_with` to access thread local storage"); - } else if Some(kind.did()) == tcx.lang_items().maybe_uninit() { + } else if tcx.is_lang_item(kind.did(), LangItem::MaybeUninit) { err.help(format!( "if this `{name}` has been initialized, \ use one of the `assume_init` methods to access the inner value" diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 220556fe256..aaf3d3ec34d 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -7,7 +7,7 @@ use rustc_errors::{ }; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; -use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, Pat, PatKind}; +use rustc_hir::{self as hir, BindingMode, ByRef, HirId, LangItem, Mutability, Pat, PatKind}; use rustc_infer::infer; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; @@ -491,7 +491,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; let expected = self.resolve_vars_if_possible(expected); pat_ty = match expected.kind() { - ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => expected, + ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => expected, ty::Str => Ty::new_static_str(tcx), _ => pat_ty, }; diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index b671dfaa0d1..911975f6179 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -3,7 +3,7 @@ use crate::{ LateContext, LateLintPass, LintContext, }; -use rustc_hir as hir; +use rustc_hir::{self as hir, LangItem}; use rustc_middle::ty; use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::{declare_lint, declare_lint_pass}; @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { // the trait is a `Deref` implementation && let Some(trait_) = &impl_.of_trait && let Some(did) = trait_.trait_def_id() - && Some(did) == tcx.lang_items().deref_trait() + && tcx.is_lang_item(did, LangItem::Deref) // the self type is `dyn t_principal` && let self_ty = tcx.type_of(item.owner_id).instantiate_identity() && let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind() diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index c9d67854112..2dc2a0efdf0 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -2,7 +2,7 @@ use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused}; use crate::{fluent_generated as fluent, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::{self as hir, LangItem}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::lint::in_external_macro; @@ -53,8 +53,8 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt { if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() { let f_diagnostic_name = cx.tcx.get_diagnostic_name(def_id); - if Some(def_id) == cx.tcx.lang_items().begin_panic_fn() - || Some(def_id) == cx.tcx.lang_items().panic_fn() + if cx.tcx.is_lang_item(def_id, LangItem::BeginPanic) + || cx.tcx.is_lang_item(def_id, LangItem::Panic) || f_diagnostic_name == Some(sym::panic_str_2015) { if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id { @@ -153,7 +153,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc ty::Ref(_, r, _) if r.is_str(), ) || matches!( ty.ty_adt_def(), - Some(ty_def) if Some(ty_def.did()) == cx.tcx.lang_items().string(), + Some(ty_def) if cx.tcx.is_lang_item(ty_def.did(), LangItem::String), ); let infcx = cx.tcx.infer_ctxt().build(); diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 4d1b1dc4fb7..6983e7abbd6 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -2,7 +2,7 @@ use crate::lints::{DropGlue, DropTraitConstraintsDiag}; use crate::LateContext; use crate::LateLintPass; use crate::LintContext; -use rustc_hir as hir; +use rustc_hir::{self as hir, LangItem}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::symbol::sym; @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { continue; }; let def_id = trait_predicate.trait_ref.def_id; - if cx.tcx.lang_items().drop_trait() == Some(def_id) { + if cx.tcx.is_lang_item(def_id, LangItem::Drop) { // Explicitly allow `impl Drop`, a drop-guards-as-unnameable-type pattern. if trait_predicate.trait_ref.self_ty().is_impl_trait() { continue; diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index c8da9f179e7..7a1aa4043be 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -10,9 +10,9 @@ use rustc_ast as ast; use rustc_ast::util::{classify, parser}; use rustc_ast::{ExprKind, StmtKind}; use rustc_errors::{pluralize, MultiSpan}; -use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, LangItem}; use rustc_infer::traits::util::elaborate; use rustc_middle::ty::adjustment; use rustc_middle::ty::{self, Ty}; @@ -289,7 +289,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { is_ty_must_use(cx, boxed_ty, expr, span) .map(|inner| MustUsePath::Boxed(Box::new(inner))) } - ty::Adt(def, args) if cx.tcx.lang_items().pin_type() == Some(def.did()) => { + ty::Adt(def, args) if cx.tcx.is_lang_item(def.did(), LangItem::Pin) => { let pinned_ty = args.type_at(0); is_ty_must_use(cx, pinned_ty, expr, span) .map(|inner| MustUsePath::Pinned(Box::new(inner))) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 89da0df8575..d7840a2d516 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2020,7 +2020,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // if this is an impl of `CoerceUnsized`, create its // "unsized info", else just store None - if Some(trait_ref.def_id) == tcx.lang_items().coerce_unsized_trait() { + if tcx.is_lang_item(trait_ref.def_id, LangItem::CoerceUnsized) { let coerce_unsized_info = tcx.coerce_unsized_info(def_id).unwrap(); record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info); } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index a89ebe46c37..684b3233cfd 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -8,9 +8,9 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::HashingControls; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, LangItem}; use rustc_index::{IndexSlice, IndexVec}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::ich::StableHashingContext; @@ -274,16 +274,16 @@ impl AdtDefData { if tcx.has_attr(did, sym::fundamental) { flags |= AdtFlags::IS_FUNDAMENTAL; } - if Some(did) == tcx.lang_items().phantom_data() { + if tcx.is_lang_item(did, LangItem::PhantomData) { flags |= AdtFlags::IS_PHANTOM_DATA; } - if Some(did) == tcx.lang_items().owned_box() { + if tcx.is_lang_item(did, LangItem::OwnedBox) { flags |= AdtFlags::IS_BOX; } - if Some(did) == tcx.lang_items().manually_drop() { + if tcx.is_lang_item(did, LangItem::ManuallyDrop) { flags |= AdtFlags::IS_MANUALLY_DROP; } - if Some(did) == tcx.lang_items().unsafe_cell_type() { + if tcx.is_lang_item(did, LangItem::UnsafeCell) { flags |= AdtFlags::IS_UNSAFE_CELL; } if is_anonymous { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index a887047f62f..bdf90cbb25b 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -699,26 +699,25 @@ impl<'tcx> Instance<'tcx> { }; let coroutine_kind = tcx.coroutine_kind(coroutine_def_id).unwrap(); - let lang_items = tcx.lang_items(); - let coroutine_callable_item = if Some(trait_id) == lang_items.future_trait() { + let coroutine_callable_item = if tcx.is_lang_item(trait_id, LangItem::Future) { assert_matches!( coroutine_kind, hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) ); hir::LangItem::FuturePoll - } else if Some(trait_id) == lang_items.iterator_trait() { + } else if tcx.is_lang_item(trait_id, LangItem::Iterator) { assert_matches!( coroutine_kind, hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) ); hir::LangItem::IteratorNext - } else if Some(trait_id) == lang_items.async_iterator_trait() { + } else if tcx.is_lang_item(trait_id, LangItem::AsyncIterator) { assert_matches!( coroutine_kind, hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) ); hir::LangItem::AsyncIteratorPollNext - } else if Some(trait_id) == lang_items.coroutine_trait() { + } else if tcx.is_lang_item(trait_id, LangItem::Coroutine) { assert_matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_)); hir::LangItem::CoroutineResume } else { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 56945bf6be4..02c0d41f619 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -9,6 +9,7 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::LangItem; use rustc_index::IndexVec; use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable}; use rustc_session::config::OptLevel; @@ -850,7 +851,7 @@ where // and we rely on this layout information to trigger a panic in // `std::mem::uninitialized::<&dyn Trait>()`, for example. if let ty::Adt(def, args) = metadata.kind() - && Some(def.did()) == tcx.lang_items().dyn_metadata() + && tcx.is_lang_item(def.did(), LangItem::DynMetadata) && let ty::Dynamic(data, _, ty::Dyn) = args.type_at(0).kind() { mk_dyn_vtable(data.principal()) @@ -1169,7 +1170,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: SpecAbi) -> // This is not part of `codegen_fn_attrs` as it can differ between crates // and therefore cannot be computed in core. if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort { - if Some(did) == tcx.lang_items().drop_in_place_fn() { + if tcx.is_lang_item(did, LangItem::DropInPlace) { return false; } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 662eafd0ccb..de1796d4800 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -999,7 +999,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let trait_ref = bound_predicate.rebind(pred.trait_ref); // Don't print `+ Sized`, but rather `+ ?Sized` if absent. - if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { + if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) { match pred.polarity { ty::PredicatePolarity::Positive => { has_sized_bound = true; @@ -1254,14 +1254,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } entry.has_fn_once = true; return; - } else if Some(trait_def_id) == self.tcx().lang_items().fn_mut_trait() { + } else if self.tcx().is_lang_item(trait_def_id, LangItem::FnMut) { let super_trait_ref = supertraits_for_pretty_printing(self.tcx(), trait_ref) .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait) .unwrap(); fn_traits.entry(super_trait_ref).or_default().fn_mut_trait_ref = Some(trait_ref); return; - } else if Some(trait_def_id) == self.tcx().lang_items().fn_trait() { + } else if self.tcx().is_lang_item(trait_def_id, LangItem::Fn) { let super_trait_ref = supertraits_for_pretty_printing(self.tcx(), trait_ref) .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait) .unwrap(); diff --git a/compiler/rustc_middle/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs index a4cbfe86711..dc1d73684f4 100644 --- a/compiler/rustc_middle/src/util/call_kind.rs +++ b/compiler/rustc_middle/src/util/call_kind.rs @@ -117,19 +117,19 @@ pub fn call_kind<'tcx>( kind.unwrap_or_else(|| { // This isn't a 'special' use of `self` debug!(?method_did, ?fn_call_span); - let desugaring = if Some(method_did) == tcx.lang_items().into_iter_fn() + let desugaring = if tcx.is_lang_item(method_did, LangItem::IntoIterIntoIter) && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop) { Some((CallDesugaringKind::ForLoopIntoIter, method_args.type_at(0))) } else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) { - if Some(method_did) == tcx.lang_items().branch_fn() { + if tcx.is_lang_item(method_did, LangItem::TryTraitBranch) { Some((CallDesugaringKind::QuestionBranch, method_args.type_at(0))) - } else if Some(method_did) == tcx.lang_items().from_residual_fn() { + } else if tcx.is_lang_item(method_did, LangItem::TryTraitFromResidual) { Some((CallDesugaringKind::QuestionFromResidual, method_args.type_at(0))) } else { None } - } else if Some(method_did) == tcx.lang_items().from_output_fn() + } else if tcx.is_lang_item(method_did, LangItem::TryTraitFromOutput) && fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock) { Some((CallDesugaringKind::TryBlockFromOutput, method_args.type_at(0))) diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index b783eba8c4e..3b69058d3cb 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -2,6 +2,7 @@ use crate::build::{parse_float_into_constval, Builder}; use rustc_ast as ast; +use rustc_hir::LangItem; use rustc_middle::mir; use rustc_middle::mir::interpret::{Allocation, LitToConstError, LitToConstInput, Scalar}; use rustc_middle::mir::*; @@ -142,7 +143,7 @@ fn lit_to_mir_constant<'tcx>( let id = tcx.allocate_bytes(data); ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx)) } - (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().c_str()) => + (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => { let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]); let allocation = tcx.mk_const_alloc(allocation); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 2040071e76e..11d3e2a8180 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -141,7 +141,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let success_block = target_block(TestBranch::Success); let fail_block = target_block(TestBranch::Failure); if let ty::Adt(def, _) = ty.kind() - && Some(def.did()) == tcx.lang_items().string() + && tcx.is_lang_item(def.did(), LangItem::String) { if !tcx.features().string_deref_patterns { bug!( diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index a98e046d4dc..7b94867114d 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -1,4 +1,5 @@ use rustc_ast as ast; +use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt}; @@ -46,7 +47,7 @@ pub(crate) fn lit_to_const<'tcx>( (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { ty::ValTree::from_scalar_int((*n).into()) } - (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().c_str()) => + (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => { let bytes = data as &[u8]; ty::ValTree::from_raw_bytes(tcx, bytes) diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index bdc59e84356..654020164db 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -454,8 +454,7 @@ where }); } - let skip_contents = - adt.is_union() || Some(adt.did()) == self.tcx().lang_items().manually_drop(); + let skip_contents = adt.is_union() || adt.is_manually_drop(); let contents_drop = if skip_contents { (self.succ, self.unwind) } else { diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index f880476cec2..16977a63c59 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -4,6 +4,7 @@ //! of MIR building, and only after this pass we think of the program has having the //! normal MIR semantics. +use rustc_hir::LangItem; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -27,7 +28,7 @@ fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> b // References and Boxes (`noalias` sources) ty::Ref(..) => true, ty::Adt(..) if ty.is_box() => true, - ty::Adt(adt, _) if Some(adt.did()) == tcx.lang_items().ptr_unique() => true, + ty::Adt(adt, _) if tcx.is_lang_item(adt.did(), LangItem::PtrUnique) => true, // Compound types: recurse ty::Array(ty, _) | ty::Slice(ty) => { // This does not branch so we keep the depth the same. diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index aa9c87d8f80..41643f20285 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -561,7 +561,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { // If projection of Discriminant then compare with `Ty::discriminant_ty` if let ty::Alias(ty::Projection, ty::AliasTy { args, def_id, .. }) = expected_ty.kind() - && Some(*def_id) == self.tcx.lang_items().discriminant_type() + && self.tcx.is_lang_item(*def_id, LangItem::Discriminant) && args.first().unwrap().as_type().unwrap().discriminant_ty(self.tcx) == operand_ty { return; diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index f19c34cae7a..c2108795372 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -1,4 +1,5 @@ use rustc_data_structures::flat_map_in_place::FlatMapInPlace; +use rustc_hir::LangItem; use rustc_index::bit_set::{BitSet, GrowableBitSet}; use rustc_index::IndexVec; use rustc_middle::bug; @@ -70,7 +71,7 @@ fn escaping_locals<'tcx>( // Exclude #[repr(simd)] types so that they are not de-optimized into an array return true; } - if Some(def.did()) == tcx.lang_items().dyn_metadata() { + if tcx.is_lang_item(def.did(), LangItem::DynMetadata) { // codegen wants to see the `DynMetadata`, // not the inner reference-to-opaque-type. return true; diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 586c1254995..ea23bbc2a38 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1,6 +1,7 @@ //! Validates the MIR to ensure that invariants are upheld. use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir::LangItem; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_infer::traits::Reveal; @@ -689,7 +690,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } ty::Adt(adt_def, args) => { // see - if Some(adt_def.did()) == self.tcx.lang_items().dyn_metadata() { + if self.tcx.is_lang_item(adt_def.did(), LangItem::DynMetadata) { self.fail( location, format!( diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 43f92f8062d..eb71eeac501 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -593,7 +593,7 @@ fn check_recursion_limit<'tcx>( let recursion_depth = recursion_depths.get(&def_id).cloned().unwrap_or(0); debug!(" => recursion depth={}", recursion_depth); - let adjusted_recursion_depth = if Some(def_id) == tcx.lang_items().drop_in_place_fn() { + let adjusted_recursion_depth = if tcx.is_lang_item(def_id, LangItem::DropInPlace) { // HACK: drop_in_place creates tight monomorphization loops. Give // it more margin. recursion_depth / 4 diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 336341f4e74..14b5b22dc64 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -104,6 +104,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_hir::definitions::DefPathDataName; +use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; @@ -813,7 +814,7 @@ fn mono_item_visibility<'tcx>( // from the `main` symbol we'll generate later. // // This may be fixable with a new `InstanceDef` perhaps? Unsure! - if tcx.lang_items().start_fn() == Some(def_id) { + if tcx.is_lang_item(def_id, LangItem::Start) { *can_be_internalized = false; return Visibility::Hidden; } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 2fbfb93150e..2cb0c06e336 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -289,7 +289,7 @@ pub fn transform_instance<'tcx>( options: TransformTyOptions, ) -> Instance<'tcx> { if (matches!(instance.def, ty::InstanceDef::Virtual(..)) - && Some(instance.def_id()) == tcx.lang_items().drop_in_place_fn()) + && tcx.is_lang_item(instance.def_id(), LangItem::DropInPlace)) || matches!(instance.def, ty::InstanceDef::DropGlue(..)) { // Adjust the type ids of DropGlues diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index a8688c88601..981231694bb 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -6,6 +6,7 @@ #![allow(rustc::usage_of_qualified_ty)] use rustc_abi::HasDataLayout; +use rustc_hir::LangItem; use rustc_middle::ty::layout::{ FnAbiOf, FnAbiOfHelpers, HasParamEnv, HasTyCtxt, LayoutOf, LayoutOfHelpers, }; @@ -295,7 +296,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); - tables.tcx.lang_items().c_str() == Some(def_id) + tables.tcx.is_lang_item(def_id, LangItem::CStr) } fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 4604c132835..f632f1ad4f2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -794,7 +794,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = obligation.predicate.kind().skip_binder() - && Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait() + && self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized) { // Don't suggest calling to turn an unsized type into a sized type return false; @@ -1106,7 +1106,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .iter() .find_map(|pred| { if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() - && Some(proj.projection_term.def_id) == self.tcx.lang_items().fn_once_output() + && self.tcx.is_lang_item(proj.projection_term.def_id,LangItem::FnOnceOutput) // args tuple will always be args[1] && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind() { @@ -1123,7 +1123,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ty::Dynamic(data, _, ty::Dyn) => { data.iter().find_map(|pred| { if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() - && Some(proj.def_id) == self.tcx.lang_items().fn_once_output() + && self.tcx.is_lang_item(proj.def_id, LangItem::FnOnceOutput) // for existential projection, args are shifted over by 1 && let ty::Tuple(args) = proj.args.type_at(0).kind() { @@ -1150,7 +1150,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; param_env.caller_bounds().iter().find_map(|pred| { if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() - && Some(proj.projection_term.def_id) == self.tcx.lang_items().fn_once_output() + && self.tcx.is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput) && proj.projection_term.self_ty() == found // args tuple will always be args[1] && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind() @@ -1822,7 +1822,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && box_path .res .opt_def_id() - .is_some_and(|def_id| Some(def_id) == self.tcx.lang_items().owned_box()) + .is_some_and(|def_id| self.tcx.is_lang_item(def_id, LangItem::OwnedBox)) { // Don't box `Box::new` vec![] @@ -2737,7 +2737,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::ObjectTypeBound(..) => {} ObligationCauseCode::RustCall => { if let Some(pred) = predicate.as_trait_clause() - && Some(pred.def_id()) == tcx.lang_items().sized_trait() + && tcx.is_lang_item(pred.def_id(), LangItem::Sized) { err.note("argument required to be sized due to `extern \"rust-call\"` ABI"); } @@ -2790,7 +2790,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Check for foreign traits being reachable. tcx.visible_parent_map(()).get(&def_id).is_some() }; - if Some(def_id) == tcx.lang_items().sized_trait() { + if tcx.is_lang_item(def_id, LangItem::Sized) { // Check if this is an implicit bound, even in foreign crates. if tcx .generics_of(item_def_id) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index aef9d482bec..9cd69f54c12 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -24,10 +24,10 @@ use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart}; use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, StashKey}; -use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; +use rustc_hir::{self as hir, LangItem}; use rustc_hir::{GenericParam, Item, Node}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::{InferOk, TypeTrace}; @@ -118,7 +118,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // with more relevant type information and hide redundant E0282 errors. errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) - if Some(pred.def_id()) == self.tcx.lang_items().sized_trait() => + if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) => { 1 } @@ -513,7 +513,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let have_alt_message = message.is_some() || label.is_some(); let is_try_conversion = self.is_try_conversion(span, main_trait_ref.def_id()); let is_unsize = - Some(leaf_trait_ref.def_id()) == self.tcx.lang_items().unsize_trait(); + self.tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Unsize); let (message, notes, append_const_msg) = if is_try_conversion { ( Some(format!( @@ -586,14 +586,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); } - if Some(leaf_trait_ref.def_id()) == tcx.lang_items().tuple_trait() { + if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Tuple) { self.add_tuple_trait_message( obligation.cause.code().peel_derives(), &mut err, ); } - if Some(leaf_trait_ref.def_id()) == tcx.lang_items().drop_trait() + if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Drop) && predicate_is_const { err.note("`~const Drop` was renamed to `~const Destruct`"); @@ -648,7 +648,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if let ObligationCauseCode::Coercion { source, target } = *obligation.cause.code().peel_derives() { - if Some(leaf_trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { + if self.tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Sized) { self.suggest_borrowing_for_object_cast( &mut err, root_obligation, @@ -716,7 +716,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.suggest_remove_await(&obligation, &mut err); self.suggest_derive(&obligation, &mut err, leaf_trait_predicate); - if Some(leaf_trait_ref.def_id()) == tcx.lang_items().try_trait() { + if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Try) { self.suggest_await_before_try( &mut err, &obligation, @@ -1020,7 +1020,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // doesn't extend the goal kind. This is worth reporting, but we can only do so // if we actually know which closure this goal comes from, so look at the cause // to see if we can extract that information. - if Some(trait_ref.def_id()) == self.tcx.lang_items().async_fn_kind_helper() + if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::AsyncFnKindHelper) && let Some(found_kind) = trait_ref.skip_binder().args.type_at(0).to_opt_closure_kind() && let Some(expected_kind) = trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind() @@ -1744,7 +1744,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let self_ty = pred.projection_term.self_ty(); with_forced_trimmed_paths! { - if Some(pred.projection_term.def_id) == self.tcx.lang_items().fn_once_output() { + if self.tcx.is_lang_item(pred.projection_term.def_id,LangItem::FnOnceOutput) { let fn_kind = self_ty.prefix_string(self.tcx); let item = match self_ty.kind() { ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(), @@ -1754,7 +1754,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { "expected `{item}` to be a {fn_kind} that returns `{expected_ty}`, but it \ returns `{normalized_ty}`", )) - } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() { + } else if self.tcx.is_lang_item(trait_def_id, LangItem::Future) { Some(format!( "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \ resolves to `{normalized_ty}`" @@ -1783,7 +1783,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ty::Bool => Some(0), ty::Char => Some(1), ty::Str => Some(2), - ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => Some(2), + ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => Some(2), ty::Int(..) | ty::Uint(..) | ty::Float(..) @@ -2342,7 +2342,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // avoid inundating the user with unnecessary errors, but we now // check upstream for type errors and don't add the obligations to // begin with in those cases. - if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { + if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) { match self.tainted_by_errors() { None => { let err = self.emit_inference_failure_err( @@ -2925,7 +2925,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let (Some(node), true) = ( self.tcx.hir().get_if_local(item_def_id), - Some(pred.def_id()) == self.tcx.lang_items().sized_trait(), + self.tcx.is_lang_item(pred.def_id(), LangItem::Sized), ) else { return; }; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 32409e13842..8ab324e6601 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1015,6 +1015,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // not eligible. let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); + let tcx = selcx.tcx(); let lang_items = selcx.tcx().lang_items(); if [ lang_items.coroutine_trait(), @@ -1031,7 +1032,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( .contains(&Some(trait_ref.def_id)) { true - } else if lang_items.async_fn_kind_helper() == Some(trait_ref.def_id) { + } else if tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncFnKindHelper) { // FIXME(async_closures): Validity constraints here could be cleaned up. if obligation.predicate.args.type_at(0).is_ty_var() || obligation.predicate.args.type_at(4).is_ty_var() @@ -1043,7 +1044,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some() && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some() } - } else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) { + } else if tcx.is_lang_item(trait_ref.def_id, LangItem::DiscriminantKind) { match self_ty.kind() { ty::Bool | ty::Char @@ -1080,7 +1081,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Infer(..) | ty::Error(_) => false, } - } else if lang_items.async_destruct_trait() == Some(trait_ref.def_id) { + } else if tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncDestruct) { match self_ty.kind() { ty::Bool | ty::Char @@ -1116,7 +1117,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Infer(_) | ty::Error(_) => false, } - } else if lang_items.pointee_trait() == Some(trait_ref.def_id) { + } else if tcx.is_lang_item(trait_ref.def_id, LangItem::PointeeTrait) { let tail = selcx.tcx().struct_tail_with_normalize( self_ty, |ty| { @@ -1300,15 +1301,15 @@ fn confirm_select_candidate<'cx, 'tcx>( match impl_source { ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data), ImplSource::Builtin(BuiltinImplSource::Misc, data) => { - let trait_def_id = obligation.predicate.trait_def_id(selcx.tcx()); - let lang_items = selcx.tcx().lang_items(); - if lang_items.coroutine_trait() == Some(trait_def_id) { + let tcx = selcx.tcx(); + let trait_def_id = obligation.predicate.trait_def_id(tcx); + if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) { confirm_coroutine_candidate(selcx, obligation, data) - } else if lang_items.future_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Future) { confirm_future_candidate(selcx, obligation, data) - } else if lang_items.iterator_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Iterator) { confirm_iterator_candidate(selcx, obligation, data) - } else if lang_items.async_iterator_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncIterator) { confirm_async_iterator_candidate(selcx, obligation, data) } else if selcx.tcx().fn_trait_kind_from_def_id(trait_def_id).is_some() { if obligation.predicate.self_ty().is_closure() @@ -1320,7 +1321,7 @@ fn confirm_select_candidate<'cx, 'tcx>( } } else if selcx.tcx().async_fn_trait_kind_from_def_id(trait_def_id).is_some() { confirm_async_closure_candidate(selcx, obligation, data) - } else if lang_items.async_fn_kind_helper() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncFnKindHelper) { confirm_async_fn_kind_helper_candidate(selcx, obligation, data) } else { confirm_builtin_candidate(selcx, obligation, data) @@ -1373,10 +1374,9 @@ fn confirm_coroutine_candidate<'cx, 'tcx>( coroutine_sig, ); - let lang_items = tcx.lang_items(); - let ty = if Some(obligation.predicate.def_id) == lang_items.coroutine_return() { + let ty = if tcx.is_lang_item(obligation.predicate.def_id, LangItem::CoroutineReturn) { return_ty - } else if Some(obligation.predicate.def_id) == lang_items.coroutine_yield() { + } else if tcx.is_lang_item(obligation.predicate.def_id, LangItem::CoroutineYield) { yield_ty } else { span_bug!( @@ -1539,21 +1539,20 @@ fn confirm_builtin_candidate<'cx, 'tcx>( ) -> Progress<'tcx> { let tcx = selcx.tcx(); let self_ty = obligation.predicate.self_ty(); - let lang_items = tcx.lang_items(); let item_def_id = obligation.predicate.def_id; let trait_def_id = tcx.trait_of_item(item_def_id).unwrap(); let args = tcx.mk_args(&[self_ty.into()]); - let (term, obligations) = if lang_items.discriminant_kind_trait() == Some(trait_def_id) { + let (term, obligations) = if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) { let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); assert_eq!(discriminant_def_id, item_def_id); (self_ty.discriminant_ty(tcx).into(), Vec::new()) - } else if lang_items.async_destruct_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncDestruct) { let destructor_def_id = tcx.associated_item_def_ids(trait_def_id)[0]; assert_eq!(destructor_def_id, item_def_id); (self_ty.async_destructor_ty(tcx).into(), Vec::new()) - } else if lang_items.pointee_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) { let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); assert_eq!(metadata_def_id, item_def_id); diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 326c68e01db..7dc051e6fe9 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -55,7 +55,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { } ty::Adt(def, _) => { - if Some(def.did()) == tcx.lang_items().manually_drop() { + if def.is_manually_drop() { // `ManuallyDrop` never has a dtor. true } else { 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 6db5fa0e4e5..a026b233c68 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -67,9 +67,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. let def_id = obligation.predicate.def_id(); - let lang_items = self.tcx().lang_items(); + let tcx = self.tcx(); - if lang_items.copy_trait() == Some(def_id) { + if tcx.is_lang_item(def_id, LangItem::Copy) { debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty()); // User-defined copy impls are permitted, but only for @@ -79,16 +79,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // For other types, we'll use the builtin rules. let copy_conditions = self.copy_clone_conditions(obligation); self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates); - } else if lang_items.discriminant_kind_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::DiscriminantKind) { // `DiscriminantKind` is automatically implemented for every type. candidates.vec.push(BuiltinCandidate { has_nested: false }); - } else if lang_items.async_destruct_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::AsyncDestruct) { // `AsyncDestruct` is automatically implemented for every type. candidates.vec.push(BuiltinCandidate { has_nested: false }); - } else if lang_items.pointee_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::PointeeTrait) { // `Pointee` is automatically implemented for every type. candidates.vec.push(BuiltinCandidate { has_nested: false }); - } else if lang_items.sized_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::Sized) { // Sized is never implementable by end-users, it is // always automatically computed. @@ -101,22 +101,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let sized_conditions = self.sized_conditions(obligation); self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates); - } else if lang_items.unsize_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::Unsize) { self.assemble_candidates_for_unsizing(obligation, &mut candidates); - } else if lang_items.destruct_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::Destruct) { self.assemble_const_destruct_candidates(obligation, &mut candidates); - } else if lang_items.transmute_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::TransmuteTrait) { // User-defined transmutability impls are permitted. self.assemble_candidates_from_impls(obligation, &mut candidates); self.assemble_candidates_for_transmutability(obligation, &mut candidates); - } else if lang_items.tuple_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::Tuple) { self.assemble_candidate_for_tuple(obligation, &mut candidates); - } else if lang_items.pointer_like() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::PointerLike) { self.assemble_candidate_for_pointer_like(obligation, &mut candidates); - } else if lang_items.fn_ptr_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) { self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates); } else { - if lang_items.clone_trait() == Some(def_id) { + if tcx.is_lang_item(def_id, LangItem::Clone) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone` // types have builtin support for `Clone`. @@ -124,17 +124,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates); } - if lang_items.coroutine_trait() == Some(def_id) { + if tcx.is_lang_item(def_id, LangItem::Coroutine) { self.assemble_coroutine_candidates(obligation, &mut candidates); - } else if lang_items.future_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::Future) { self.assemble_future_candidates(obligation, &mut candidates); - } else if lang_items.iterator_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::Iterator) { self.assemble_iterator_candidates(obligation, &mut candidates); - } else if lang_items.fused_iterator_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::FusedIterator) { self.assemble_fused_iterator_candidates(obligation, &mut candidates); - } else if lang_items.async_iterator_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::AsyncIterator) { self.assemble_async_iterator_candidates(obligation, &mut candidates); - } else if lang_items.async_fn_kind_helper() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::AsyncFnKindHelper) { self.assemble_async_fn_kind_helper_candidates(obligation, &mut candidates); } @@ -755,7 +755,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.ambiguous = true; } ty::Coroutine(coroutine_def_id, _) - if self.tcx().lang_items().unpin_trait() == Some(def_id) => + if self.tcx().is_lang_item(def_id, LangItem::Unpin) => { match self.tcx().coroutine_movability(coroutine_def_id) { hir::Movability::Static => { diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 08524f625fe..074fd487888 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -258,16 +258,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Vec> { debug!(?obligation, ?has_nested, "confirm_builtin_candidate"); - let lang_items = self.tcx().lang_items(); + let tcx = self.tcx(); let obligations = if has_nested { let trait_def = obligation.predicate.def_id(); - let conditions = if Some(trait_def) == lang_items.sized_trait() { + let conditions = if tcx.is_lang_item(trait_def, LangItem::Sized) { self.sized_conditions(obligation) - } else if Some(trait_def) == lang_items.copy_trait() { + } else if tcx.is_lang_item(trait_def, LangItem::Copy) { self.copy_clone_conditions(obligation) - } else if Some(trait_def) == lang_items.clone_trait() { + } else if tcx.is_lang_item(trait_def, LangItem::Clone) { self.copy_clone_conditions(obligation) - } else if Some(trait_def) == lang_items.fused_iterator_trait() { + } else if tcx.is_lang_item(trait_def, LangItem::FusedIterator) { self.fused_iterator_conditions(obligation) } else { bug!("unexpected builtin trait {:?}", trait_def) @@ -1444,7 +1444,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Foreign(_) => {} // `ManuallyDrop` is trivially drop - ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().manually_drop() => {} + ty::Adt(def, _) if def.is_manually_drop() => {} // These types are built-in, so we can fast-track by registering // nested predicates for their constituent type(s) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 212ef2e4b2b..b4019585771 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -32,6 +32,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::LangItem; use rustc_infer::infer::relate::TypeRelation; use rustc_infer::infer::BoundRegionConversionTime; use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType; @@ -2800,19 +2801,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let predicates = predicates.instantiate_own(tcx, args); let mut obligations = Vec::with_capacity(predicates.len()); for (index, (predicate, span)) in predicates.into_iter().enumerate() { - let cause = - if Some(parent_trait_pred.def_id()) == tcx.lang_items().coerce_unsized_trait() { - cause.clone() - } else { - cause.clone().derived_cause(parent_trait_pred, |derived| { - ObligationCauseCode::ImplDerived(Box::new(ImplDerivedCause { - derived, - impl_or_alias_def_id: def_id, - impl_def_predicate_index: Some(index), - span, - })) - }) - }; + let cause = if tcx.is_lang_item(parent_trait_pred.def_id(), LangItem::CoerceUnsized) { + cause.clone() + } else { + cause.clone().derived_cause(parent_trait_pred, |derived| { + ObligationCauseCode::ImplDerived(Box::new(ImplDerivedCause { + derived, + impl_or_alias_def_id: def_id, + impl_def_predicate_index: Some(index), + span, + })) + }) + }; let clause = normalize_with_depth_to( self, param_env, diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index e4dcea785d4..094903f61d4 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -1,5 +1,6 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; +use rustc_hir::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::query::Providers; @@ -34,7 +35,7 @@ fn resolve_instance<'tcx>( let def = if tcx.intrinsic(def_id).is_some() { debug!(" => intrinsic"); ty::InstanceDef::Intrinsic(def_id) - } else if Some(def_id) == tcx.lang_items().drop_in_place_fn() { + } else if tcx.is_lang_item(def_id, LangItem::DropInPlace) { let ty = args.type_at(0); if ty.needs_drop(tcx, param_env) { @@ -57,7 +58,7 @@ fn resolve_instance<'tcx>( debug!(" => trivial drop glue"); ty::InstanceDef::DropGlue(def_id, None) } - } else if Some(def_id) == tcx.lang_items().async_drop_in_place_fn() { + } else if tcx.is_lang_item(def_id, LangItem::AsyncDropInPlace) { let ty = args.type_at(0); if ty.async_drop_glue_morphology(tcx) != AsyncDropGlueMorphology::Noop { @@ -221,8 +222,7 @@ fn resolve_associated_item<'tcx>( ) } traits::ImplSource::Builtin(BuiltinImplSource::Misc, _) => { - let lang_items = tcx.lang_items(); - if Some(trait_ref.def_id) == lang_items.clone_trait() { + if tcx.is_lang_item(trait_ref.def_id, LangItem::Clone) { // FIXME(eddyb) use lang items for methods instead of names. let name = tcx.item_name(trait_item_id); if name == sym::clone { @@ -248,8 +248,8 @@ fn resolve_associated_item<'tcx>( let args = tcx.erase_regions(rcvr_args); Some(ty::Instance::new(trait_item_id, args)) } - } else if Some(trait_ref.def_id) == lang_items.fn_ptr_trait() { - if lang_items.fn_ptr_addr() == Some(trait_item_id) { + } else if tcx.is_lang_item(trait_ref.def_id, LangItem::FnPtrTrait) { + if tcx.is_lang_item(trait_item_id, LangItem::FnPtrAddr) { let self_ty = trait_ref.self_ty(); if !matches!(self_ty.kind(), ty::FnPtr(..)) { return Ok(None); -- cgit 1.4.1-3-g733a5 From 0562064959f478e18ba840854a8d73503a1cf9f0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jun 2024 17:19:47 -0400 Subject: Correctly consider depth when visiting WF goals --- compiler/rustc_trait_selection/src/solve/fulfill.rs | 6 ++++-- .../rustc_trait_selection/src/solve/inspect/analyse.rs | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 519a24f6975..3c01d1a65f5 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -520,8 +520,9 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { if let Some(ty::PredicateKind::AliasRelate(lhs, rhs, _)) = pred_kind.no_bound_vars() { if let Some(obligation) = goal .infcx() - .visit_proof_tree( + .visit_proof_tree_at_depth( goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(lhs.into())), + goal.depth() + 1, self, ) .break_value() @@ -529,8 +530,9 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { return ControlFlow::Break(obligation); } else if let Some(obligation) = goal .infcx() - .visit_proof_tree( + .visit_proof_tree_at_depth( goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(rhs.into())), + goal.depth() + 1, self, ) .break_value() diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index b9c98b6a2e9..464c188b6e3 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -278,6 +278,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { self.source } + pub fn depth(&self) -> usize { + self.depth + } + fn candidates_recur( &'a self, candidates: &mut Vec>, @@ -435,9 +439,18 @@ impl<'tcx> InferCtxt<'tcx> { &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, visitor: &mut V, + ) -> V::Result { + self.visit_proof_tree_at_depth(goal, 0, visitor) + } + + fn visit_proof_tree_at_depth>( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + depth: usize, + visitor: &mut V, ) -> V::Result { let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes); let proof_tree = proof_tree.unwrap(); - visitor.visit_goal(&InspectGoal::new(self, 0, proof_tree, None, GoalSource::Misc)) + visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc)) } } -- cgit 1.4.1-3-g733a5 From cbc3bdbe01990773a90f72260ce2a4b1c778e554 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 14 Jun 2024 23:09:15 +0300 Subject: delegation: Fix hygiene for `self` And fix diagnostics for `self` from a macro. --- compiler/rustc_resolve/src/late.rs | 24 +++++++++++--------- compiler/rustc_resolve/src/late/diagnostics.rs | 24 ++++++++++++-------- tests/ui/delegation/macro-inside-list.rs | 4 ++-- tests/ui/delegation/self-hygiene.rs | 20 +++++++++++++++++ tests/ui/delegation/self-hygiene.stderr | 31 ++++++++++++++++++++++++++ 5 files changed, 81 insertions(+), 22 deletions(-) create mode 100644 tests/ui/delegation/self-hygiene.rs create mode 100644 tests/ui/delegation/self-hygiene.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b0adc3775f6..fa711d932b6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3281,17 +3281,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } self.visit_path(&delegation.path, delegation.id); if let Some(body) = &delegation.body { - // `PatBoundCtx` is not necessary in this context - let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; - - let span = delegation.path.segments.last().unwrap().ident.span; - self.fresh_binding( - Ident::new(kw::SelfLower, span), - delegation.id, - PatternSource::FnParam, - &mut bindings, - ); - self.visit_block(body); + self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { + // `PatBoundCtx` is not necessary in this context + let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; + + let span = delegation.path.segments.last().unwrap().ident.span; + this.fresh_binding( + Ident::new(kw::SelfLower, span), + delegation.id, + PatternSource::FnParam, + &mut bindings, + ); + this.visit_block(body); + }); } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 9eeb0da7ed2..be24755d4c5 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1021,12 +1021,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { }, ); let is_assoc_fn = self.self_type_is_available(); + let self_from_macro = "a `self` parameter, but a macro invocation can only \ + access identifiers it receives from parameters"; if let Some((fn_kind, span)) = &self.diag_metadata.current_function { // The current function has a `self` parameter, but we were unable to resolve // a reference to `self`. This can only happen if the `self` identifier we // are resolving came from a different hygiene context. if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) { - err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters"); + err.span_label(*span, format!("this function has {self_from_macro}")); } else { let doesnt = if is_assoc_fn { let (span, sugg) = fn_kind @@ -1068,14 +1070,18 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } } else if let Some(item_kind) = self.diag_metadata.current_item { - err.span_label( - item_kind.ident.span, - format!( - "`self` not allowed in {} {}", - item_kind.kind.article(), - item_kind.kind.descr() - ), - ); + if matches!(item_kind.kind, ItemKind::Delegation(..)) { + err.span_label(item_kind.span, format!("delegation supports {self_from_macro}")); + } else { + err.span_label( + item_kind.ident.span, + format!( + "`self` not allowed in {} {}", + item_kind.kind.article(), + item_kind.kind.descr() + ), + ); + } } true } diff --git a/tests/ui/delegation/macro-inside-list.rs b/tests/ui/delegation/macro-inside-list.rs index 16c74d396ef..d07a4e47dd4 100644 --- a/tests/ui/delegation/macro-inside-list.rs +++ b/tests/ui/delegation/macro-inside-list.rs @@ -14,9 +14,9 @@ struct S(u8); // Macro expansion works inside delegation items. macro_rules! u8 { () => { u8 } } -macro_rules! self_0 { () => { &self.0 } } +macro_rules! self_0 { ($self:ident) => { &$self.0 } } impl Trait for S { - reuse ::{foo, bar} { self_0!() } + reuse ::{foo, bar} { self_0!(self) } } fn main() { diff --git a/tests/ui/delegation/self-hygiene.rs b/tests/ui/delegation/self-hygiene.rs new file mode 100644 index 00000000000..dac6c319416 --- /dev/null +++ b/tests/ui/delegation/self-hygiene.rs @@ -0,0 +1,20 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +macro_rules! emit_self { () => { self } } +//~^ ERROR expected value, found module `self` +//~| ERROR expected value, found module `self` + +struct S; +impl S { + fn method(self) { + emit_self!(); + } +} + +fn foo(arg: u8) {} +reuse foo as bar { + emit_self!() +} + +fn main() {} diff --git a/tests/ui/delegation/self-hygiene.stderr b/tests/ui/delegation/self-hygiene.stderr new file mode 100644 index 00000000000..fa64b7d1d7f --- /dev/null +++ b/tests/ui/delegation/self-hygiene.stderr @@ -0,0 +1,31 @@ +error[E0424]: expected value, found module `self` + --> $DIR/self-hygiene.rs:4:34 + | +LL | macro_rules! emit_self { () => { self } } + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter +... +LL | / fn method(self) { +LL | | emit_self!(); + | | ------------ in this macro invocation +LL | | } + | |_____- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters + | + = note: this error originates in the macro `emit_self` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0424]: expected value, found module `self` + --> $DIR/self-hygiene.rs:4:34 + | +LL | macro_rules! emit_self { () => { self } } + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter +... +LL | / reuse foo as bar { +LL | | emit_self!() + | | ------------ in this macro invocation +LL | | } + | |_- delegation supports a `self` parameter, but a macro invocation can only access identifiers it receives from parameters + | + = note: this error originates in the macro `emit_self` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0424`. -- cgit 1.4.1-3-g733a5 From c006748f6272c19cedb67d25b4444bb07cc5ce12 Mon Sep 17 00:00:00 2001 From: Rémy Rakic Date: Fri, 14 Jun 2024 21:52:25 +0000 Subject: make bors ignore comments in PR template --- .github/pull_request_template.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ca704082a3f..fd54a153a16 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,3 +1,4 @@ + \ No newline at end of file +--> + -- cgit 1.4.1-3-g733a5 From 3b9adbec32757264ba30b68e04ce66d6023810aa Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jun 2024 20:35:45 -0400 Subject: Only compute vtable information during codegen --- compiler/rustc_codegen_cranelift/src/unsize.rs | 3 +- compiler/rustc_codegen_ssa/src/base.rs | 3 +- compiler/rustc_middle/src/query/keys.rs | 8 ++ compiler/rustc_middle/src/query/mod.rs | 7 +- .../src/solve/assembly/mod.rs | 9 +- .../src/solve/eval_ctxt/mod.rs | 36 ------ .../src/solve/eval_ctxt/select.rs | 4 +- .../rustc_trait_selection/src/solve/trait_goals.rs | 32 +++--- compiler/rustc_trait_selection/src/traits/mod.rs | 2 +- .../src/traits/select/confirmation.rs | 43 +------ compiler/rustc_trait_selection/src/traits/util.rs | 17 --- .../rustc_trait_selection/src/traits/vtable.rs | 127 ++++++++++++--------- compiler/rustc_ty_utils/src/instance.rs | 22 +++- compiler/rustc_type_ir/src/solve.rs | 23 ++-- 14 files changed, 141 insertions(+), 195 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 4acbc8a27ed..967aa53abbd 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -39,8 +39,7 @@ pub(crate) fn unsized_info<'tcx>( } // trait upcasting coercion - let vptr_entry_idx = - fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((source, target)); + let vptr_entry_idx = fx.tcx.supertrait_vtable_slot((source, target)); if let Some(entry_idx) = vptr_entry_idx { let entry_idx = u32::try_from(entry_idx).unwrap(); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 0b450c43924..c18816533a2 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -163,8 +163,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // trait upcasting coercion - let vptr_entry_idx = - cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((source, target)); + let vptr_entry_idx = cx.tcx().supertrait_vtable_slot((source, target)); if let Some(entry_idx) = vptr_entry_idx { let ptr_size = bx.data_layout().pointer_size; diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index faa137019cb..5452e1dff3e 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -360,6 +360,14 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) { } } +impl<'tcx> Key for ty::TraitRef<'tcx> { + type Cache = DefaultCache; + + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.def_span(self.def_id) + } +} + impl<'tcx> Key for ty::PolyTraitRef<'tcx> { type Cache = DefaultCache; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index a8bf735fa5a..8ba930f493e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -46,6 +46,7 @@ use crate::traits::{ }; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::ValidityRequirement; +use crate::ty::print::PrintTraitRefExt; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::TyCtxtFeed; use crate::ty::{ @@ -1271,7 +1272,11 @@ rustc_queries! { desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id()) } } - query vtable_trait_upcasting_coercion_new_vptr_slot(key: (Ty<'tcx>, Ty<'tcx>)) -> Option { + query first_method_vtable_slot(key: ty::TraitRef<'tcx>) -> usize { + desc { |tcx| "finding the slot within the vtable of `{}` for the implementation of `{}`", key.self_ty(), key.print_only_trait_name() } + } + + query supertrait_vtable_slot(key: (Ty<'tcx>, Ty<'tcx>)) -> Option { desc { |tcx| "finding the slot within vtable for trait object `{}` vtable ptr during trait upcasting coercion from `{}` vtable", key.1, key.0 } } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index b51efd339c4..ab67c5f3694 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -3,6 +3,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::util::supertraits; use rustc_middle::bug; use rustc_middle::traits::solve::inspect::ProbeKind; use rustc_middle::traits::solve::{ @@ -743,14 +744,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // a projection goal. if let Some(principal) = bounds.principal() { let principal_trait_ref = principal.with_self_ty(tcx, self_ty); - self.walk_vtable(principal_trait_ref, |ecx, assumption, vtable_base, _| { + for (idx, assumption) in supertraits(self.interner(), principal_trait_ref).enumerate() { candidates.extend(G::probe_and_consider_object_bound_candidate( - ecx, - CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base }), + self, + CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)), goal, assumption.upcast(tcx), )); - }); + } } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 860c580374d..6b8375b53e8 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -24,7 +24,6 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen use std::ops::ControlFlow; use crate::traits::coherence; -use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment}; use super::inspect::ProofTreeBuilder; use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT}; @@ -1022,41 +1021,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } } - - /// Walk through the vtable of a principal trait ref, executing a `supertrait_visitor` - /// for every trait ref encountered (including the principal). Passes both the vtable - /// base and the (optional) vptr slot. - pub(super) fn walk_vtable( - &mut self, - principal: ty::PolyTraitRef<'tcx>, - mut supertrait_visitor: impl FnMut(&mut Self, ty::PolyTraitRef<'tcx>, usize, Option), - ) { - let tcx = self.interner(); - let mut offset = 0; - prepare_vtable_segments::<()>(tcx, principal, |segment| { - match segment { - VtblSegment::MetadataDSA => { - offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); - } - VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - let own_vtable_entries = count_own_vtable_entries(tcx, trait_ref); - - supertrait_visitor( - self, - trait_ref, - offset, - emit_vptr.then(|| offset + own_vtable_entries), - ); - - offset += own_vtable_entries; - if emit_vptr { - offset += 1; - } - } - } - ControlFlow::Continue(()) - }); - } } /// Eagerly replace aliases with inference variables, emitting `AliasRelate` diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index 68c0c8bf09e..257fd263b94 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -114,8 +114,8 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>( // In the old trait solver, we arbitrarily choose lower vtable candidates // over higher ones. ( - CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: a }), - CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: b }), + CandidateSource::BuiltinImpl(BuiltinImplSource::Object(a)), + CandidateSource::BuiltinImpl(BuiltinImplSource::Object(b)), ) => a >= b, // Prefer dyn candidates over non-dyn candidates. This is necessary to // handle the unsoundness between `impl Any for T` and `dyn Any: Any`. diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index a741f488901..0715471d74f 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -9,6 +9,7 @@ use rustc_hir::{LangItem, Movability}; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::MaybeCause; +use rustc_infer::traits::util::supertraits; use rustc_middle::bug; use rustc_middle::traits::solve::inspect::ProbeKind; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult}; @@ -756,24 +757,19 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { a_data.principal(), )); } else if let Some(a_principal) = a_data.principal() { - self.walk_vtable( - a_principal.with_self_ty(tcx, a_ty), - |ecx, new_a_principal, _, vtable_vptr_slot| { - responses.extend(ecx.consider_builtin_upcast_to_principal( - goal, - CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting { - vtable_vptr_slot, - }), - a_data, - a_region, - b_data, - b_region, - Some(new_a_principal.map_bound(|trait_ref| { - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) - })), - )); - }, - ); + for new_a_principal in supertraits(tcx, a_principal.with_self_ty(tcx, a_ty)).skip(1) { + responses.extend(self.consider_builtin_upcast_to_principal( + goal, + CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting), + a_data, + a_region, + b_data, + b_region, + Some(new_a_principal.map_bound(|trait_ref| { + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + })), + )); + } } responses diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index eae2f9d1792..af6bfdae440 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -65,7 +65,7 @@ pub use self::structural_match::search_for_structural_match_violation; pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::elaborate; pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo}; -pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; +pub use self::util::{impl_item_is_final, upcast_choices}; pub use self::util::{supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item}; pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 749081006f3..6cf87a9ac78 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -22,10 +22,6 @@ use rustc_span::def_id::DefId; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::util::{self, closure_trait_ref_and_return_type}; -use crate::traits::vtable::{ - count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset, - VtblSegment, -}; use crate::traits::{ ImplDerivedCause, ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause, PolyTraitObligation, PredicateObligation, Selection, SelectionError, @@ -689,13 +685,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?nested, "object nested obligations"); - let vtable_base = vtable_trait_first_method_offset( - tcx, - unnormalized_upcast_trait_ref, - ty::Binder::dummy(object_trait_ref), - ); - - Ok(ImplSource::Builtin(BuiltinImplSource::Object { vtable_base: vtable_base }, nested)) + Ok(ImplSource::Builtin(BuiltinImplSource::Object(index), nested)) } fn confirm_fn_pointer_candidate( @@ -1125,36 +1115,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { )? .expect("did not expect ambiguity during confirmation"); - let vtable_segment_callback = { - let mut vptr_offset = 0; - move |segment| { - match segment { - VtblSegment::MetadataDSA => { - vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); - } - VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - vptr_offset += count_own_vtable_entries(tcx, trait_ref); - if trait_ref == unnormalized_upcast_principal { - if emit_vptr { - return ControlFlow::Break(Some(vptr_offset)); - } else { - return ControlFlow::Break(None); - } - } - - if emit_vptr { - vptr_offset += 1; - } - } - } - ControlFlow::Continue(()) - } - }; - - let vtable_vptr_slot = - prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap(); - - Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, nested)) + Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting, nested)) } fn confirm_builtin_unsize_candidate( diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index ce7245d93a4..c3fe816028e 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -208,23 +208,6 @@ pub fn upcast_choices<'tcx>( supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect() } -/// Given an upcast trait object described by `object`, returns the -/// index of the method `method_def_id` (which should be part of -/// `object.upcast_trait_ref`) within the vtable for `object`. -pub fn get_vtable_index_of_object_method<'tcx>( - tcx: TyCtxt<'tcx>, - vtable_base: usize, - method_def_id: DefId, -) -> Option { - // Count number of methods preceding the one we are selecting and - // add them to the total offset. - tcx.own_existential_vtable_entries(tcx.parent(method_def_id)) - .iter() - .copied() - .position(|def_id| def_id == method_def_id) - .map(|index| vtable_base + index) -} - pub fn closure_trait_ref_and_return_type<'tcx>( tcx: TyCtxt<'tcx>, fn_trait_def_id: DefId, diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 9bd4a9aab0a..017b0a45d1f 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -1,15 +1,11 @@ use crate::errors::DumpVTableEntries; use crate::traits::{impossible_predicates, is_vtable_safe_method}; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::LangItem; use rustc_infer::traits::util::PredicateSet; -use rustc_infer::traits::ImplSource; use rustc_middle::bug; use rustc_middle::query::Providers; -use rustc_middle::traits::BuiltinImplSource; -use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt, Upcast, VtblEntry}; +use rustc_middle::ty::{GenericArgs, TypeVisitableExt}; use rustc_span::{sym, Span}; use smallvec::{smallvec, SmallVec}; @@ -320,30 +316,42 @@ fn vtable_entries<'tcx>( tcx.arena.alloc_from_iter(entries) } -/// Find slot base for trait methods within vtable entries of another trait -pub(super) fn vtable_trait_first_method_offset<'tcx>( - tcx: TyCtxt<'tcx>, - trait_to_be_found: ty::PolyTraitRef<'tcx>, - trait_owning_vtable: ty::PolyTraitRef<'tcx>, -) -> usize { - // #90177 - let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found); +// Given a `dyn Subtrait: Supertrait` trait ref, find corresponding first slot +// for `Supertrait`'s methods in the vtable of `Subtrait`. +pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRef<'tcx>) -> usize { + debug_assert!(!key.has_non_region_infer() && !key.has_non_region_param()); - let vtable_segment_callback = { - let mut vtable_base = 0; + let ty::Dynamic(source, _, _) = *key.self_ty().kind() else { + bug!(); + }; + let source_principal = tcx + .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap()) + .with_self_ty(tcx, tcx.types.trait_object_dummy_self); + + let target_principal = tcx + .normalize_erasing_regions(ty::ParamEnv::reveal_all(), key) + // We don't care about the self type, since it will always be the same thing. + .with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let vtable_segment_callback = { + let mut vptr_offset = 0; move |segment| { match segment { VtblSegment::MetadataDSA => { - vtable_base += TyCtxt::COMMON_VTABLE_ENTRIES.len(); + vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); } VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - if tcx.erase_regions(trait_ref) == trait_to_be_found_erased { - return ControlFlow::Break(vtable_base); + if tcx + .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref) + == target_principal + { + return ControlFlow::Break(vptr_offset); } - vtable_base += count_own_vtable_entries(tcx, trait_ref); + + vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len(); + if emit_vptr { - vtable_base += 1; + vptr_offset += 1; } } } @@ -351,55 +359,72 @@ pub(super) fn vtable_trait_first_method_offset<'tcx>( } }; - if let Some(vtable_base) = - prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback) - { - vtable_base - } else { - bug!("Failed to find info for expected trait in vtable"); - } + prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap() } -/// Find slot offset for trait vptr within vtable entries of another trait -pub(crate) fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>( +/// Given a `dyn Subtrait` and `dyn Supertrait` trait object, find the slot of +/// // the trait vptr in the subtrait's vtable. +pub(crate) fn supertrait_vtable_slot<'tcx>( tcx: TyCtxt<'tcx>, key: ( - Ty<'tcx>, // trait object type whose trait owning vtable - Ty<'tcx>, // trait object for supertrait + Ty<'tcx>, // Source -- `dyn Subtrait`. + Ty<'tcx>, // Target -- `dyn Supertrait` being coerced to. ), ) -> Option { + debug_assert!(!key.has_non_region_infer() && !key.has_non_region_param()); + let (source, target) = key; - assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.has_infer()); - assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.has_infer()); + let ty::Dynamic(source, _, _) = *source.kind() else { + bug!(); + }; + let source_principal = tcx + .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap()) + .with_self_ty(tcx, tcx.types.trait_object_dummy_self); - // this has been typecked-before, so diagnostics is not really needed. - let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None); + let ty::Dynamic(target, _, _) = *target.kind() else { + bug!(); + }; + let target_principal = tcx + .normalize_erasing_regions(ty::ParamEnv::reveal_all(), target.principal().unwrap()) + .with_self_ty(tcx, tcx.types.trait_object_dummy_self); - let trait_ref = ty::TraitRef::new(tcx, unsize_trait_did, [source, target]); + let vtable_segment_callback = { + let mut vptr_offset = 0; + move |segment| { + match segment { + VtblSegment::MetadataDSA => { + vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); + } + VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { + vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len(); + if tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), trait_ref) + == target_principal + { + if emit_vptr { + return ControlFlow::Break(Some(vptr_offset)); + } else { + return ControlFlow::Break(None); + } + } - match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) { - Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, _)) => { - *vtable_vptr_slot + if emit_vptr { + vptr_offset += 1; + } + } + } + ControlFlow::Continue(()) } - otherwise => bug!("expected TraitUpcasting candidate, got {otherwise:?}"), - } -} + }; -/// Given a trait `trait_ref`, returns the number of vtable entries -/// that come from `trait_ref`, excluding its supertraits. Used in -/// computing the vtable base for an upcast trait of a trait object. -pub(crate) fn count_own_vtable_entries<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, -) -> usize { - tcx.own_existential_vtable_entries(trait_ref.def_id()).len() + prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap() } pub(super) fn provide(providers: &mut Providers) { *providers = Providers { own_existential_vtable_entries, vtable_entries, - vtable_trait_upcasting_coercion_new_vptr_slot, + first_method_vtable_slot, + supertrait_vtable_slot, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index e4dcea785d4..2d87975c759 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -212,13 +212,23 @@ fn resolve_associated_item<'tcx>( Some(ty::Instance::new(leaf_def.item.def_id, args)) } - traits::ImplSource::Builtin(BuiltinImplSource::Object { vtable_base }, _) => { - traits::get_vtable_index_of_object_method(tcx, *vtable_base, trait_item_id).map( - |index| Instance { - def: ty::InstanceDef::Virtual(trait_item_id, index), + traits::ImplSource::Builtin(BuiltinImplSource::Object(_), _) => { + let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_args); + if trait_ref.has_non_region_infer() || trait_ref.has_non_region_param() { + // We only resolve totally substituted vtable entries. + None + } else { + let vtable_base = tcx.first_method_vtable_slot(trait_ref); + let offset = tcx + .own_existential_vtable_entries(trait_id) + .iter() + .copied() + .position(|def_id| def_id == trait_item_id); + offset.map(|offset| Instance { + def: ty::InstanceDef::Virtual(trait_item_id, vtable_base + offset), args: rcvr_args, - }, - ) + }) + } } traits::ImplSource::Builtin(BuiltinImplSource::Misc, _) => { let lang_items = tcx.lang_items(); diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index 45125fe6191..6a89a8a4cc3 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -171,25 +171,20 @@ pub enum CandidateSource { #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))] pub enum BuiltinImplSource { - /// Some builtin impl we don't need to differentiate. This should be used + /// Some built-in impl we don't need to differentiate. This should be used /// unless more specific information is necessary. Misc, - /// A builtin impl for trait objects. + /// A built-in impl for trait objects. The index is only used in winnowing. + Object(usize), + /// A built-in implementation of `Upcast` for trait objects to other trait objects. /// - /// The vtable is formed by concatenating together the method lists of - /// the base object trait and all supertraits, pointers to supertrait vtable will - /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods - /// in that vtable. - Object { vtable_base: usize }, - /// The vtable is formed by concatenating together the method lists of - /// the base object trait and all supertraits, pointers to supertrait vtable will - /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable - /// within that vtable. - TraitUpcasting { vtable_vptr_slot: Option }, + /// This can be removed when `feature(dyn_upcasting)` is stabilized, since we only + /// use it to detect when upcasting traits in hir typeck. + TraitUpcasting, /// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`. /// - /// This needs to be a separate variant as it is still unstable and we need to emit - /// a feature error when using it on stable. + /// This can be removed when `feature(tuple_unsizing)` is stabilized, since we only + /// use it to detect when unsizing tuples in hir typeck. TupleUnsizing, } -- cgit 1.4.1-3-g733a5 From 9efa158872a5a8bb150106dd4e89a741c43dfcdd Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 14 Jun 2024 23:04:53 -0400 Subject: Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 4dcbca118ab..a1f47ec3f7c 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 4dcbca118ab7f9ffac4728004c983754bc6a04ff +Subproject commit a1f47ec3f7cd076986f1bfcd7061f2e8cb1a726e -- cgit 1.4.1-3-g733a5 From 58b065eb4423d2075f5478b05e287dbbb8470ca0 Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Sat, 27 Apr 2024 23:09:43 -0700 Subject: make uninitialized_error_reported a set of locals --- compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs | 6 +++--- compiler/rustc_borrowck/src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8200a58f31f..fb3d17777a5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -100,12 +100,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { move_site_vec.iter().map(|move_site| move_site.moi).collect(); if move_out_indices.is_empty() { - let root_place = PlaceRef { projection: &[], ..used_place }; + let root_local = used_place.local; - if !self.uninitialized_error_reported.insert(root_place) { + if !self.uninitialized_error_reported.insert(root_local) { debug!( "report_use_of_moved_or_uninitialized place: error about {:?} suppressed", - root_place + root_local ); return; } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 5c9826ecca7..b3b53e9cb79 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -566,7 +566,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> { fn_self_span_reported: FxIndexSet, /// This field keeps track of errors reported in the checking of uninitialized variables, /// so that we don't report seemingly duplicate errors. - uninitialized_error_reported: FxIndexSet>, + uninitialized_error_reported: FxIndexSet, /// This field keeps track of all the local variables that are declared mut and are mutated. /// Used for the warning issued by an unused mutable local variable. used_mut: FxIndexSet, -- cgit 1.4.1-3-g733a5 From 17a9d3498b64180039faec901ccc51a75452a0e4 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 11 Jun 2024 21:25:45 -0700 Subject: Add ub-checks to slice_index MIR-opt test --- tests/mir-opt/pre-codegen/slice_index.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mir-opt/pre-codegen/slice_index.rs b/tests/mir-opt/pre-codegen/slice_index.rs index 04bbbff57b3..88b99777dd9 100644 --- a/tests/mir-opt/pre-codegen/slice_index.rs +++ b/tests/mir-opt/pre-codegen/slice_index.rs @@ -1,5 +1,5 @@ // skip-filecheck -//@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 +//@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -Z ub-checks=yes // EMIT_MIR_FOR_EACH_PANIC_STRATEGY #![crate_type = "lib"] -- cgit 1.4.1-3-g733a5 From b8eb6ad03273d42d6a22ced57a46e5652fb35f1d Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 14 Jun 2024 22:38:52 -0700 Subject: std: suggest OnceLock over Once --- library/std/src/sync/mod.rs | 3 ++- library/std/src/sync/once.rs | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 2a13b1a8ae2..9a38c42f43a 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -133,7 +133,8 @@ //! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at //! most one thread at a time is able to access some data. //! -//! - [`Once`]: Used for a thread-safe, one-time global initialization routine +//! - [`Once`]: Used for a thread-safe, one-time global initialization routine. +//! Mostly useful for implementing other types like `OnceLock`. //! //! - [`OnceLock`]: Used for thread-safe, one-time initialization of a //! variable, with potentially different initializers based on the caller. diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 608229fd674..9d969af8c6d 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -10,9 +10,15 @@ use crate::fmt; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sys::sync as sys; -/// A synchronization primitive which can be used to run a one-time global -/// initialization. Useful for one-time initialization for FFI or related -/// functionality. This type can only be constructed with [`Once::new()`]. +/// A low-level synchronization primitive for one-time global execution. +/// +/// Previously this was the only "execute once" synchronization in `std`. +/// Other libraries implemented novel synchronizing types with `Once`, like +/// [`OnceLock`] or [`LazyLock`], before those were added to `std`. +/// `OnceLock` in particular supersedes `Once` in functionality and should +/// be preferred for the common case where the `Once` is associated with data. +/// +/// This type can only be constructed with [`Once::new()`]. /// /// # Examples /// @@ -25,6 +31,9 @@ use crate::sys::sync as sys; /// // run initialization here /// }); /// ``` +/// +/// [`OnceLock`]: crate::sync::OnceLock +/// [`LazyLock`]: crate::sync::LazyLock #[stable(feature = "rust1", since = "1.0.0")] pub struct Once { inner: sys::Once, -- cgit 1.4.1-3-g733a5 From 297c97dbe087a9308eba2348fc86cad10f032ea6 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 15 Jun 2024 09:26:56 +0200 Subject: .mailmap: Associate both my work and my private email with me --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 0bd16a797ca..33673244be6 100644 --- a/.mailmap +++ b/.mailmap @@ -379,6 +379,7 @@ Markus Westerlind Markus Martin Carton Martin Habovštiak Martin Hafskjold Thoresen +Martin Nordholts Matej Lach Matej Ľach Mateusz Mikuła Mateusz Mikuła -- cgit 1.4.1-3-g733a5 From a4eaf879823456d5ffa3177a27359b9a2b9134e3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 15 Jun 2024 13:00:20 +0200 Subject: Migrate `run-make/dep-graph` to `rmake.rs` --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/dep-graph/Makefile | 12 ------------ tests/run-make/dep-graph/rmake.rs | 18 ++++++++++++++++++ 3 files changed, 18 insertions(+), 13 deletions(-) delete mode 100644 tests/run-make/dep-graph/Makefile create mode 100644 tests/run-make/dep-graph/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index be9df226d64..df536cdc030 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -25,7 +25,6 @@ run-make/cross-lang-lto-upstream-rlibs/Makefile run-make/cross-lang-lto/Makefile run-make/debug-assertions/Makefile run-make/debugger-visualizer-dep-info/Makefile -run-make/dep-graph/Makefile run-make/dep-info-doesnt-run-much/Makefile run-make/dep-info-spaces/Makefile run-make/dep-info/Makefile diff --git a/tests/run-make/dep-graph/Makefile b/tests/run-make/dep-graph/Makefile deleted file mode 100644 index d06333f4454..00000000000 --- a/tests/run-make/dep-graph/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../tools.mk - -# ignore-cross-compile - -# Just verify that we successfully run and produce dep graphs when requested. - -all: - RUST_DEP_GRAPH=$(TMPDIR)/dep-graph $(RUSTC) \ - -Cincremental=$(TMPDIR)/incr \ - -Zquery-dep-graph -Zdump-dep-graph foo.rs - test -f $(TMPDIR)/dep-graph.txt - test -f $(TMPDIR)/dep-graph.dot diff --git a/tests/run-make/dep-graph/rmake.rs b/tests/run-make/dep-graph/rmake.rs new file mode 100644 index 00000000000..351418997f1 --- /dev/null +++ b/tests/run-make/dep-graph/rmake.rs @@ -0,0 +1,18 @@ +// Just verify that we successfully run and produce dep graphs when requested. + +//@ ignore-cross-compile + +use run_make_support::{path, rustc}; + +fn main() { + rustc() + .input("foo.rs") + .incremental(path("incr")) + .arg("-Zquery-dep-graph") + .arg("-Zdump-dep-graph") + .env("RUST_DEP_GRAPH", path("dep-graph")) + .run(); + + assert!(path("dep-graph.txt").is_file()); + assert!(path("dep-graph.dot").is_file()); +} -- cgit 1.4.1-3-g733a5 From ea2ac347f0d45dd6d499cbd63213c1f3c4515d41 Mon Sep 17 00:00:00 2001 From: "许杰友 Jieyou Xu (Joe)" Date: Sat, 15 Jun 2024 15:50:00 +0000 Subject: trait_selection: remove extra words --- compiler/rustc_trait_selection/src/traits/coherence.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index fc5c71252e1..a4177d8a93f 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -769,8 +769,8 @@ pub struct UncoveredTyParams<'tcx, T> { /// add "non-blanket" impls without breaking negative reasoning in dependent /// crates. This is the "rebalancing coherence" (RFC 1023) restriction. /// -/// For that, we only a allow crate to perform negative reasoning on -/// non-local-non-`#[fundamental]` only if there's a local key parameter as per (2). +/// For that, we only allow a crate to perform negative reasoning on +/// non-local-non-`#[fundamental]` if there's a local key parameter as per (2). /// /// Because we never perform negative reasoning generically (coherence does /// not involve type parameters), this can be interpreted as doing the full -- cgit 1.4.1-3-g733a5 From 52242f2c7247f6a66786d044beb347ae2f9813e3 Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 15 Jun 2024 18:53:45 +0300 Subject: bump few deps --- Cargo.lock | 71 +++++++--------------------------------- src/bootstrap/Cargo.lock | 30 +++++------------ src/tools/linkchecker/Cargo.toml | 2 +- 3 files changed, 22 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 699e5ebf754..be903baf869 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,7 +87,7 @@ version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459" dependencies = [ - "html5ever 0.27.0", + "html5ever", "maplit", "once_cell", "tendril", @@ -542,7 +542,7 @@ checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" dependencies = [ "chrono", "chrono-tz-build", - "phf 0.11.2", + "phf", ] [[package]] @@ -552,8 +552,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" dependencies = [ "parse-zoneinfo", - "phf 0.11.2", - "phf_codegen 0.11.2", + "phf", + "phf_codegen", ] [[package]] @@ -1083,13 +1083,13 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.66", ] [[package]] @@ -1738,20 +1738,6 @@ dependencies = [ "utf8-width", ] -[[package]] -name = "html5ever" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" -dependencies = [ - "log", - "mac", - "markup5ever 0.11.0", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "html5ever" version = "0.27.0" @@ -1760,7 +1746,7 @@ checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" dependencies = [ "log", "mac", - "markup5ever 0.12.1", + "markup5ever", "proc-macro2", "quote", "syn 2.0.66", @@ -2181,7 +2167,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.52.5", + "windows-targets 0.48.5", ] [[package]] @@ -2231,7 +2217,7 @@ dependencies = [ name = "linkchecker" version = "0.1.0" dependencies = [ - "html5ever 0.26.0", + "html5ever", "regex", ] @@ -2316,20 +2302,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" -[[package]] -name = "markup5ever" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" -dependencies = [ - "log", - "phf 0.10.1", - "phf_codegen 0.10.0", - "string_cache", - "string_cache_codegen", - "tendril", -] - [[package]] name = "markup5ever" version = "0.12.1" @@ -2337,8 +2309,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" dependencies = [ "log", - "phf 0.11.2", - "phf_codegen 0.11.2", + "phf", + "phf_codegen", "string_cache", "string_cache_codegen", "tendril", @@ -2951,15 +2923,6 @@ dependencies = [ "sha2", ] -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared 0.10.0", -] - [[package]] name = "phf" version = "0.11.2" @@ -2969,16 +2932,6 @@ dependencies = [ "phf_shared 0.11.2", ] -[[package]] -name = "phf_codegen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", -] - [[package]] name = "phf_codegen" version = "0.11.2" diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 127699b8641..9c24742cff1 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -17,12 +17,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "bitflags" version = "1.3.2" @@ -181,34 +175,28 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.17" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.18" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" @@ -331,12 +319,12 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "junction" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca39ef0d69b18e6a2fd14c2f0a1d593200f4a4ed949b240b5917ab51fac754cb" +checksum = "1c9c415a9b7b1e86cd5738f39d34c9e78c765da7fb1756dbd7d31b3b0d2e7afa" dependencies = [ "scopeguard", - "winapi", + "windows-sys", ] [[package]] diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml index 05049aabc7d..f1be6e9e749 100644 --- a/src/tools/linkchecker/Cargo.toml +++ b/src/tools/linkchecker/Cargo.toml @@ -9,4 +9,4 @@ path = "main.rs" [dependencies] regex = "1" -html5ever = "0.26.0" +html5ever = "0.27.0" -- cgit 1.4.1-3-g733a5 From b717aa1b95eb0ad62c4e2c3e2079b78cab00793a Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 15 Jun 2024 17:45:58 +0200 Subject: tests/ui/lint: Move 19 tests to new `non-snake-case` subdir Mainly so that it is easier to only run all `non-snake-case`-specific tests but no other tests with: ./x test tests/ui/lint/non-snake-case But also to reduce the size of the large `tests/ui/lint` directory. And rename some tests to pass tidy, and remove them from `src/tools/tidy/src/issues.txt`. --- src/tools/tidy/src/issues.txt | 3 - tests/ui/lint/issue-31924-non-snake-ffi.rs | 15 ---- ...e-66362-no-snake-case-warning-for-field-puns.rs | 29 ------- ...362-no-snake-case-warning-for-field-puns.stderr | 32 -------- tests/ui/lint/issue-89469.rs | 20 ----- tests/ui/lint/lint-non-snake-case-crate-bin.rs | 7 -- tests/ui/lint/lint-non-snake-case-crate-bin2.rs | 7 -- tests/ui/lint/lint-non-snake-case-crate-bin3.rs | 8 -- tests/ui/lint/lint-non-snake-case-crate-cdylib.rs | 7 -- .../lint/lint-non-snake-case-crate-cdylib.stderr | 14 ---- tests/ui/lint/lint-non-snake-case-crate-dylib.rs | 7 -- .../ui/lint/lint-non-snake-case-crate-dylib.stderr | 14 ---- tests/ui/lint/lint-non-snake-case-crate-lib.rs | 7 -- tests/ui/lint/lint-non-snake-case-crate-lib.stderr | 14 ---- .../lint/lint-non-snake-case-crate-proc-macro.rs | 7 -- .../lint-non-snake-case-crate-proc-macro.stderr | 14 ---- tests/ui/lint/lint-non-snake-case-crate-rlib.rs | 7 -- .../ui/lint/lint-non-snake-case-crate-rlib.stderr | 14 ---- .../ui/lint/lint-non-snake-case-crate-staticlib.rs | 7 -- .../lint-non-snake-case-crate-staticlib.stderr | 14 ---- tests/ui/lint/lint-non-snake-case-functions.rs | 44 ----------- tests/ui/lint/lint-non-snake-case-functions.stderr | 62 --------------- ...n-snake-case-identifiers-suggestion-reserved.rs | 19 ----- ...ake-case-identifiers-suggestion-reserved.stderr | 67 ---------------- tests/ui/lint/lint-non-snake-case-lifetimes.rs | 8 -- tests/ui/lint/lint-non-snake-case-lifetimes.stderr | 14 ---- tests/ui/lint/lint-non-snake-case-modules.rs | 10 --- tests/ui/lint/lint-non-snake-case-modules.stderr | 14 ---- .../lint-non-snake-case-no-lowercase-equivalent.rs | 11 --- tests/ui/lint/lint-nonstandard-style-unicode-2.rs | 29 ------- .../lint/lint-nonstandard-style-unicode-2.stderr | 20 ----- tests/ui/lint/lint-uppercase-variables.rs | 41 ---------- tests/ui/lint/lint-uppercase-variables.stderr | 90 ---------------------- ...w-snake-case-field-destructuring-issue-89469.rs | 20 +++++ .../lint-non-snake-case-crate-bin.rs | 7 ++ .../lint-non-snake-case-crate-bin2.rs | 7 ++ .../lint-non-snake-case-crate-bin3.rs | 8 ++ .../lint-non-snake-case-crate-cdylib.rs | 7 ++ .../lint-non-snake-case-crate-cdylib.stderr | 14 ++++ .../lint-non-snake-case-crate-dylib.rs | 7 ++ .../lint-non-snake-case-crate-dylib.stderr | 14 ++++ .../lint-non-snake-case-crate-lib.rs | 7 ++ .../lint-non-snake-case-crate-lib.stderr | 14 ++++ .../lint-non-snake-case-crate-proc-macro.rs | 7 ++ .../lint-non-snake-case-crate-proc-macro.stderr | 14 ++++ .../lint-non-snake-case-crate-rlib.rs | 7 ++ .../lint-non-snake-case-crate-rlib.stderr | 14 ++++ .../lint-non-snake-case-crate-staticlib.rs | 7 ++ .../lint-non-snake-case-crate-staticlib.stderr | 14 ++++ .../lint-non-snake-case-functions.rs | 44 +++++++++++ .../lint-non-snake-case-functions.stderr | 62 +++++++++++++++ ...n-snake-case-identifiers-suggestion-reserved.rs | 19 +++++ ...ake-case-identifiers-suggestion-reserved.stderr | 67 ++++++++++++++++ .../lint-non-snake-case-lifetimes.rs | 8 ++ .../lint-non-snake-case-lifetimes.stderr | 14 ++++ .../non-snake-case/lint-non-snake-case-modules.rs | 10 +++ .../lint-non-snake-case-modules.stderr | 14 ++++ .../lint-non-snake-case-no-lowercase-equivalent.rs | 11 +++ .../lint-nonstandard-style-unicode-2.rs | 29 +++++++ .../lint-nonstandard-style-unicode-2.stderr | 20 +++++ .../non-snake-case/lint-uppercase-variables.rs | 41 ++++++++++ .../non-snake-case/lint-uppercase-variables.stderr | 90 ++++++++++++++++++++++ ...nake-case-warning-for-field-puns-issue-66362.rs | 29 +++++++ ...-case-warning-for-field-puns-issue-66362.stderr | 32 ++++++++ .../non-snake-case/non-snake-ffi-issue-31924.rs | 15 ++++ 65 files changed, 673 insertions(+), 676 deletions(-) delete mode 100644 tests/ui/lint/issue-31924-non-snake-ffi.rs delete mode 100644 tests/ui/lint/issue-66362-no-snake-case-warning-for-field-puns.rs delete mode 100644 tests/ui/lint/issue-66362-no-snake-case-warning-for-field-puns.stderr delete mode 100644 tests/ui/lint/issue-89469.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-bin.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-bin2.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-bin3.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-cdylib.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-cdylib.stderr delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-dylib.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-dylib.stderr delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-lib.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-lib.stderr delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-proc-macro.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-proc-macro.stderr delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-rlib.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-rlib.stderr delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-staticlib.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-crate-staticlib.stderr delete mode 100644 tests/ui/lint/lint-non-snake-case-functions.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-functions.stderr delete mode 100644 tests/ui/lint/lint-non-snake-case-identifiers-suggestion-reserved.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-identifiers-suggestion-reserved.stderr delete mode 100644 tests/ui/lint/lint-non-snake-case-lifetimes.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-lifetimes.stderr delete mode 100644 tests/ui/lint/lint-non-snake-case-modules.rs delete mode 100644 tests/ui/lint/lint-non-snake-case-modules.stderr delete mode 100644 tests/ui/lint/lint-non-snake-case-no-lowercase-equivalent.rs delete mode 100644 tests/ui/lint/lint-nonstandard-style-unicode-2.rs delete mode 100644 tests/ui/lint/lint-nonstandard-style-unicode-2.stderr delete mode 100644 tests/ui/lint/lint-uppercase-variables.rs delete mode 100644 tests/ui/lint/lint-uppercase-variables.stderr create mode 100644 tests/ui/lint/non-snake-case/allow-snake-case-field-destructuring-issue-89469.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin2.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin3.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.stderr create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.stderr create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.stderr create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.stderr create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.stderr create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.stderr create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-functions.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-functions.stderr create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-identifiers-suggestion-reserved.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-identifiers-suggestion-reserved.stderr create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-lifetimes.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-lifetimes.stderr create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-modules.rs create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-modules.stderr create mode 100644 tests/ui/lint/non-snake-case/lint-non-snake-case-no-lowercase-equivalent.rs create mode 100644 tests/ui/lint/non-snake-case/lint-nonstandard-style-unicode-2.rs create mode 100644 tests/ui/lint/non-snake-case/lint-nonstandard-style-unicode-2.stderr create mode 100644 tests/ui/lint/non-snake-case/lint-uppercase-variables.rs create mode 100644 tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr create mode 100644 tests/ui/lint/non-snake-case/no-snake-case-warning-for-field-puns-issue-66362.rs create mode 100644 tests/ui/lint/non-snake-case/no-snake-case-warning-for-field-puns-issue-66362.stderr create mode 100644 tests/ui/lint/non-snake-case/non-snake-ffi-issue-31924.rs diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index a6ba8959f0c..3c7284ce6db 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2760,7 +2760,6 @@ ui/lint/issue-1866.rs ui/lint/issue-19102.rs ui/lint/issue-20343.rs ui/lint/issue-30302.rs -ui/lint/issue-31924-non-snake-ffi.rs ui/lint/issue-34798.rs ui/lint/issue-35075.rs ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs @@ -2769,7 +2768,6 @@ ui/lint/issue-54099-camel-case-underscore-types.rs ui/lint/issue-57410-1.rs ui/lint/issue-57410.rs ui/lint/issue-63364.rs -ui/lint/issue-66362-no-snake-case-warning-for-field-puns.rs ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs ui/lint/issue-79546-fuel-ice.rs ui/lint/issue-79744.rs @@ -2777,7 +2775,6 @@ ui/lint/issue-80988.rs ui/lint/issue-81218.rs ui/lint/issue-83477.rs ui/lint/issue-87274-paren-parent.rs -ui/lint/issue-89469.rs ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs ui/lint/issue-97094.rs ui/lint/issue-99387.rs diff --git a/tests/ui/lint/issue-31924-non-snake-ffi.rs b/tests/ui/lint/issue-31924-non-snake-ffi.rs deleted file mode 100644 index ade4e630fb2..00000000000 --- a/tests/ui/lint/issue-31924-non-snake-ffi.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ check-pass - -#![deny(non_snake_case)] - -#[no_mangle] -pub extern "C" fn SparklingGenerationForeignFunctionInterface() {} // OK - -pub struct Foo; - -impl Foo { - #[no_mangle] - pub extern "C" fn SparklingGenerationForeignFunctionInterface() {} // OK -} - -fn main() {} diff --git a/tests/ui/lint/issue-66362-no-snake-case-warning-for-field-puns.rs b/tests/ui/lint/issue-66362-no-snake-case-warning-for-field-puns.rs deleted file mode 100644 index c2b81959f2c..00000000000 --- a/tests/ui/lint/issue-66362-no-snake-case-warning-for-field-puns.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![deny(non_snake_case)] -#![allow(unused_variables)] -#![allow(dead_code)] - -enum Foo { - Bad { - lowerCamelCaseName: bool, - //~^ ERROR structure field `lowerCamelCaseName` should have a snake case name - }, - Good { - snake_case_name: bool, - }, -} - -fn main() { - let b = Foo::Bad { lowerCamelCaseName: true }; - - match b { - Foo::Bad { lowerCamelCaseName } => {} - Foo::Good { snake_case_name: lowerCamelCaseBinding } => { } - //~^ ERROR variable `lowerCamelCaseBinding` should have a snake case name - } - - if let Foo::Good { snake_case_name: anotherLowerCamelCaseBinding } = b { } - //~^ ERROR variable `anotherLowerCamelCaseBinding` should have a snake case name - - if let Foo::Bad { lowerCamelCaseName: yetAnotherLowerCamelCaseBinding } = b { } - //~^ ERROR variable `yetAnotherLowerCamelCaseBinding` should have a snake case name -} diff --git a/tests/ui/lint/issue-66362-no-snake-case-warning-for-field-puns.stderr b/tests/ui/lint/issue-66362-no-snake-case-warning-for-field-puns.stderr deleted file mode 100644 index 09dc3640f99..00000000000 --- a/tests/ui/lint/issue-66362-no-snake-case-warning-for-field-puns.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error: structure field `lowerCamelCaseName` should have a snake case name - --> $DIR/issue-66362-no-snake-case-warning-for-field-puns.rs:7:9 - | -LL | lowerCamelCaseName: bool, - | ^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `lower_camel_case_name` - | -note: the lint level is defined here - --> $DIR/issue-66362-no-snake-case-warning-for-field-puns.rs:1:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: variable `lowerCamelCaseBinding` should have a snake case name - --> $DIR/issue-66362-no-snake-case-warning-for-field-puns.rs:20:38 - | -LL | Foo::Good { snake_case_name: lowerCamelCaseBinding } => { } - | ^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `lower_camel_case_binding` - -error: variable `anotherLowerCamelCaseBinding` should have a snake case name - --> $DIR/issue-66362-no-snake-case-warning-for-field-puns.rs:24:41 - | -LL | if let Foo::Good { snake_case_name: anotherLowerCamelCaseBinding } = b { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `another_lower_camel_case_binding` - -error: variable `yetAnotherLowerCamelCaseBinding` should have a snake case name - --> $DIR/issue-66362-no-snake-case-warning-for-field-puns.rs:27:43 - | -LL | if let Foo::Bad { lowerCamelCaseName: yetAnotherLowerCamelCaseBinding } = b { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `yet_another_lower_camel_case_binding` - -error: aborting due to 4 previous errors - diff --git a/tests/ui/lint/issue-89469.rs b/tests/ui/lint/issue-89469.rs deleted file mode 100644 index f691d6b5a92..00000000000 --- a/tests/ui/lint/issue-89469.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Regression test for #89469, where an extra non_snake_case warning was -// reported for a shorthand field binding. - -//@ check-pass -#![deny(non_snake_case)] - -#[allow(non_snake_case)] -struct Entry { - A: u16, - a: u16 -} - -fn foo() -> Entry {todo!()} - -pub fn f() { - let Entry { A, a } = foo(); - let _ = (A, a); -} - -fn main() {} diff --git a/tests/ui/lint/lint-non-snake-case-crate-bin.rs b/tests/ui/lint/lint-non-snake-case-crate-bin.rs deleted file mode 100644 index f8aad88ecee..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-bin.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -//@ check-pass -#![crate_name = "NonSnakeCase"] - -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/lint-non-snake-case-crate-bin2.rs b/tests/ui/lint/lint-non-snake-case-crate-bin2.rs deleted file mode 100644 index c077d81e9e5..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-bin2.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -//@ compile-flags: --crate-name NonSnakeCase -//@ check-pass - -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/lint-non-snake-case-crate-bin3.rs b/tests/ui/lint/lint-non-snake-case-crate-bin3.rs deleted file mode 100644 index 278f7cfd3ee..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-bin3.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -//@ check-pass -#![crate_type = "bin"] -#![crate_name = "NonSnakeCase"] - -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/lint-non-snake-case-crate-cdylib.rs b/tests/ui/lint/lint-non-snake-case-crate-cdylib.rs deleted file mode 100644 index 781c6794fc2..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-cdylib.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -#![crate_type = "cdylib"] -#![crate_name = "NonSnakeCase"] -//~^ ERROR crate `NonSnakeCase` should have a snake case name -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/lint-non-snake-case-crate-cdylib.stderr b/tests/ui/lint/lint-non-snake-case-crate-cdylib.stderr deleted file mode 100644 index f9167aa8df3..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-cdylib.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate-cdylib.rs:3:18 - | -LL | #![crate_name = "NonSnakeCase"] - | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` - | -note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate-cdylib.rs:5:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/lint-non-snake-case-crate-dylib.rs b/tests/ui/lint/lint-non-snake-case-crate-dylib.rs deleted file mode 100644 index 3f65295f068..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-dylib.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -#![crate_type = "dylib"] -#![crate_name = "NonSnakeCase"] -//~^ ERROR crate `NonSnakeCase` should have a snake case name -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/lint-non-snake-case-crate-dylib.stderr b/tests/ui/lint/lint-non-snake-case-crate-dylib.stderr deleted file mode 100644 index 4ee1a9cb3dd..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-dylib.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate-dylib.rs:3:18 - | -LL | #![crate_name = "NonSnakeCase"] - | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` - | -note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate-dylib.rs:5:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/lint-non-snake-case-crate-lib.rs b/tests/ui/lint/lint-non-snake-case-crate-lib.rs deleted file mode 100644 index 20c58e66aa6..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -#![crate_type = "lib"] -#![crate_name = "NonSnakeCase"] -//~^ ERROR crate `NonSnakeCase` should have a snake case name -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/lint-non-snake-case-crate-lib.stderr b/tests/ui/lint/lint-non-snake-case-crate-lib.stderr deleted file mode 100644 index a68c0e832b8..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-lib.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate-lib.rs:3:18 - | -LL | #![crate_name = "NonSnakeCase"] - | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` - | -note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate-lib.rs:5:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/lint-non-snake-case-crate-proc-macro.rs b/tests/ui/lint/lint-non-snake-case-crate-proc-macro.rs deleted file mode 100644 index f0f2fa4393e..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-proc-macro.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -#![crate_type = "proc-macro"] -#![crate_name = "NonSnakeCase"] -//~^ ERROR crate `NonSnakeCase` should have a snake case name -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/lint-non-snake-case-crate-proc-macro.stderr b/tests/ui/lint/lint-non-snake-case-crate-proc-macro.stderr deleted file mode 100644 index e0091057bc9..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-proc-macro.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate-proc-macro.rs:3:18 - | -LL | #![crate_name = "NonSnakeCase"] - | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` - | -note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate-proc-macro.rs:5:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/lint-non-snake-case-crate-rlib.rs b/tests/ui/lint/lint-non-snake-case-crate-rlib.rs deleted file mode 100644 index 1a558def3d0..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-rlib.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -#![crate_type = "rlib"] -#![crate_name = "NonSnakeCase"] -//~^ ERROR crate `NonSnakeCase` should have a snake case name -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/lint-non-snake-case-crate-rlib.stderr b/tests/ui/lint/lint-non-snake-case-crate-rlib.stderr deleted file mode 100644 index 6e9d54bd5bc..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-rlib.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate-rlib.rs:3:18 - | -LL | #![crate_name = "NonSnakeCase"] - | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` - | -note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate-rlib.rs:5:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/lint-non-snake-case-crate-staticlib.rs b/tests/ui/lint/lint-non-snake-case-crate-staticlib.rs deleted file mode 100644 index 2ec53c15eb8..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-staticlib.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -#![crate_type = "staticlib"] -#![crate_name = "NonSnakeCase"] -//~^ ERROR crate `NonSnakeCase` should have a snake case name -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/lint-non-snake-case-crate-staticlib.stderr b/tests/ui/lint/lint-non-snake-case-crate-staticlib.stderr deleted file mode 100644 index 4ee6d5bd4d4..00000000000 --- a/tests/ui/lint/lint-non-snake-case-crate-staticlib.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate-staticlib.rs:3:18 - | -LL | #![crate_name = "NonSnakeCase"] - | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` - | -note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate-staticlib.rs:5:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/lint-non-snake-case-functions.rs b/tests/ui/lint/lint-non-snake-case-functions.rs deleted file mode 100644 index fa64a9f980e..00000000000 --- a/tests/ui/lint/lint-non-snake-case-functions.rs +++ /dev/null @@ -1,44 +0,0 @@ -#![deny(non_snake_case)] -#![allow(dead_code)] - -struct Foo; - -impl Foo { - fn Foo_Method() {} - //~^ ERROR method `Foo_Method` should have a snake case name - - // Don't allow two underscores in a row - fn foo__method(&self) {} - //~^ ERROR method `foo__method` should have a snake case name - - pub fn xyZ(&mut self) {} - //~^ ERROR method `xyZ` should have a snake case name - - fn render_HTML() {} - //~^ ERROR method `render_HTML` should have a snake case name -} - -trait X { - fn ABC(); - //~^ ERROR trait method `ABC` should have a snake case name - - fn a_b_C(&self) {} - //~^ ERROR trait method `a_b_C` should have a snake case name - - fn something__else(&mut self); - //~^ ERROR trait method `something__else` should have a snake case name -} - -impl X for Foo { - // These errors should be caught at the trait definition not the impl - fn ABC() {} - fn something__else(&mut self) {} -} - -fn Cookie() {} -//~^ ERROR function `Cookie` should have a snake case name - -pub fn bi_S_Cuit() {} -//~^ ERROR function `bi_S_Cuit` should have a snake case name - -fn main() { } diff --git a/tests/ui/lint/lint-non-snake-case-functions.stderr b/tests/ui/lint/lint-non-snake-case-functions.stderr deleted file mode 100644 index f6ac6b99b60..00000000000 --- a/tests/ui/lint/lint-non-snake-case-functions.stderr +++ /dev/null @@ -1,62 +0,0 @@ -error: method `Foo_Method` should have a snake case name - --> $DIR/lint-non-snake-case-functions.rs:7:8 - | -LL | fn Foo_Method() {} - | ^^^^^^^^^^ help: convert the identifier to snake case: `foo_method` - | -note: the lint level is defined here - --> $DIR/lint-non-snake-case-functions.rs:1:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: method `foo__method` should have a snake case name - --> $DIR/lint-non-snake-case-functions.rs:11:8 - | -LL | fn foo__method(&self) {} - | ^^^^^^^^^^^ help: convert the identifier to snake case: `foo_method` - -error: method `xyZ` should have a snake case name - --> $DIR/lint-non-snake-case-functions.rs:14:12 - | -LL | pub fn xyZ(&mut self) {} - | ^^^ help: convert the identifier to snake case: `xy_z` - -error: method `render_HTML` should have a snake case name - --> $DIR/lint-non-snake-case-functions.rs:17:8 - | -LL | fn render_HTML() {} - | ^^^^^^^^^^^ help: convert the identifier to snake case: `render_html` - -error: trait method `ABC` should have a snake case name - --> $DIR/lint-non-snake-case-functions.rs:22:8 - | -LL | fn ABC(); - | ^^^ help: convert the identifier to snake case: `abc` - -error: trait method `a_b_C` should have a snake case name - --> $DIR/lint-non-snake-case-functions.rs:25:8 - | -LL | fn a_b_C(&self) {} - | ^^^^^ help: convert the identifier to snake case (notice the capitalization): `a_b_c` - -error: trait method `something__else` should have a snake case name - --> $DIR/lint-non-snake-case-functions.rs:28:8 - | -LL | fn something__else(&mut self); - | ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `something_else` - -error: function `Cookie` should have a snake case name - --> $DIR/lint-non-snake-case-functions.rs:38:4 - | -LL | fn Cookie() {} - | ^^^^^^ help: convert the identifier to snake case (notice the capitalization): `cookie` - -error: function `bi_S_Cuit` should have a snake case name - --> $DIR/lint-non-snake-case-functions.rs:41:8 - | -LL | pub fn bi_S_Cuit() {} - | ^^^^^^^^^ help: convert the identifier to snake case (notice the capitalization): `bi_s_cuit` - -error: aborting due to 9 previous errors - diff --git a/tests/ui/lint/lint-non-snake-case-identifiers-suggestion-reserved.rs b/tests/ui/lint/lint-non-snake-case-identifiers-suggestion-reserved.rs deleted file mode 100644 index 8cc4f976a4b..00000000000 --- a/tests/ui/lint/lint-non-snake-case-identifiers-suggestion-reserved.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![warn(unused)] -#![allow(dead_code)] -#![deny(non_snake_case)] - -mod Impl {} -//~^ ERROR module `Impl` should have a snake case name - -fn While() {} -//~^ ERROR function `While` should have a snake case name - -fn main() { - let Mod: usize = 0; - //~^ ERROR variable `Mod` should have a snake case name - //~^^ WARN unused variable: `Mod` - - let Super: usize = 0; - //~^ ERROR variable `Super` should have a snake case name - //~^^ WARN unused variable: `Super` -} diff --git a/tests/ui/lint/lint-non-snake-case-identifiers-suggestion-reserved.stderr b/tests/ui/lint/lint-non-snake-case-identifiers-suggestion-reserved.stderr deleted file mode 100644 index 2841815ecf2..00000000000 --- a/tests/ui/lint/lint-non-snake-case-identifiers-suggestion-reserved.stderr +++ /dev/null @@ -1,67 +0,0 @@ -warning: unused variable: `Mod` - --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:12:9 - | -LL | let Mod: usize = 0; - | ^^^ help: if this is intentional, prefix it with an underscore: `_Mod` - | -note: the lint level is defined here - --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:1:9 - | -LL | #![warn(unused)] - | ^^^^^^ - = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` - -warning: unused variable: `Super` - --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:16:9 - | -LL | let Super: usize = 0; - | ^^^^^ help: if this is intentional, prefix it with an underscore: `_Super` - -error: module `Impl` should have a snake case name - --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:5:5 - | -LL | mod Impl {} - | ^^^^ - | -note: the lint level is defined here - --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:3:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ -help: rename the identifier or convert it to a snake case raw identifier - | -LL | mod r#impl {} - | ~~~~~~ - -error: function `While` should have a snake case name - --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:8:4 - | -LL | fn While() {} - | ^^^^^ - | -help: rename the identifier or convert it to a snake case raw identifier - | -LL | fn r#while() {} - | ~~~~~~~ - -error: variable `Mod` should have a snake case name - --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:12:9 - | -LL | let Mod: usize = 0; - | ^^^ - | -help: rename the identifier or convert it to a snake case raw identifier - | -LL | let r#mod: usize = 0; - | ~~~~~ - -error: variable `Super` should have a snake case name - --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:16:9 - | -LL | let Super: usize = 0; - | ^^^^^ help: rename the identifier - | - = note: `super` cannot be used as a raw identifier - -error: aborting due to 4 previous errors; 2 warnings emitted - diff --git a/tests/ui/lint/lint-non-snake-case-lifetimes.rs b/tests/ui/lint/lint-non-snake-case-lifetimes.rs deleted file mode 100644 index de76d2dbef2..00000000000 --- a/tests/ui/lint/lint-non-snake-case-lifetimes.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![deny(non_snake_case)] -#![allow(dead_code)] - -fn f<'FooBar>( //~ ERROR lifetime `'FooBar` should have a snake case name - _: &'FooBar () -) {} - -fn main() { } diff --git a/tests/ui/lint/lint-non-snake-case-lifetimes.stderr b/tests/ui/lint/lint-non-snake-case-lifetimes.stderr deleted file mode 100644 index 8be7365cfc3..00000000000 --- a/tests/ui/lint/lint-non-snake-case-lifetimes.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: lifetime `'FooBar` should have a snake case name - --> $DIR/lint-non-snake-case-lifetimes.rs:4:6 - | -LL | fn f<'FooBar>( - | ^^^^^^^ help: convert the identifier to snake case: `'foo_bar` - | -note: the lint level is defined here - --> $DIR/lint-non-snake-case-lifetimes.rs:1:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/lint-non-snake-case-modules.rs b/tests/ui/lint/lint-non-snake-case-modules.rs deleted file mode 100644 index 73f12332172..00000000000 --- a/tests/ui/lint/lint-non-snake-case-modules.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![deny(non_snake_case)] -#![allow(dead_code)] - -mod FooBar { //~ ERROR module `FooBar` should have a snake case name - pub struct S; -} - -fn f(_: FooBar::S) { } - -fn main() { } diff --git a/tests/ui/lint/lint-non-snake-case-modules.stderr b/tests/ui/lint/lint-non-snake-case-modules.stderr deleted file mode 100644 index f21f9a934f3..00000000000 --- a/tests/ui/lint/lint-non-snake-case-modules.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: module `FooBar` should have a snake case name - --> $DIR/lint-non-snake-case-modules.rs:4:5 - | -LL | mod FooBar { - | ^^^^^^ help: convert the identifier to snake case: `foo_bar` - | -note: the lint level is defined here - --> $DIR/lint-non-snake-case-modules.rs:1:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/lint-non-snake-case-no-lowercase-equivalent.rs b/tests/ui/lint/lint-non-snake-case-no-lowercase-equivalent.rs deleted file mode 100644 index a43d2974ff3..00000000000 --- a/tests/ui/lint/lint-non-snake-case-no-lowercase-equivalent.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ check-pass - -#![allow(dead_code)] -//@ pretty-expanded FIXME #23616 - -#![deny(non_snake_case)] - -// This name is neither upper nor lower case -fn 你好() {} - -fn main() {} diff --git a/tests/ui/lint/lint-nonstandard-style-unicode-2.rs b/tests/ui/lint/lint-nonstandard-style-unicode-2.rs deleted file mode 100644 index 9690be5908b..00000000000 --- a/tests/ui/lint/lint-nonstandard-style-unicode-2.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![allow(dead_code)] - -#![forbid(non_snake_case)] - -// Some scripts (e.g., hiragana) don't have a concept of -// upper/lowercase - -// 2. non_snake_case - -// Can only use non-uppercase letters. -// So this works: - -fn 编程() {} - -// but this doesn't: - -fn Ц() {} -//~^ ERROR function `Ц` should have a snake case name - -// besides this, you cannot use continuous underscores in the middle - -fn 分__隔() {} -//~^ ERROR function `分__隔` should have a snake case name - -// but you can use them both at the beginning and at the end. - -fn _______不_连_续_的_存_在_______() {} - -fn main() {} diff --git a/tests/ui/lint/lint-nonstandard-style-unicode-2.stderr b/tests/ui/lint/lint-nonstandard-style-unicode-2.stderr deleted file mode 100644 index 8eb0654e0a1..00000000000 --- a/tests/ui/lint/lint-nonstandard-style-unicode-2.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: function `Ц` should have a snake case name - --> $DIR/lint-nonstandard-style-unicode-2.rs:17:4 - | -LL | fn Ц() {} - | ^ help: convert the identifier to snake case: `ц` - | -note: the lint level is defined here - --> $DIR/lint-nonstandard-style-unicode-2.rs:3:11 - | -LL | #![forbid(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: function `分__隔` should have a snake case name - --> $DIR/lint-nonstandard-style-unicode-2.rs:22:4 - | -LL | fn 分__隔() {} - | ^^^^^^ help: convert the identifier to snake case: `分_隔` - -error: aborting due to 2 previous errors - diff --git a/tests/ui/lint/lint-uppercase-variables.rs b/tests/ui/lint/lint-uppercase-variables.rs deleted file mode 100644 index 59dba536f24..00000000000 --- a/tests/ui/lint/lint-uppercase-variables.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![warn(unused)] -#![allow(dead_code)] -#![deny(non_snake_case)] - -mod foo { - pub enum Foo { Foo } -} - -struct Something { - X: usize //~ ERROR structure field `X` should have a snake case name -} - -fn test(Xx: usize) { //~ ERROR variable `Xx` should have a snake case name - println!("{}", Xx); -} - -fn main() { - let Test: usize = 0; //~ ERROR variable `Test` should have a snake case name - println!("{}", Test); - - match foo::Foo::Foo { - Foo => {} - //~^ ERROR variable `Foo` should have a snake case name - //~^^ ERROR `Foo` is named the same as one of the variants of the type `foo::Foo` - //~^^^ WARN unused variable: `Foo` - } - - let Foo = foo::Foo::Foo; - //~^ ERROR variable `Foo` should have a snake case name - //~^^ ERROR `Foo` is named the same as one of the variants of the type `foo::Foo` - //~^^^ WARN unused variable: `Foo` - - fn in_param(Foo: foo::Foo) {} - //~^ ERROR variable `Foo` should have a snake case name - //~^^ ERROR `Foo` is named the same as one of the variants of the type `foo::Foo` - //~^^^ WARN unused variable: `Foo` - - test(1); - - let _ = Something { X: 0 }; -} diff --git a/tests/ui/lint/lint-uppercase-variables.stderr b/tests/ui/lint/lint-uppercase-variables.stderr deleted file mode 100644 index 9220828014f..00000000000 --- a/tests/ui/lint/lint-uppercase-variables.stderr +++ /dev/null @@ -1,90 +0,0 @@ -error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` - --> $DIR/lint-uppercase-variables.rs:22:9 - | -LL | Foo => {} - | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` - | - = note: `#[deny(bindings_with_variant_name)]` on by default - -error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` - --> $DIR/lint-uppercase-variables.rs:28:9 - | -LL | let Foo = foo::Foo::Foo; - | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` - -warning: unused variable: `Foo` - --> $DIR/lint-uppercase-variables.rs:22:9 - | -LL | Foo => {} - | ^^^ help: if this is intentional, prefix it with an underscore: `_Foo` - | -note: the lint level is defined here - --> $DIR/lint-uppercase-variables.rs:1:9 - | -LL | #![warn(unused)] - | ^^^^^^ - = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` - -warning: unused variable: `Foo` - --> $DIR/lint-uppercase-variables.rs:28:9 - | -LL | let Foo = foo::Foo::Foo; - | ^^^ help: if this is intentional, prefix it with an underscore: `_Foo` - -error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` - --> $DIR/lint-uppercase-variables.rs:33:17 - | -LL | fn in_param(Foo: foo::Foo) {} - | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` - -warning: unused variable: `Foo` - --> $DIR/lint-uppercase-variables.rs:33:17 - | -LL | fn in_param(Foo: foo::Foo) {} - | ^^^ help: if this is intentional, prefix it with an underscore: `_Foo` - -error: structure field `X` should have a snake case name - --> $DIR/lint-uppercase-variables.rs:10:5 - | -LL | X: usize - | ^ help: convert the identifier to snake case (notice the capitalization): `x` - | -note: the lint level is defined here - --> $DIR/lint-uppercase-variables.rs:3:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: variable `Xx` should have a snake case name - --> $DIR/lint-uppercase-variables.rs:13:9 - | -LL | fn test(Xx: usize) { - | ^^ help: convert the identifier to snake case (notice the capitalization): `xx` - -error: variable `Test` should have a snake case name - --> $DIR/lint-uppercase-variables.rs:18:9 - | -LL | let Test: usize = 0; - | ^^^^ help: convert the identifier to snake case: `test` - -error: variable `Foo` should have a snake case name - --> $DIR/lint-uppercase-variables.rs:22:9 - | -LL | Foo => {} - | ^^^ help: convert the identifier to snake case (notice the capitalization): `foo` - -error: variable `Foo` should have a snake case name - --> $DIR/lint-uppercase-variables.rs:28:9 - | -LL | let Foo = foo::Foo::Foo; - | ^^^ help: convert the identifier to snake case (notice the capitalization): `foo` - -error: variable `Foo` should have a snake case name - --> $DIR/lint-uppercase-variables.rs:33:17 - | -LL | fn in_param(Foo: foo::Foo) {} - | ^^^ help: convert the identifier to snake case (notice the capitalization): `foo` - -error: aborting due to 9 previous errors; 3 warnings emitted - -For more information about this error, try `rustc --explain E0170`. diff --git a/tests/ui/lint/non-snake-case/allow-snake-case-field-destructuring-issue-89469.rs b/tests/ui/lint/non-snake-case/allow-snake-case-field-destructuring-issue-89469.rs new file mode 100644 index 00000000000..f691d6b5a92 --- /dev/null +++ b/tests/ui/lint/non-snake-case/allow-snake-case-field-destructuring-issue-89469.rs @@ -0,0 +1,20 @@ +// Regression test for #89469, where an extra non_snake_case warning was +// reported for a shorthand field binding. + +//@ check-pass +#![deny(non_snake_case)] + +#[allow(non_snake_case)] +struct Entry { + A: u16, + a: u16 +} + +fn foo() -> Entry {todo!()} + +pub fn f() { + let Entry { A, a } = foo(); + let _ = (A, a); +} + +fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin.rs new file mode 100644 index 00000000000..f8aad88ecee --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin.rs @@ -0,0 +1,7 @@ +//@ only-x86_64-unknown-linux-gnu +//@ check-pass +#![crate_name = "NonSnakeCase"] + +#![deny(non_snake_case)] + +fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin2.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin2.rs new file mode 100644 index 00000000000..c077d81e9e5 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin2.rs @@ -0,0 +1,7 @@ +//@ only-x86_64-unknown-linux-gnu +//@ compile-flags: --crate-name NonSnakeCase +//@ check-pass + +#![deny(non_snake_case)] + +fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin3.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin3.rs new file mode 100644 index 00000000000..278f7cfd3ee --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin3.rs @@ -0,0 +1,8 @@ +//@ only-x86_64-unknown-linux-gnu +//@ check-pass +#![crate_type = "bin"] +#![crate_name = "NonSnakeCase"] + +#![deny(non_snake_case)] + +fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.rs new file mode 100644 index 00000000000..781c6794fc2 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.rs @@ -0,0 +1,7 @@ +//@ only-x86_64-unknown-linux-gnu +#![crate_type = "cdylib"] +#![crate_name = "NonSnakeCase"] +//~^ ERROR crate `NonSnakeCase` should have a snake case name +#![deny(non_snake_case)] + +fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.stderr new file mode 100644 index 00000000000..f9167aa8df3 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.stderr @@ -0,0 +1,14 @@ +error: crate `NonSnakeCase` should have a snake case name + --> $DIR/lint-non-snake-case-crate-cdylib.rs:3:18 + | +LL | #![crate_name = "NonSnakeCase"] + | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` + | +note: the lint level is defined here + --> $DIR/lint-non-snake-case-crate-cdylib.rs:5:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.rs new file mode 100644 index 00000000000..3f65295f068 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.rs @@ -0,0 +1,7 @@ +//@ only-x86_64-unknown-linux-gnu +#![crate_type = "dylib"] +#![crate_name = "NonSnakeCase"] +//~^ ERROR crate `NonSnakeCase` should have a snake case name +#![deny(non_snake_case)] + +fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.stderr new file mode 100644 index 00000000000..4ee1a9cb3dd --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.stderr @@ -0,0 +1,14 @@ +error: crate `NonSnakeCase` should have a snake case name + --> $DIR/lint-non-snake-case-crate-dylib.rs:3:18 + | +LL | #![crate_name = "NonSnakeCase"] + | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` + | +note: the lint level is defined here + --> $DIR/lint-non-snake-case-crate-dylib.rs:5:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.rs new file mode 100644 index 00000000000..20c58e66aa6 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.rs @@ -0,0 +1,7 @@ +//@ only-x86_64-unknown-linux-gnu +#![crate_type = "lib"] +#![crate_name = "NonSnakeCase"] +//~^ ERROR crate `NonSnakeCase` should have a snake case name +#![deny(non_snake_case)] + +fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.stderr new file mode 100644 index 00000000000..a68c0e832b8 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.stderr @@ -0,0 +1,14 @@ +error: crate `NonSnakeCase` should have a snake case name + --> $DIR/lint-non-snake-case-crate-lib.rs:3:18 + | +LL | #![crate_name = "NonSnakeCase"] + | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` + | +note: the lint level is defined here + --> $DIR/lint-non-snake-case-crate-lib.rs:5:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.rs new file mode 100644 index 00000000000..f0f2fa4393e --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.rs @@ -0,0 +1,7 @@ +//@ only-x86_64-unknown-linux-gnu +#![crate_type = "proc-macro"] +#![crate_name = "NonSnakeCase"] +//~^ ERROR crate `NonSnakeCase` should have a snake case name +#![deny(non_snake_case)] + +fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.stderr new file mode 100644 index 00000000000..e0091057bc9 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.stderr @@ -0,0 +1,14 @@ +error: crate `NonSnakeCase` should have a snake case name + --> $DIR/lint-non-snake-case-crate-proc-macro.rs:3:18 + | +LL | #![crate_name = "NonSnakeCase"] + | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` + | +note: the lint level is defined here + --> $DIR/lint-non-snake-case-crate-proc-macro.rs:5:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.rs new file mode 100644 index 00000000000..1a558def3d0 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.rs @@ -0,0 +1,7 @@ +//@ only-x86_64-unknown-linux-gnu +#![crate_type = "rlib"] +#![crate_name = "NonSnakeCase"] +//~^ ERROR crate `NonSnakeCase` should have a snake case name +#![deny(non_snake_case)] + +fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.stderr new file mode 100644 index 00000000000..6e9d54bd5bc --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.stderr @@ -0,0 +1,14 @@ +error: crate `NonSnakeCase` should have a snake case name + --> $DIR/lint-non-snake-case-crate-rlib.rs:3:18 + | +LL | #![crate_name = "NonSnakeCase"] + | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` + | +note: the lint level is defined here + --> $DIR/lint-non-snake-case-crate-rlib.rs:5:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.rs new file mode 100644 index 00000000000..2ec53c15eb8 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.rs @@ -0,0 +1,7 @@ +//@ only-x86_64-unknown-linux-gnu +#![crate_type = "staticlib"] +#![crate_name = "NonSnakeCase"] +//~^ ERROR crate `NonSnakeCase` should have a snake case name +#![deny(non_snake_case)] + +fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.stderr new file mode 100644 index 00000000000..4ee6d5bd4d4 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.stderr @@ -0,0 +1,14 @@ +error: crate `NonSnakeCase` should have a snake case name + --> $DIR/lint-non-snake-case-crate-staticlib.rs:3:18 + | +LL | #![crate_name = "NonSnakeCase"] + | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` + | +note: the lint level is defined here + --> $DIR/lint-non-snake-case-crate-staticlib.rs:5:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-functions.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-functions.rs new file mode 100644 index 00000000000..fa64a9f980e --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-functions.rs @@ -0,0 +1,44 @@ +#![deny(non_snake_case)] +#![allow(dead_code)] + +struct Foo; + +impl Foo { + fn Foo_Method() {} + //~^ ERROR method `Foo_Method` should have a snake case name + + // Don't allow two underscores in a row + fn foo__method(&self) {} + //~^ ERROR method `foo__method` should have a snake case name + + pub fn xyZ(&mut self) {} + //~^ ERROR method `xyZ` should have a snake case name + + fn render_HTML() {} + //~^ ERROR method `render_HTML` should have a snake case name +} + +trait X { + fn ABC(); + //~^ ERROR trait method `ABC` should have a snake case name + + fn a_b_C(&self) {} + //~^ ERROR trait method `a_b_C` should have a snake case name + + fn something__else(&mut self); + //~^ ERROR trait method `something__else` should have a snake case name +} + +impl X for Foo { + // These errors should be caught at the trait definition not the impl + fn ABC() {} + fn something__else(&mut self) {} +} + +fn Cookie() {} +//~^ ERROR function `Cookie` should have a snake case name + +pub fn bi_S_Cuit() {} +//~^ ERROR function `bi_S_Cuit` should have a snake case name + +fn main() { } diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-functions.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-functions.stderr new file mode 100644 index 00000000000..f6ac6b99b60 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-functions.stderr @@ -0,0 +1,62 @@ +error: method `Foo_Method` should have a snake case name + --> $DIR/lint-non-snake-case-functions.rs:7:8 + | +LL | fn Foo_Method() {} + | ^^^^^^^^^^ help: convert the identifier to snake case: `foo_method` + | +note: the lint level is defined here + --> $DIR/lint-non-snake-case-functions.rs:1:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: method `foo__method` should have a snake case name + --> $DIR/lint-non-snake-case-functions.rs:11:8 + | +LL | fn foo__method(&self) {} + | ^^^^^^^^^^^ help: convert the identifier to snake case: `foo_method` + +error: method `xyZ` should have a snake case name + --> $DIR/lint-non-snake-case-functions.rs:14:12 + | +LL | pub fn xyZ(&mut self) {} + | ^^^ help: convert the identifier to snake case: `xy_z` + +error: method `render_HTML` should have a snake case name + --> $DIR/lint-non-snake-case-functions.rs:17:8 + | +LL | fn render_HTML() {} + | ^^^^^^^^^^^ help: convert the identifier to snake case: `render_html` + +error: trait method `ABC` should have a snake case name + --> $DIR/lint-non-snake-case-functions.rs:22:8 + | +LL | fn ABC(); + | ^^^ help: convert the identifier to snake case: `abc` + +error: trait method `a_b_C` should have a snake case name + --> $DIR/lint-non-snake-case-functions.rs:25:8 + | +LL | fn a_b_C(&self) {} + | ^^^^^ help: convert the identifier to snake case (notice the capitalization): `a_b_c` + +error: trait method `something__else` should have a snake case name + --> $DIR/lint-non-snake-case-functions.rs:28:8 + | +LL | fn something__else(&mut self); + | ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `something_else` + +error: function `Cookie` should have a snake case name + --> $DIR/lint-non-snake-case-functions.rs:38:4 + | +LL | fn Cookie() {} + | ^^^^^^ help: convert the identifier to snake case (notice the capitalization): `cookie` + +error: function `bi_S_Cuit` should have a snake case name + --> $DIR/lint-non-snake-case-functions.rs:41:8 + | +LL | pub fn bi_S_Cuit() {} + | ^^^^^^^^^ help: convert the identifier to snake case (notice the capitalization): `bi_s_cuit` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-identifiers-suggestion-reserved.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-identifiers-suggestion-reserved.rs new file mode 100644 index 00000000000..8cc4f976a4b --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-identifiers-suggestion-reserved.rs @@ -0,0 +1,19 @@ +#![warn(unused)] +#![allow(dead_code)] +#![deny(non_snake_case)] + +mod Impl {} +//~^ ERROR module `Impl` should have a snake case name + +fn While() {} +//~^ ERROR function `While` should have a snake case name + +fn main() { + let Mod: usize = 0; + //~^ ERROR variable `Mod` should have a snake case name + //~^^ WARN unused variable: `Mod` + + let Super: usize = 0; + //~^ ERROR variable `Super` should have a snake case name + //~^^ WARN unused variable: `Super` +} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-identifiers-suggestion-reserved.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-identifiers-suggestion-reserved.stderr new file mode 100644 index 00000000000..2841815ecf2 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-identifiers-suggestion-reserved.stderr @@ -0,0 +1,67 @@ +warning: unused variable: `Mod` + --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:12:9 + | +LL | let Mod: usize = 0; + | ^^^ help: if this is intentional, prefix it with an underscore: `_Mod` + | +note: the lint level is defined here + --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:1:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: unused variable: `Super` + --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:16:9 + | +LL | let Super: usize = 0; + | ^^^^^ help: if this is intentional, prefix it with an underscore: `_Super` + +error: module `Impl` should have a snake case name + --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:5:5 + | +LL | mod Impl {} + | ^^^^ + | +note: the lint level is defined here + --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:3:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ +help: rename the identifier or convert it to a snake case raw identifier + | +LL | mod r#impl {} + | ~~~~~~ + +error: function `While` should have a snake case name + --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:8:4 + | +LL | fn While() {} + | ^^^^^ + | +help: rename the identifier or convert it to a snake case raw identifier + | +LL | fn r#while() {} + | ~~~~~~~ + +error: variable `Mod` should have a snake case name + --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:12:9 + | +LL | let Mod: usize = 0; + | ^^^ + | +help: rename the identifier or convert it to a snake case raw identifier + | +LL | let r#mod: usize = 0; + | ~~~~~ + +error: variable `Super` should have a snake case name + --> $DIR/lint-non-snake-case-identifiers-suggestion-reserved.rs:16:9 + | +LL | let Super: usize = 0; + | ^^^^^ help: rename the identifier + | + = note: `super` cannot be used as a raw identifier + +error: aborting due to 4 previous errors; 2 warnings emitted + diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-lifetimes.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-lifetimes.rs new file mode 100644 index 00000000000..de76d2dbef2 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-lifetimes.rs @@ -0,0 +1,8 @@ +#![deny(non_snake_case)] +#![allow(dead_code)] + +fn f<'FooBar>( //~ ERROR lifetime `'FooBar` should have a snake case name + _: &'FooBar () +) {} + +fn main() { } diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-lifetimes.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-lifetimes.stderr new file mode 100644 index 00000000000..8be7365cfc3 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-lifetimes.stderr @@ -0,0 +1,14 @@ +error: lifetime `'FooBar` should have a snake case name + --> $DIR/lint-non-snake-case-lifetimes.rs:4:6 + | +LL | fn f<'FooBar>( + | ^^^^^^^ help: convert the identifier to snake case: `'foo_bar` + | +note: the lint level is defined here + --> $DIR/lint-non-snake-case-lifetimes.rs:1:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-modules.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-modules.rs new file mode 100644 index 00000000000..73f12332172 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-modules.rs @@ -0,0 +1,10 @@ +#![deny(non_snake_case)] +#![allow(dead_code)] + +mod FooBar { //~ ERROR module `FooBar` should have a snake case name + pub struct S; +} + +fn f(_: FooBar::S) { } + +fn main() { } diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-modules.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-modules.stderr new file mode 100644 index 00000000000..f21f9a934f3 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-modules.stderr @@ -0,0 +1,14 @@ +error: module `FooBar` should have a snake case name + --> $DIR/lint-non-snake-case-modules.rs:4:5 + | +LL | mod FooBar { + | ^^^^^^ help: convert the identifier to snake case: `foo_bar` + | +note: the lint level is defined here + --> $DIR/lint-non-snake-case-modules.rs:1:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-no-lowercase-equivalent.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-no-lowercase-equivalent.rs new file mode 100644 index 00000000000..a43d2974ff3 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-no-lowercase-equivalent.rs @@ -0,0 +1,11 @@ +//@ check-pass + +#![allow(dead_code)] +//@ pretty-expanded FIXME #23616 + +#![deny(non_snake_case)] + +// This name is neither upper nor lower case +fn 你好() {} + +fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-nonstandard-style-unicode-2.rs b/tests/ui/lint/non-snake-case/lint-nonstandard-style-unicode-2.rs new file mode 100644 index 00000000000..9690be5908b --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-nonstandard-style-unicode-2.rs @@ -0,0 +1,29 @@ +#![allow(dead_code)] + +#![forbid(non_snake_case)] + +// Some scripts (e.g., hiragana) don't have a concept of +// upper/lowercase + +// 2. non_snake_case + +// Can only use non-uppercase letters. +// So this works: + +fn 编程() {} + +// but this doesn't: + +fn Ц() {} +//~^ ERROR function `Ц` should have a snake case name + +// besides this, you cannot use continuous underscores in the middle + +fn 分__隔() {} +//~^ ERROR function `分__隔` should have a snake case name + +// but you can use them both at the beginning and at the end. + +fn _______不_连_续_的_存_在_______() {} + +fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-nonstandard-style-unicode-2.stderr b/tests/ui/lint/non-snake-case/lint-nonstandard-style-unicode-2.stderr new file mode 100644 index 00000000000..8eb0654e0a1 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-nonstandard-style-unicode-2.stderr @@ -0,0 +1,20 @@ +error: function `Ц` should have a snake case name + --> $DIR/lint-nonstandard-style-unicode-2.rs:17:4 + | +LL | fn Ц() {} + | ^ help: convert the identifier to snake case: `ц` + | +note: the lint level is defined here + --> $DIR/lint-nonstandard-style-unicode-2.rs:3:11 + | +LL | #![forbid(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: function `分__隔` should have a snake case name + --> $DIR/lint-nonstandard-style-unicode-2.rs:22:4 + | +LL | fn 分__隔() {} + | ^^^^^^ help: convert the identifier to snake case: `分_隔` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/non-snake-case/lint-uppercase-variables.rs b/tests/ui/lint/non-snake-case/lint-uppercase-variables.rs new file mode 100644 index 00000000000..59dba536f24 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-uppercase-variables.rs @@ -0,0 +1,41 @@ +#![warn(unused)] +#![allow(dead_code)] +#![deny(non_snake_case)] + +mod foo { + pub enum Foo { Foo } +} + +struct Something { + X: usize //~ ERROR structure field `X` should have a snake case name +} + +fn test(Xx: usize) { //~ ERROR variable `Xx` should have a snake case name + println!("{}", Xx); +} + +fn main() { + let Test: usize = 0; //~ ERROR variable `Test` should have a snake case name + println!("{}", Test); + + match foo::Foo::Foo { + Foo => {} + //~^ ERROR variable `Foo` should have a snake case name + //~^^ ERROR `Foo` is named the same as one of the variants of the type `foo::Foo` + //~^^^ WARN unused variable: `Foo` + } + + let Foo = foo::Foo::Foo; + //~^ ERROR variable `Foo` should have a snake case name + //~^^ ERROR `Foo` is named the same as one of the variants of the type `foo::Foo` + //~^^^ WARN unused variable: `Foo` + + fn in_param(Foo: foo::Foo) {} + //~^ ERROR variable `Foo` should have a snake case name + //~^^ ERROR `Foo` is named the same as one of the variants of the type `foo::Foo` + //~^^^ WARN unused variable: `Foo` + + test(1); + + let _ = Something { X: 0 }; +} diff --git a/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr b/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr new file mode 100644 index 00000000000..9220828014f --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr @@ -0,0 +1,90 @@ +error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` + --> $DIR/lint-uppercase-variables.rs:22:9 + | +LL | Foo => {} + | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` + | + = note: `#[deny(bindings_with_variant_name)]` on by default + +error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` + --> $DIR/lint-uppercase-variables.rs:28:9 + | +LL | let Foo = foo::Foo::Foo; + | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` + +warning: unused variable: `Foo` + --> $DIR/lint-uppercase-variables.rs:22:9 + | +LL | Foo => {} + | ^^^ help: if this is intentional, prefix it with an underscore: `_Foo` + | +note: the lint level is defined here + --> $DIR/lint-uppercase-variables.rs:1:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: unused variable: `Foo` + --> $DIR/lint-uppercase-variables.rs:28:9 + | +LL | let Foo = foo::Foo::Foo; + | ^^^ help: if this is intentional, prefix it with an underscore: `_Foo` + +error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` + --> $DIR/lint-uppercase-variables.rs:33:17 + | +LL | fn in_param(Foo: foo::Foo) {} + | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` + +warning: unused variable: `Foo` + --> $DIR/lint-uppercase-variables.rs:33:17 + | +LL | fn in_param(Foo: foo::Foo) {} + | ^^^ help: if this is intentional, prefix it with an underscore: `_Foo` + +error: structure field `X` should have a snake case name + --> $DIR/lint-uppercase-variables.rs:10:5 + | +LL | X: usize + | ^ help: convert the identifier to snake case (notice the capitalization): `x` + | +note: the lint level is defined here + --> $DIR/lint-uppercase-variables.rs:3:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: variable `Xx` should have a snake case name + --> $DIR/lint-uppercase-variables.rs:13:9 + | +LL | fn test(Xx: usize) { + | ^^ help: convert the identifier to snake case (notice the capitalization): `xx` + +error: variable `Test` should have a snake case name + --> $DIR/lint-uppercase-variables.rs:18:9 + | +LL | let Test: usize = 0; + | ^^^^ help: convert the identifier to snake case: `test` + +error: variable `Foo` should have a snake case name + --> $DIR/lint-uppercase-variables.rs:22:9 + | +LL | Foo => {} + | ^^^ help: convert the identifier to snake case (notice the capitalization): `foo` + +error: variable `Foo` should have a snake case name + --> $DIR/lint-uppercase-variables.rs:28:9 + | +LL | let Foo = foo::Foo::Foo; + | ^^^ help: convert the identifier to snake case (notice the capitalization): `foo` + +error: variable `Foo` should have a snake case name + --> $DIR/lint-uppercase-variables.rs:33:17 + | +LL | fn in_param(Foo: foo::Foo) {} + | ^^^ help: convert the identifier to snake case (notice the capitalization): `foo` + +error: aborting due to 9 previous errors; 3 warnings emitted + +For more information about this error, try `rustc --explain E0170`. diff --git a/tests/ui/lint/non-snake-case/no-snake-case-warning-for-field-puns-issue-66362.rs b/tests/ui/lint/non-snake-case/no-snake-case-warning-for-field-puns-issue-66362.rs new file mode 100644 index 00000000000..c2b81959f2c --- /dev/null +++ b/tests/ui/lint/non-snake-case/no-snake-case-warning-for-field-puns-issue-66362.rs @@ -0,0 +1,29 @@ +#![deny(non_snake_case)] +#![allow(unused_variables)] +#![allow(dead_code)] + +enum Foo { + Bad { + lowerCamelCaseName: bool, + //~^ ERROR structure field `lowerCamelCaseName` should have a snake case name + }, + Good { + snake_case_name: bool, + }, +} + +fn main() { + let b = Foo::Bad { lowerCamelCaseName: true }; + + match b { + Foo::Bad { lowerCamelCaseName } => {} + Foo::Good { snake_case_name: lowerCamelCaseBinding } => { } + //~^ ERROR variable `lowerCamelCaseBinding` should have a snake case name + } + + if let Foo::Good { snake_case_name: anotherLowerCamelCaseBinding } = b { } + //~^ ERROR variable `anotherLowerCamelCaseBinding` should have a snake case name + + if let Foo::Bad { lowerCamelCaseName: yetAnotherLowerCamelCaseBinding } = b { } + //~^ ERROR variable `yetAnotherLowerCamelCaseBinding` should have a snake case name +} diff --git a/tests/ui/lint/non-snake-case/no-snake-case-warning-for-field-puns-issue-66362.stderr b/tests/ui/lint/non-snake-case/no-snake-case-warning-for-field-puns-issue-66362.stderr new file mode 100644 index 00000000000..cbbcf990918 --- /dev/null +++ b/tests/ui/lint/non-snake-case/no-snake-case-warning-for-field-puns-issue-66362.stderr @@ -0,0 +1,32 @@ +error: structure field `lowerCamelCaseName` should have a snake case name + --> $DIR/no-snake-case-warning-for-field-puns-issue-66362.rs:7:9 + | +LL | lowerCamelCaseName: bool, + | ^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `lower_camel_case_name` + | +note: the lint level is defined here + --> $DIR/no-snake-case-warning-for-field-puns-issue-66362.rs:1:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: variable `lowerCamelCaseBinding` should have a snake case name + --> $DIR/no-snake-case-warning-for-field-puns-issue-66362.rs:20:38 + | +LL | Foo::Good { snake_case_name: lowerCamelCaseBinding } => { } + | ^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `lower_camel_case_binding` + +error: variable `anotherLowerCamelCaseBinding` should have a snake case name + --> $DIR/no-snake-case-warning-for-field-puns-issue-66362.rs:24:41 + | +LL | if let Foo::Good { snake_case_name: anotherLowerCamelCaseBinding } = b { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `another_lower_camel_case_binding` + +error: variable `yetAnotherLowerCamelCaseBinding` should have a snake case name + --> $DIR/no-snake-case-warning-for-field-puns-issue-66362.rs:27:43 + | +LL | if let Foo::Bad { lowerCamelCaseName: yetAnotherLowerCamelCaseBinding } = b { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `yet_another_lower_camel_case_binding` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lint/non-snake-case/non-snake-ffi-issue-31924.rs b/tests/ui/lint/non-snake-case/non-snake-ffi-issue-31924.rs new file mode 100644 index 00000000000..ade4e630fb2 --- /dev/null +++ b/tests/ui/lint/non-snake-case/non-snake-ffi-issue-31924.rs @@ -0,0 +1,15 @@ +//@ check-pass + +#![deny(non_snake_case)] + +#[no_mangle] +pub extern "C" fn SparklingGenerationForeignFunctionInterface() {} // OK + +pub struct Foo; + +impl Foo { + #[no_mangle] + pub extern "C" fn SparklingGenerationForeignFunctionInterface() {} // OK +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From d69f08853827fdec134d2be93d21a0e797ea619e Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 15 Jun 2024 20:36:54 +0300 Subject: fix build with html5ever bump --- src/tools/linkchecker/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 32f935de730..7321bd1bb52 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -503,7 +503,7 @@ fn maybe_redirect(source: &str) -> Option { fn parse_html(source: &str, sink: Sink) -> Sink { let tendril: ByteTendril = source.as_bytes().into(); - let mut input = BufferQueue::new(); + let mut input = BufferQueue::default(); input.push_back(tendril.try_reinterpret().unwrap()); let mut tok = Tokenizer::new(sink, TokenizerOpts::default()); -- cgit 1.4.1-3-g733a5 From 729ed8194f01f2b2e97fbb874c360bf52884e785 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 16 Jun 2024 00:18:06 +0000 Subject: cargo update Locking 18 packages to latest compatible versions Updating annotate-snippets v0.11.3 -> v0.11.4 Updating clap v4.5.6 -> v4.5.7 Updating clap_builder v4.5.6 -> v4.5.7 Updating derive_more v0.99.17 -> v0.99.18 Adding icu_collections v1.5.0 Adding icu_normalizer v1.5.0 Adding icu_normalizer_data v1.5.0 Adding icu_properties v1.5.0 Adding icu_properties_data v1.5.0 Updating idna v0.5.0 -> v1.0.0 Updating mdbook-i18n-helpers v0.3.3 -> v0.3.4 Updating redox_syscall v0.5.1 -> v0.5.2 Updating regex-lite v0.1.5 -> v0.1.6 Updating regex-syntax v0.8.3 -> v0.8.4 Removing unicode-bidi v0.3.15 Updating url v2.5.0 -> v2.5.1 Adding utf16_iter v1.0.5 Adding utf8_iter v1.0.4 Adding write16 v1.0.0 note: pass `--verbose` to see 88 unchanged dependencies behind latest --- Cargo.lock | 137 ++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 104 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 138e00adc49..28231a4c5ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "annotate-snippets" -version = "0.11.3" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "086b0afab3b349e5691143adbfb26983821e3eec4ba4c51957104d372c2e1b7d" +checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991" dependencies = [ "anstyle", "unicode-width", @@ -568,9 +568,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.6" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9689a29b593160de5bc4aacab7b5d54fb52231de70122626c178e6a368994c7" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" dependencies = [ "clap_builder", "clap_derive", @@ -588,9 +588,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.6" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5387378c84f6faa26890ebf9f0a92989f8873d4d380467bcd0d8d8620424df" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" dependencies = [ "anstream", "anstyle", @@ -688,7 +688,7 @@ dependencies = [ "itertools 0.12.1", "quine-mc_cluskey", "regex", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", "rustc-semver", "semver", "serde", @@ -1083,13 +1083,13 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.66", ] [[package]] @@ -1804,6 +1804,18 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + [[package]] name = "icu_list" version = "1.5.0" @@ -1857,6 +1869,51 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + [[package]] name = "icu_provider" version = "1.5.0" @@ -1906,12 +1963,14 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", + "smallvec", + "utf8_iter", ] [[package]] @@ -2393,9 +2452,9 @@ dependencies = [ [[package]] name = "mdbook-i18n-helpers" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f71f5961d6f3376e1ff3e5989c2e3ecccc3e8a00f3a3acde446847f84852e4" +checksum = "8c8f972ab672d366c3dad77ea5aa7bae68db2d25fbeb889849f97469d7b658e4" dependencies = [ "anyhow", "chrono", @@ -2871,7 +2930,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "smallvec", "windows-targets 0.52.5", ] @@ -3350,9 +3409,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ "bitflags 2.5.0", ] @@ -3411,9 +3470,9 @@ dependencies = [ [[package]] name = "regex-lite" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" [[package]] name = "regex-syntax" @@ -3429,9 +3488,9 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "remote-test-client" @@ -5484,7 +5543,7 @@ dependencies = [ "once_cell", "onig", "plist", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", "serde", "serde_derive", "serde_json", @@ -5997,7 +6056,7 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29e5f4ffcbab82453958fbf59990e981b8e8a177dcd60c2bd8f9b52c3036a6e1" dependencies = [ - "annotate-snippets 0.11.3", + "annotate-snippets 0.11.4", "anyhow", "bstr", "cargo-platform", @@ -6078,12 +6137,6 @@ dependencies = [ "ucd-parse", ] -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" version = "1.0.12" @@ -6185,9 +6238,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" dependencies = [ "form_urlencoded", "idna", @@ -6200,12 +6253,24 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + [[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -6569,6 +6634,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + [[package]] name = "writeable" version = "0.5.5" -- cgit 1.4.1-3-g733a5 From 33c4817d98850ce90dd18a7e80bd04ca05dafaee Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 11 Jun 2024 21:26:41 -0700 Subject: Redo SliceIndex implementations --- library/core/src/slice/index.rs | 118 +++++++++++++++------ tests/mir-opt/pre-codegen/slice_index.rs | 26 ++++- ..._get_mut_usize.PreCodegen.after.panic-abort.mir | 43 +++++++- ...get_mut_usize.PreCodegen.after.panic-unwind.mir | 43 +++++++- ...cked_mut_range.PreCodegen.after.panic-abort.mir | 56 ++++++++-- ...ked_mut_range.PreCodegen.after.panic-unwind.mir | 56 ++++++++-- ...nchecked_range.PreCodegen.after.panic-abort.mir | 40 ++++++- ...checked_range.PreCodegen.after.panic-unwind.mir | 40 ++++++- 8 files changed, 371 insertions(+), 51 deletions(-) diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 98513340a47..143dbd8a496 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -2,7 +2,6 @@ use crate::intrinsics::const_eval_select; use crate::ops; -use crate::ptr; use crate::ub_checks::assert_unsafe_precondition; #[stable(feature = "rust1", since = "1.0.0")] @@ -106,6 +105,47 @@ const fn slice_end_index_overflow_fail() -> ! { panic!("attempted to index slice up to maximum usize"); } +// The UbChecks are great for catching bugs in the unsafe methods, but including +// them in safe indexing is unnecessary and hurts inlining and debug runtime perf. +// Both the safe and unsafe public methods share these helpers, +// which use intrinsics directly to get *no* extra checks. + +#[inline(always)] +const unsafe fn get_noubcheck(ptr: *const [T], index: usize) -> *const T { + let ptr = ptr as *const T; + // SAFETY: The caller already checked these preconditions + unsafe { crate::intrinsics::offset(ptr, index) } +} + +#[inline(always)] +const unsafe fn get_mut_noubcheck(ptr: *mut [T], index: usize) -> *mut T { + let ptr = ptr as *mut T; + // SAFETY: The caller already checked these preconditions + unsafe { crate::intrinsics::offset(ptr, index) } +} + +#[inline(always)] +const unsafe fn get_offset_len_noubcheck( + ptr: *const [T], + offset: usize, + len: usize, +) -> *const [T] { + // SAFETY: The caller already checked these preconditions + let ptr = unsafe { get_noubcheck(ptr, offset) }; + crate::intrinsics::aggregate_raw_ptr(ptr, len) +} + +#[inline(always)] +const unsafe fn get_offset_len_mut_noubcheck( + ptr: *mut [T], + offset: usize, + len: usize, +) -> *mut [T] { + // SAFETY: The caller already checked these preconditions + let ptr = unsafe { get_mut_noubcheck(ptr, offset) }; + crate::intrinsics::aggregate_raw_ptr(ptr, len) +} + mod private_slice_index { use super::ops; #[stable(feature = "slice_get_slice", since = "1.28.0")] @@ -203,13 +243,17 @@ unsafe impl SliceIndex<[T]> for usize { #[inline] fn get(self, slice: &[T]) -> Option<&T> { // SAFETY: `self` is checked to be in bounds. - if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None } + if self < slice.len() { unsafe { Some(&*get_noubcheck(slice, self)) } } else { None } } #[inline] fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { - // SAFETY: `self` is checked to be in bounds. - if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None } + if self < slice.len() { + // SAFETY: `self` is checked to be in bounds. + unsafe { Some(&mut *get_mut_noubcheck(slice, self)) } + } else { + None + } } #[inline] @@ -227,7 +271,7 @@ unsafe impl SliceIndex<[T]> for usize { // Use intrinsics::assume instead of hint::assert_unchecked so that we don't check the // precondition of this function twice. crate::intrinsics::assume(self < slice.len()); - slice.as_ptr().add(self) + get_noubcheck(slice, self) } } @@ -239,7 +283,7 @@ unsafe impl SliceIndex<[T]> for usize { (this: usize = self, len: usize = slice.len()) => this < len ); // SAFETY: see comments for `get_unchecked` above. - unsafe { slice.as_mut_ptr().add(self) } + unsafe { get_mut_noubcheck(slice, self) } } #[inline] @@ -265,7 +309,7 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { fn get(self, slice: &[T]) -> Option<&[T]> { if self.end() <= slice.len() { // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&*self.get_unchecked(slice)) } + unsafe { Some(&*get_offset_len_noubcheck(slice, self.start(), self.len())) } } else { None } @@ -275,7 +319,7 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { if self.end() <= slice.len() { // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&mut *self.get_unchecked_mut(slice)) } + unsafe { Some(&mut *get_offset_len_mut_noubcheck(slice, self.start(), self.len())) } } else { None } @@ -292,7 +336,7 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. - unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start()), self.len()) } + unsafe { get_offset_len_noubcheck(slice, self.start(), self.len()) } } #[inline] @@ -304,14 +348,14 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { ); // SAFETY: see comments for `get_unchecked` above. - unsafe { ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start()), self.len()) } + unsafe { get_offset_len_mut_noubcheck(slice, self.start(), self.len()) } } #[inline] fn index(self, slice: &[T]) -> &[T] { if self.end() <= slice.len() { // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &*self.get_unchecked(slice) } + unsafe { &*get_offset_len_noubcheck(slice, self.start(), self.len()) } } else { slice_end_index_len_fail(self.end(), slice.len()) } @@ -321,7 +365,7 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { fn index_mut(self, slice: &mut [T]) -> &mut [T] { if self.end() <= slice.len() { // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &mut *self.get_unchecked_mut(slice) } + unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start(), self.len()) } } else { slice_end_index_len_fail(self.end(), slice.len()) } @@ -338,21 +382,26 @@ unsafe impl SliceIndex<[T]> for ops::Range { #[inline] fn get(self, slice: &[T]) -> Option<&[T]> { - if self.start > self.end || self.end > slice.len() { - None - } else { + // Using checked_sub is a safe way to get `SubUnchecked` in MIR + if let Some(new_len) = usize::checked_sub(self.end, self.start) + && self.end <= slice.len() + { // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&*self.get_unchecked(slice)) } + unsafe { Some(&*get_offset_len_noubcheck(slice, self.start, new_len)) } + } else { + None } } #[inline] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - if self.start > self.end || self.end > slice.len() { - None - } else { + if let Some(new_len) = usize::checked_sub(self.end, self.start) + && self.end <= slice.len() + { // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&mut *self.get_unchecked_mut(slice)) } + unsafe { Some(&mut *get_offset_len_mut_noubcheck(slice, self.start, new_len)) } + } else { + None } } @@ -373,8 +422,10 @@ unsafe impl SliceIndex<[T]> for ops::Range { // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe and the length calculation cannot overflow. unsafe { - let new_len = self.end.unchecked_sub(self.start); - ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) + // Using the intrinsic avoids a superfluous UB check, + // since the one on this method already checked `end >= start`. + let new_len = crate::intrinsics::unchecked_sub(self.end, self.start); + get_offset_len_noubcheck(slice, self.start, new_len) } } @@ -391,31 +442,34 @@ unsafe impl SliceIndex<[T]> for ops::Range { ); // SAFETY: see comments for `get_unchecked` above. unsafe { - let new_len = self.end.unchecked_sub(self.start); - ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) + let new_len = crate::intrinsics::unchecked_sub(self.end, self.start); + get_offset_len_mut_noubcheck(slice, self.start, new_len) } } #[inline(always)] fn index(self, slice: &[T]) -> &[T] { - if self.start > self.end { - slice_index_order_fail(self.start, self.end); - } else if self.end > slice.len() { + // Using checked_sub is a safe way to get `SubUnchecked` in MIR + let Some(new_len) = usize::checked_sub(self.end, self.start) else { + slice_index_order_fail(self.start, self.end) + }; + if self.end > slice.len() { slice_end_index_len_fail(self.end, slice.len()); } // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &*self.get_unchecked(slice) } + unsafe { &*get_offset_len_noubcheck(slice, self.start, new_len) } } #[inline] fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if self.start > self.end { - slice_index_order_fail(self.start, self.end); - } else if self.end > slice.len() { + let Some(new_len) = usize::checked_sub(self.end, self.start) else { + slice_index_order_fail(self.start, self.end) + }; + if self.end > slice.len() { slice_end_index_len_fail(self.end, slice.len()); } // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &mut *self.get_unchecked_mut(slice) } + unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start, new_len) } } } diff --git a/tests/mir-opt/pre-codegen/slice_index.rs b/tests/mir-opt/pre-codegen/slice_index.rs index 88b99777dd9..886e57a3380 100644 --- a/tests/mir-opt/pre-codegen/slice_index.rs +++ b/tests/mir-opt/pre-codegen/slice_index.rs @@ -1,4 +1,3 @@ -// skip-filecheck //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -Z ub-checks=yes // EMIT_MIR_FOR_EACH_PANIC_STRATEGY @@ -9,21 +8,39 @@ use std::ops::Range; // EMIT_MIR slice_index.slice_index_usize.PreCodegen.after.mir pub fn slice_index_usize(slice: &[u32], index: usize) -> u32 { + // CHECK-LABEL: slice_index_usize + // CHECK: [[LEN:_[0-9]+]] = Len((*_1)) + // CHECK: Lt(_2, [[LEN]]) + // CHECK-NOT: precondition_check + // CHECK: _0 = (*_1)[_2]; slice[index] } // EMIT_MIR slice_index.slice_get_mut_usize.PreCodegen.after.mir pub fn slice_get_mut_usize(slice: &mut [u32], index: usize) -> Option<&mut u32> { + // CHECK-LABEL: slice_get_mut_usize + // CHECK: [[LEN:_[0-9]+]] = Len((*_1)) + // CHECK: Lt(_2, move [[LEN]]) + // CHECK-NOT: precondition_check slice.get_mut(index) } // EMIT_MIR slice_index.slice_index_range.PreCodegen.after.mir pub fn slice_index_range(slice: &[u32], index: Range) -> &[u32] { + // CHECK-LABEL: slice_index_range &slice[index] } // EMIT_MIR slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir pub unsafe fn slice_get_unchecked_mut_range(slice: &mut [u32], index: Range) -> &mut [u32] { + // CHECK-LABEL: slice_get_unchecked_mut_range + // CHECK: [[START:_[0-9]+]] = move (_2.0: usize); + // CHECK: [[END:_[0-9]+]] = move (_2.1: usize); + // CHECK: precondition_check + // CHECK: [[LEN:_[0-9]+]] = SubUnchecked([[END]], [[START]]); + // CHECK: [[PTR:_[0-9]+]] = Offset({{_[0-9]+}}, [[START]]); + // CHECK: [[SLICE:_[0-9]+]] = *mut [u32] from ([[PTR]], [[LEN]]) + // CHECK: _0 = &mut (*[[SLICE]]); slice.get_unchecked_mut(index) } @@ -32,5 +49,12 @@ pub unsafe fn slice_ptr_get_unchecked_range( slice: *const [u32], index: Range, ) -> *const [u32] { + // CHECK-LABEL: slice_ptr_get_unchecked_range + // CHECK: [[START:_[0-9]+]] = move (_2.0: usize); + // CHECK: [[END:_[0-9]+]] = move (_2.1: usize); + // CHECK: precondition_check + // CHECK: [[LEN:_[0-9]+]] = SubUnchecked([[END]], [[START]]); + // CHECK: [[PTR:_[0-9]+]] = Offset({{_[0-9]+}}, [[START]]); + // CHECK: _0 = *const [u32] from ([[PTR]], [[LEN]]) slice.get_unchecked(index) } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir index 7e20817cf23..f2ef2b0cc3c 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir @@ -5,13 +5,54 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { debug index => _2; let mut _0: std::option::Option<&mut u32>; scope 1 (inlined core::slice::::get_mut::) { + scope 2 (inlined >::get_mut) { + let mut _3: usize; + let mut _4: bool; + let mut _5: *mut [u32]; + let mut _7: *mut u32; + let mut _8: &mut u32; + scope 3 (inlined core::slice::index::get_mut_noubcheck::) { + let _6: *mut u32; + scope 4 { + } + } + } } bb0: { - _0 = >::get_mut(move _2, move _1) -> [return: bb1, unwind unreachable]; + StorageLive(_7); + StorageLive(_4); + StorageLive(_3); + _3 = Len((*_1)); + _4 = Lt(_2, move _3); + switchInt(move _4) -> [0: bb1, otherwise: bb2]; } bb1: { + StorageDead(_3); + _0 = const Option::<&mut u32>::None; + goto -> bb3; + } + + bb2: { + StorageDead(_3); + StorageLive(_8); + StorageLive(_5); + _5 = &raw mut (*_1); + StorageLive(_6); + _6 = _5 as *mut u32 (PtrToPtr); + _7 = Offset(_6, _2); + StorageDead(_6); + StorageDead(_5); + _8 = &mut (*_7); + _0 = Option::<&mut u32>::Some(move _8); + StorageDead(_8); + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_7); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir index 2f65b8c6401..f2ef2b0cc3c 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir @@ -5,13 +5,54 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { debug index => _2; let mut _0: std::option::Option<&mut u32>; scope 1 (inlined core::slice::::get_mut::) { + scope 2 (inlined >::get_mut) { + let mut _3: usize; + let mut _4: bool; + let mut _5: *mut [u32]; + let mut _7: *mut u32; + let mut _8: &mut u32; + scope 3 (inlined core::slice::index::get_mut_noubcheck::) { + let _6: *mut u32; + scope 4 { + } + } + } } bb0: { - _0 = >::get_mut(move _2, move _1) -> [return: bb1, unwind continue]; + StorageLive(_7); + StorageLive(_4); + StorageLive(_3); + _3 = Len((*_1)); + _4 = Lt(_2, move _3); + switchInt(move _4) -> [0: bb1, otherwise: bb2]; } bb1: { + StorageDead(_3); + _0 = const Option::<&mut u32>::None; + goto -> bb3; + } + + bb2: { + StorageDead(_3); + StorageLive(_8); + StorageLive(_5); + _5 = &raw mut (*_1); + StorageLive(_6); + _6 = _5 as *mut u32 (PtrToPtr); + _7 = Offset(_6, _2); + StorageDead(_6); + StorageDead(_5); + _8 = &mut (*_7); + _0 = Option::<&mut u32>::Some(move _8); + StorageDead(_8); + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_7); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index ef3f4a21720..5e0398d1114 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -4,20 +4,62 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _1; debug index => _2; let mut _0: &mut [u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { - let mut _3: *mut [u32]; - let mut _4: *mut [u32]; + let mut _5: *mut [u32]; + let mut _12: *mut [u32]; + scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { + let mut _7: usize; + let _8: (); + let _9: usize; + scope 3 { + scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::) { + let _11: *mut u32; + scope 7 { + } + scope 8 (inlined core::slice::index::get_mut_noubcheck::) { + let _10: *mut u32; + scope 9 { + } + } + } + } + scope 4 (inlined std::ptr::mut_ptr::::len) { + let mut _6: *const [u32]; + scope 5 (inlined std::ptr::metadata::<[u32]>) { + } + } + } } bb0: { - StorageLive(_3); - _3 = &raw mut (*_1); - _4 = as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind unreachable]; + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_5); + _5 = &raw mut (*_1); + StorageLive(_9); + StorageLive(_7); + StorageLive(_6); + _6 = _5 as *const [u32] (PointerCoercion(MutToConstPointer)); + _7 = PtrMetadata(_6); + StorageDead(_6); + _8 = as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(_3, _4, move _7) -> [return: bb1, unwind unreachable]; } bb1: { - StorageDead(_3); - _0 = &mut (*_4); + StorageDead(_7); + _9 = SubUnchecked(_4, _3); + StorageLive(_11); + StorageLive(_10); + _10 = _5 as *mut u32 (PtrToPtr); + _11 = Offset(_10, _3); + StorageDead(_10); + _12 = *mut [u32] from (_11, _9); + StorageDead(_11); + StorageDead(_9); + StorageDead(_5); + _0 = &mut (*_12); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 9e93a43ac72..5e0398d1114 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -4,20 +4,62 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _1; debug index => _2; let mut _0: &mut [u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { - let mut _3: *mut [u32]; - let mut _4: *mut [u32]; + let mut _5: *mut [u32]; + let mut _12: *mut [u32]; + scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { + let mut _7: usize; + let _8: (); + let _9: usize; + scope 3 { + scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::) { + let _11: *mut u32; + scope 7 { + } + scope 8 (inlined core::slice::index::get_mut_noubcheck::) { + let _10: *mut u32; + scope 9 { + } + } + } + } + scope 4 (inlined std::ptr::mut_ptr::::len) { + let mut _6: *const [u32]; + scope 5 (inlined std::ptr::metadata::<[u32]>) { + } + } + } } bb0: { - StorageLive(_3); - _3 = &raw mut (*_1); - _4 = as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind continue]; + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_5); + _5 = &raw mut (*_1); + StorageLive(_9); + StorageLive(_7); + StorageLive(_6); + _6 = _5 as *const [u32] (PointerCoercion(MutToConstPointer)); + _7 = PtrMetadata(_6); + StorageDead(_6); + _8 = as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(_3, _4, move _7) -> [return: bb1, unwind unreachable]; } bb1: { - StorageDead(_3); - _0 = &mut (*_4); + StorageDead(_7); + _9 = SubUnchecked(_4, _3); + StorageLive(_11); + StorageLive(_10); + _10 = _5 as *mut u32 (PtrToPtr); + _11 = Offset(_10, _3); + StorageDead(_10); + _12 = *mut [u32] from (_11, _9); + StorageDead(_11); + StorageDead(_9); + StorageDead(_5); + _0 = &mut (*_12); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir index 650069ee6ce..c61bebe6cc3 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir @@ -4,14 +4,52 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - debug slice => _1; debug index => _2; let mut _0: *const [u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined std::ptr::const_ptr::::get_unchecked::>) { + scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked) { + let mut _5: usize; + let _6: (); + let _7: usize; + scope 3 { + scope 6 (inlined core::slice::index::get_offset_len_noubcheck::) { + let _9: *const u32; + scope 7 { + } + scope 8 (inlined core::slice::index::get_noubcheck::) { + let _8: *const u32; + scope 9 { + } + } + } + } + scope 4 (inlined std::ptr::const_ptr::::len) { + scope 5 (inlined std::ptr::metadata::<[u32]>) { + } + } + } } bb0: { - _0 = as SliceIndex<[u32]>>::get_unchecked(move _2, move _1) -> [return: bb1, unwind unreachable]; + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_7); + StorageLive(_5); + _5 = PtrMetadata(_1); + _6 = as SliceIndex<[T]>>::get_unchecked::precondition_check(_3, _4, move _5) -> [return: bb1, unwind unreachable]; } bb1: { + StorageDead(_5); + _7 = SubUnchecked(_4, _3); + StorageLive(_9); + StorageLive(_8); + _8 = _1 as *const u32 (PtrToPtr); + _9 = Offset(_8, _3); + StorageDead(_8); + _0 = *const [u32] from (_9, _7); + StorageDead(_9); + StorageDead(_7); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir index 74e8158e754..c61bebe6cc3 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir @@ -4,14 +4,52 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - debug slice => _1; debug index => _2; let mut _0: *const [u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined std::ptr::const_ptr::::get_unchecked::>) { + scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked) { + let mut _5: usize; + let _6: (); + let _7: usize; + scope 3 { + scope 6 (inlined core::slice::index::get_offset_len_noubcheck::) { + let _9: *const u32; + scope 7 { + } + scope 8 (inlined core::slice::index::get_noubcheck::) { + let _8: *const u32; + scope 9 { + } + } + } + } + scope 4 (inlined std::ptr::const_ptr::::len) { + scope 5 (inlined std::ptr::metadata::<[u32]>) { + } + } + } } bb0: { - _0 = as SliceIndex<[u32]>>::get_unchecked(move _2, move _1) -> [return: bb1, unwind continue]; + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_7); + StorageLive(_5); + _5 = PtrMetadata(_1); + _6 = as SliceIndex<[T]>>::get_unchecked::precondition_check(_3, _4, move _5) -> [return: bb1, unwind unreachable]; } bb1: { + StorageDead(_5); + _7 = SubUnchecked(_4, _3); + StorageLive(_9); + StorageLive(_8); + _8 = _1 as *const u32 (PtrToPtr); + _9 = Offset(_8, _3); + StorageDead(_8); + _0 = *const [u32] from (_9, _7); + StorageDead(_9); + StorageDead(_7); return; } } -- cgit 1.4.1-3-g733a5 From 89df41636b5b7a530c88ebf2e986431c5a6a6341 Mon Sep 17 00:00:00 2001 From: Jerry Wang Date: Sat, 15 Jun 2024 22:58:58 -0400 Subject: Remove `run-make-support/src/llvm_readobj.rs` --- src/tools/run-make-support/src/llvm_readobj.rs | 45 -------------------------- 1 file changed, 45 deletions(-) delete mode 100644 src/tools/run-make-support/src/llvm_readobj.rs diff --git a/src/tools/run-make-support/src/llvm_readobj.rs b/src/tools/run-make-support/src/llvm_readobj.rs deleted file mode 100644 index 3c719356e8f..00000000000 --- a/src/tools/run-make-support/src/llvm_readobj.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::path::{Path, PathBuf}; - -use crate::command::Command; -use crate::env_var; - -/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available -/// at `$LLVM_BIN_DIR/llvm-readobj`. -#[track_caller] -pub fn llvm_readobj() -> LlvmReadobj { - LlvmReadobj::new() -} - -/// A `llvm-readobj` invocation builder. -#[derive(Debug)] -#[must_use] -pub struct LlvmReadobj { - cmd: Command, -} - -crate::impl_common_helpers!(LlvmReadobj); - -impl LlvmReadobj { - /// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available - /// at `$LLVM_BIN_DIR/llvm-readobj`. - #[track_caller] - pub fn new() -> Self { - let llvm_bin_dir = env_var("LLVM_BIN_DIR"); - let llvm_bin_dir = PathBuf::from(llvm_bin_dir); - let llvm_readobj = llvm_bin_dir.join("llvm-readobj"); - let cmd = Command::new(llvm_readobj); - Self { cmd } - } - - /// Provide an input file. - pub fn input>(&mut self, path: P) -> &mut Self { - self.cmd.arg(path.as_ref()); - self - } - - /// Pass `--file-header` to display file headers. - pub fn file_header(&mut self) -> &mut Self { - self.cmd.arg("--file-header"); - self - } -} -- cgit 1.4.1-3-g733a5 From eb0bad46353de33f2d228ff7a8d9245254b64057 Mon Sep 17 00:00:00 2001 From: Jerry Wang Date: Sat, 15 Jun 2024 23:10:42 -0400 Subject: Add drop bombs to `llvm.rs` --- src/tools/run-make-support/src/llvm.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tools/run-make-support/src/llvm.rs b/src/tools/run-make-support/src/llvm.rs index 414251abda2..664093e072d 100644 --- a/src/tools/run-make-support/src/llvm.rs +++ b/src/tools/run-make-support/src/llvm.rs @@ -4,18 +4,21 @@ use crate::{env_var, Command}; /// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available /// at `$LLVM_BIN_DIR/llvm-readobj`. +#[track_caller] pub fn llvm_readobj() -> LlvmReadobj { LlvmReadobj::new() } /// Construct a new `llvm-profdata` invocation. This assumes that `llvm-profdata` is available /// at `$LLVM_BIN_DIR/llvm-profdata`. +#[track_caller] pub fn llvm_profdata() -> LlvmProfdata { LlvmProfdata::new() } /// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available /// at `$LLVM_FILECHECK`. +#[track_caller] pub fn llvm_filecheck() -> LlvmFilecheck { LlvmFilecheck::new() } @@ -55,6 +58,7 @@ pub fn llvm_bin_dir() -> PathBuf { impl LlvmReadobj { /// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available /// at `$LLVM_BIN_DIR/llvm-readobj`. + #[track_caller] pub fn new() -> Self { let llvm_readobj = llvm_bin_dir().join("llvm-readobj"); let cmd = Command::new(llvm_readobj); @@ -77,6 +81,7 @@ impl LlvmReadobj { impl LlvmProfdata { /// Construct a new `llvm-profdata` invocation. This assumes that `llvm-profdata` is available /// at `$LLVM_BIN_DIR/llvm-profdata`. + #[track_caller] pub fn new() -> Self { let llvm_profdata = llvm_bin_dir().join("llvm-profdata"); let cmd = Command::new(llvm_profdata); @@ -107,6 +112,7 @@ impl LlvmProfdata { impl LlvmFilecheck { /// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available /// at `$LLVM_FILECHECK`. + #[track_caller] pub fn new() -> Self { let llvm_filecheck = env_var("LLVM_FILECHECK"); let cmd = Command::new(llvm_filecheck); -- cgit 1.4.1-3-g733a5 From 893f95f1f7c663c67c884120003b3bf21b0af61a Mon Sep 17 00:00:00 2001 From: lukaslueg Date: Sun, 16 Jun 2024 09:07:08 +0200 Subject: Update `Arc::try_unwrap()` docs Clarify the language wrt `race condition` not meaning `memory unsafety`. --- library/alloc/src/sync.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 60e3918157e..f9d884e0ea5 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -940,15 +940,18 @@ impl Arc { /// This will succeed even if there are outstanding weak references. /// /// It is strongly recommended to use [`Arc::into_inner`] instead if you don't - /// want to keep the `Arc` in the [`Err`] case. - /// Immediately dropping the [`Err`] payload, like in the expression - /// `Arc::try_unwrap(this).ok()`, can still cause the strong count to - /// drop to zero and the inner value of the `Arc` to be dropped: - /// For instance if two threads each execute this expression in parallel, then - /// there is a race condition. The threads could first both check whether they - /// have the last clone of their `Arc` via `Arc::try_unwrap`, and then - /// both drop their `Arc` in the call to [`ok`][`Result::ok`], - /// taking the strong count from two down to zero. + /// keep the `Arc` in the [`Err`] case. + /// Immediately dropping the [`Err`]-value, as the expression + /// `Arc::try_unwrap(this).ok()` does, can cause the strong count to + /// drop to zero and the inner value of the `Arc` to be dropped. + /// For instance, if two threads execute such an expression in parallel, + /// there is a race condition without the possibility of unsafety: + /// The threads could first both check whether they own the last instance + /// in `Arc::try_unwrap`, determine that they both do not, and then both + /// discard and drop their instance in the call to [`ok`][`Result::ok`]. + /// In this scenario, the value inside the `Arc` is safely destroyed + /// by exactly one of the threads, but neither thread will ever be able + /// to use the value. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From ac751b3049ac6b7d080eae796acb215c5eb36df3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 16 Jun 2024 11:46:02 +0200 Subject: Migrate `run-make/duplicate-output-flavors` to `rmake.rs` --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/duplicate-output-flavors/Makefile | 5 ----- tests/run-make/duplicate-output-flavors/rmake.rs | 6 ++++++ 3 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 tests/run-make/duplicate-output-flavors/Makefile create mode 100644 tests/run-make/duplicate-output-flavors/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index be9df226d64..9a6111db79d 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -31,7 +31,6 @@ run-make/dep-info-spaces/Makefile run-make/dep-info/Makefile run-make/dump-ice-to-disk/Makefile run-make/dump-mono-stats/Makefile -run-make/duplicate-output-flavors/Makefile run-make/dylib-chain/Makefile run-make/emit-path-unhashed/Makefile run-make/emit-shared-files/Makefile diff --git a/tests/run-make/duplicate-output-flavors/Makefile b/tests/run-make/duplicate-output-flavors/Makefile deleted file mode 100644 index e33279966c9..00000000000 --- a/tests/run-make/duplicate-output-flavors/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) --crate-type=rlib foo.rs - $(RUSTC) --crate-type=rlib,rlib foo.rs diff --git a/tests/run-make/duplicate-output-flavors/rmake.rs b/tests/run-make/duplicate-output-flavors/rmake.rs new file mode 100644 index 00000000000..09545228807 --- /dev/null +++ b/tests/run-make/duplicate-output-flavors/rmake.rs @@ -0,0 +1,6 @@ +use run_make_support::rustc; + +fn main() { + rustc().input("foo.rs").crate_type("rlib").run(); + rustc().input("foo.rs").crate_type("rlib,rlib").run(); +} -- cgit 1.4.1-3-g733a5 From c6c1c992e2f7b7084cae6268fb9635f55bd5ecc6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 16 Jun 2024 00:53:00 +0300 Subject: rustc_span: Optimize more hygiene operations using `Span::map_ctxt` --- compiler/rustc_span/src/lib.rs | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index b7ffe6c618a..5c63e6b8649 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1065,33 +1065,41 @@ impl Span { #[inline] pub fn remove_mark(&mut self) -> ExpnId { - let mut span = self.data(); - let mark = span.ctxt.remove_mark(); - *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); + let mut mark = ExpnId::root(); + *self = self.map_ctxt(|mut ctxt| { + mark = ctxt.remove_mark(); + ctxt + }); mark } #[inline] pub fn adjust(&mut self, expn_id: ExpnId) -> Option { - let mut span = self.data(); - let mark = span.ctxt.adjust(expn_id); - *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); + let mut mark = None; + *self = self.map_ctxt(|mut ctxt| { + mark = ctxt.adjust(expn_id); + ctxt + }); mark } #[inline] pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option { - let mut span = self.data(); - let mark = span.ctxt.normalize_to_macros_2_0_and_adjust(expn_id); - *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); + let mut mark = None; + *self = self.map_ctxt(|mut ctxt| { + mark = ctxt.normalize_to_macros_2_0_and_adjust(expn_id); + ctxt + }); mark } #[inline] pub fn glob_adjust(&mut self, expn_id: ExpnId, glob_span: Span) -> Option> { - let mut span = self.data(); - let mark = span.ctxt.glob_adjust(expn_id, glob_span); - *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); + let mut mark = None; + *self = self.map_ctxt(|mut ctxt| { + mark = ctxt.glob_adjust(expn_id, glob_span); + ctxt + }); mark } @@ -1101,9 +1109,11 @@ impl Span { expn_id: ExpnId, glob_span: Span, ) -> Option> { - let mut span = self.data(); - let mark = span.ctxt.reverse_glob_adjust(expn_id, glob_span); - *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); + let mut mark = None; + *self = self.map_ctxt(|mut ctxt| { + mark = ctxt.reverse_glob_adjust(expn_id, glob_span); + ctxt + }); mark } -- cgit 1.4.1-3-g733a5 From 14da80c37279ada8d92d3f900414ebc0d7935e13 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 16 Jun 2024 00:53:00 +0300 Subject: rustc_span: Minor improvements Introduce `{IndexNewtype,SyntaxContext}::from_u16` for convenience because small indices are sometimes encoded as `u16`. Use `SpanData::span` instead of `Span::new` where appropriate. Add a clarifying comment about decoding span parents. --- compiler/rustc_index_macros/src/newtype.rs | 15 +++++++++++++++ compiler/rustc_infer/src/infer/mod.rs | 4 ++-- compiler/rustc_metadata/src/rmeta/decoder.rs | 4 ++-- compiler/rustc_span/src/hygiene.rs | 5 +++++ compiler/rustc_span/src/lib.rs | 4 ++-- compiler/rustc_span/src/span_encoding.rs | 15 +++++++-------- 6 files changed, 33 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs index fe9a048734f..41863f7b15f 100644 --- a/compiler/rustc_index_macros/src/newtype.rs +++ b/compiler/rustc_index_macros/src/newtype.rs @@ -205,6 +205,21 @@ impl Parse for Newtype { } } + /// Creates a new index from a given `u16`. + /// + /// # Panics + /// + /// Will panic if `value` exceeds `MAX`. + #[inline] + #vis const fn from_u16(value: u16) -> Self { + let value = value as u32; + assert!(value <= #max); + // SAFETY: We just checked that `value <= max`. + unsafe { + Self::from_u32_unchecked(value) + } + } + /// Creates a new index from a given `u32`. /// /// # Safety diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 9447ea06fdd..8412912b9f3 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -881,13 +881,13 @@ impl<'tcx> InferCtxt<'tcx> { .collect(); vars.extend( (0..inner.int_unification_table().len()) - .map(|i| ty::IntVid::from_u32(i as u32)) + .map(|i| ty::IntVid::from_usize(i)) .filter(|&vid| inner.int_unification_table().probe_value(vid).is_unknown()) .map(|v| Ty::new_int_var(self.tcx, v)), ); vars.extend( (0..inner.float_unification_table().len()) - .map(|i| ty::FloatVid::from_u32(i as u32)) + .map(|i| ty::FloatVid::from_usize(i)) .filter(|&vid| inner.float_unification_table().probe_value(vid).is_unknown()) .map(|v| Ty::new_float_var(self.tcx, v)), ); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 19bb943e6bc..ea7037740f1 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -539,7 +539,7 @@ impl<'a, 'tcx> SpanDecoder for DecodeContext<'a, 'tcx> { } else { SpanData::decode(self) }; - Span::new(data.lo, data.hi, data.ctxt, data.parent) + data.span() } fn decode_symbol(&mut self) -> Symbol { @@ -669,7 +669,7 @@ impl<'a, 'tcx> Decodable> for SpanData { let lo = lo + source_file.translated_source_file.start_pos; let hi = hi + source_file.translated_source_file.start_pos; - // Do not try to decode parent for foreign spans. + // Do not try to decode parent for foreign spans (it wasn't encoded in the first place). SpanData { lo, hi, ctxt, parent: None } } } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 00ef17d630c..ba0ad9230c8 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -691,6 +691,11 @@ impl SyntaxContext { SyntaxContext(raw) } + #[inline] + pub(crate) const fn from_u16(raw: u16) -> SyntaxContext { + SyntaxContext(raw as u32) + } + /// Extend a syntax context with a given expansion and transparency. pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { HygieneData::with(|data| data.apply_mark(self, expn_id, transparency)) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index b7ffe6c618a..9c557ed148c 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -967,7 +967,7 @@ impl Span { /// This span, but in a larger context, may switch to the metavariable span if suitable. pub fn with_neighbor(self, neighbor: Span) -> Span { match Span::prepare_to_combine(self, neighbor) { - Ok((this, ..)) => Span::new(this.lo, this.hi, this.ctxt, this.parent), + Ok((this, ..)) => this.span(), Err(_) => self, } } @@ -1352,7 +1352,7 @@ impl fmt::Debug for Span { impl fmt::Debug for SpanData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&Span::new(self.lo, self.hi, self.ctxt, self.parent), f) + fmt::Debug::fmt(&self.span(), f) } } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 9d5bc5b0512..31d2a9db01d 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -121,7 +121,7 @@ impl InlineCtxt { SpanData { lo: BytePos(self.lo), hi: BytePos(self.lo.debug_strict_add(len)), - ctxt: SyntaxContext::from_u32(self.ctxt as u32), + ctxt: SyntaxContext::from_u16(self.ctxt), parent: None, } } @@ -146,7 +146,7 @@ impl InlineParent { lo: BytePos(self.lo), hi: BytePos(self.lo.debug_strict_add(len)), ctxt: SyntaxContext::root(), - parent: Some(LocalDefId { local_def_index: DefIndex::from_u32(self.parent as u32) }), + parent: Some(LocalDefId { local_def_index: DefIndex::from_u16(self.parent) }), } } #[inline] @@ -167,7 +167,7 @@ impl PartiallyInterned { #[inline] fn data(self) -> SpanData { SpanData { - ctxt: SyntaxContext::from_u32(self.ctxt as u32), + ctxt: SyntaxContext::from_u16(self.ctxt), ..with_span_interner(|interner| interner.spans[self.index as usize]) } } @@ -331,8 +331,7 @@ impl Span { match_span_kind! { self, InlineCtxt(span) => { - updated_ctxt32 = - update(SyntaxContext::from_u32(span.ctxt as u32)).as_u32(); + updated_ctxt32 = update(SyntaxContext::from_u16(span.ctxt)).as_u32(); // Any small new context including zero will preserve the format. if updated_ctxt32 <= MAX_CTXT { return InlineCtxt::span(span.lo, span.len, updated_ctxt32 as u16); @@ -349,7 +348,7 @@ impl Span { data = span.data(); }, PartiallyInterned(span) => { - updated_ctxt32 = update(SyntaxContext::from_u32(span.ctxt as u32)).as_u32(); + updated_ctxt32 = update(SyntaxContext::from_u16(span.ctxt)).as_u32(); // Any small new context excluding zero will preserve the format. // Zero may change the format to `InlineParent` if parent and len are small enough. if updated_ctxt32 <= MAX_CTXT && updated_ctxt32 != 0 { @@ -373,9 +372,9 @@ impl Span { fn inline_ctxt(self) -> Result { match_span_kind! { self, - InlineCtxt(span) => Ok(SyntaxContext::from_u32(span.ctxt as u32)), + InlineCtxt(span) => Ok(SyntaxContext::from_u16(span.ctxt)), InlineParent(_span) => Ok(SyntaxContext::root()), - PartiallyInterned(span) => Ok(SyntaxContext::from_u32(span.ctxt as u32)), + PartiallyInterned(span) => Ok(SyntaxContext::from_u16(span.ctxt)), Interned(span) => Err(span.index as usize), } } -- cgit 1.4.1-3-g733a5 From cf9510cd3382fb1a5b4902a1b0e68af3e3274931 Mon Sep 17 00:00:00 2001 From: joboet Date: Sun, 16 Jun 2024 13:14:01 +0200 Subject: std: move `sys_common::backtrace` to `sys` --- library/std/src/backtrace.rs | 2 +- library/std/src/error.rs | 2 +- library/std/src/panicking.rs | 6 +- library/std/src/rt.rs | 2 +- library/std/src/sys/backtrace.rs | 227 +++++++++++++++++++++ library/std/src/sys/mod.rs | 1 + library/std/src/sys_common/backtrace.rs | 227 --------------------- library/std/src/sys_common/mod.rs | 1 - library/std/src/thread/mod.rs | 2 +- .../exported_symbol_bad_unwind2.both.stderr | 2 +- .../exported_symbol_bad_unwind2.definition.stderr | 2 +- .../fail/intrinsics/uninit_uninhabited_type.stderr | 2 +- .../miri/tests/fail/intrinsics/zero_fn_ptr.stderr | 2 +- .../miri/tests/fail/panic/double_panic.stderr | 2 +- .../miri/tests/fail/panic/panic_abort1.stderr | 2 +- .../miri/tests/fail/panic/panic_abort2.stderr | 2 +- .../miri/tests/fail/panic/panic_abort3.stderr | 2 +- .../miri/tests/fail/panic/panic_abort4.stderr | 2 +- .../miri/tests/fail/terminate-terminator.stderr | 2 +- .../miri/tests/fail/unwind-action-terminate.stderr | 2 +- .../tests/pass/backtrace/backtrace-api-v0.stderr | 2 +- .../tests/pass/backtrace/backtrace-api-v1.stderr | 2 +- .../pass/backtrace/backtrace-global-alloc.stderr | 4 +- .../miri/tests/pass/backtrace/backtrace-std.stderr | 4 +- 24 files changed, 252 insertions(+), 252 deletions(-) create mode 100644 library/std/src/sys/backtrace.rs delete mode 100644 library/std/src/sys_common/backtrace.rs diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index e3e0cde8afe..4d376753cb6 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -95,7 +95,7 @@ use crate::fmt; use crate::panic::UnwindSafe; use crate::sync::atomic::{AtomicU8, Ordering::Relaxed}; use crate::sync::LazyLock; -use crate::sys_common::backtrace::{lock, output_filename, set_image_base}; +use crate::sys::backtrace::{lock, output_filename, set_image_base}; /// A captured OS thread stack backtrace. /// diff --git a/library/std/src/error.rs b/library/std/src/error.rs index b240e4e2c45..87aad8f764b 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -429,7 +429,7 @@ impl Report { /// 1: rust_out::main::_doctest_main_src_error_rs_1158_0 /// 2: rust_out::main /// 3: core::ops::function::FnOnce::call_once - /// 4: std::sys_common::backtrace::__rust_begin_short_backtrace + /// 4: std::sys::backtrace::__rust_begin_short_backtrace /// 5: std::rt::lang_start::{{closure}} /// 6: std::panicking::try /// 7: std::rt::lang_start_internal diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 8fd8134c111..2bb5ea28b18 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -19,8 +19,8 @@ use crate::mem::{self, ManuallyDrop}; use crate::process; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{PoisonError, RwLock}; +use crate::sys::backtrace; use crate::sys::stdio::panic_output; -use crate::sys_common::backtrace; use crate::thread; #[cfg(not(test))] @@ -655,7 +655,7 @@ pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { let loc = info.location().unwrap(); // The current implementation always returns Some let msg = info.message(); - crate::sys_common::backtrace::__rust_end_short_backtrace(move || { + crate::sys::backtrace::__rust_end_short_backtrace(move || { if let Some(s) = msg.as_str() { rust_panic_with_hook( &mut StaticStrPayload(s), @@ -727,7 +727,7 @@ pub const fn begin_panic(msg: M) -> ! { } let loc = Location::caller(); - crate::sys_common::backtrace::__rust_end_short_backtrace(move || { + crate::sys::backtrace::__rust_end_short_backtrace(move || { rust_panic_with_hook( &mut Payload { inner: Some(msg) }, loc, diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 46f691d7b75..b03fa1c01f2 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -156,7 +156,7 @@ fn lang_start( sigpipe: u8, ) -> isize { let Ok(v) = lang_start_internal( - &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report().to_i32(), + &move || crate::sys::backtrace::__rust_begin_short_backtrace(main).report().to_i32(), argc, argv, sigpipe, diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs new file mode 100644 index 00000000000..0b2338fd7de --- /dev/null +++ b/library/std/src/sys/backtrace.rs @@ -0,0 +1,227 @@ +//! Common code for printing backtraces. + +use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt}; +use crate::borrow::Cow; +use crate::env; +use crate::fmt; +use crate::io; +use crate::io::prelude::*; +use crate::path::{self, Path, PathBuf}; +use crate::sync::{Mutex, PoisonError}; + +/// Max number of frames to print. +const MAX_NB_FRAMES: usize = 100; + +pub fn lock() -> impl Drop { + static LOCK: Mutex<()> = Mutex::new(()); + LOCK.lock().unwrap_or_else(PoisonError::into_inner) +} + +/// Prints the current backtrace. +pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { + // There are issues currently linking libbacktrace into tests, and in + // general during std's own unit tests we're not testing this path. In + // test mode immediately return here to optimize away any references to the + // libbacktrace symbols + if cfg!(test) { + return Ok(()); + } + + // Use a lock to prevent mixed output in multithreading context. + // Some platforms also requires it, like `SymFromAddr` on Windows. + unsafe { + let _lock = lock(); + _print(w, format) + } +} + +unsafe fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { + struct DisplayBacktrace { + format: PrintFmt, + } + impl fmt::Display for DisplayBacktrace { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + unsafe { _print_fmt(fmt, self.format) } + } + } + write!(w, "{}", DisplayBacktrace { format }) +} + +unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result { + // Always 'fail' to get the cwd when running under Miri - + // this allows Miri to display backtraces in isolation mode + let cwd = if !cfg!(miri) { env::current_dir().ok() } else { None }; + + let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| { + output_filename(fmt, bows, print_fmt, cwd.as_ref()) + }; + writeln!(fmt, "stack backtrace:")?; + let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path); + bt_fmt.add_context()?; + let mut idx = 0; + let mut res = Ok(()); + let mut omitted_count: usize = 0; + let mut first_omit = true; + // Start immediately if we're not using a short backtrace. + let mut start = print_fmt != PrintFmt::Short; + set_image_base(); + backtrace_rs::trace_unsynchronized(|frame| { + if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { + return false; + } + + let mut hit = false; + backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { + hit = true; + + // Any frames between `__rust_begin_short_backtrace` and `__rust_end_short_backtrace` + // are omitted from the backtrace in short mode, `__rust_end_short_backtrace` will be + // called before the panic hook, so we won't ignore any frames if there is no + // invoke of `__rust_begin_short_backtrace`. + if print_fmt == PrintFmt::Short { + if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { + if start && sym.contains("__rust_begin_short_backtrace") { + start = false; + return; + } + if sym.contains("__rust_end_short_backtrace") { + start = true; + return; + } + if !start { + omitted_count += 1; + } + } + } + + if start { + 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; + } + 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 && start { + 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; + } + if !hit && start { + res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); + } + + idx += 1; + res.is_ok() + }); + res?; + bt_fmt.finish()?; + if print_fmt == PrintFmt::Short { + writeln!( + fmt, + "note: Some details are omitted, \ + run with `RUST_BACKTRACE=full` for a verbose backtrace." + )?; + } + Ok(()) +} + +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that +/// this is only inline(never) when backtraces in std are enabled, otherwise +/// it's fine to optimize away. +#[cfg_attr(feature = "backtrace", inline(never))] +pub fn __rust_begin_short_backtrace(f: F) -> T +where + F: FnOnce() -> T, +{ + let result = f(); + + // prevent this frame from being tail-call optimised away + crate::hint::black_box(()); + + result +} + +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that +/// this is only inline(never) when backtraces in std are enabled, otherwise +/// it's fine to optimize away. +#[cfg_attr(feature = "backtrace", inline(never))] +pub fn __rust_end_short_backtrace(f: F) -> T +where + F: FnOnce() -> T, +{ + let result = f(); + + // prevent this frame from being tail-call optimised away + crate::hint::black_box(()); + + result +} + +/// Prints the filename of the backtrace frame. +/// +/// See also `output`. +pub fn output_filename( + fmt: &mut fmt::Formatter<'_>, + bows: BytesOrWideString<'_>, + print_fmt: PrintFmt, + cwd: Option<&PathBuf>, +) -> fmt::Result { + let file: Cow<'_, Path> = match bows { + #[cfg(unix)] + BytesOrWideString::Bytes(bytes) => { + use crate::os::unix::prelude::*; + Path::new(crate::ffi::OsStr::from_bytes(bytes)).into() + } + #[cfg(not(unix))] + BytesOrWideString::Bytes(bytes) => { + Path::new(crate::str::from_utf8(bytes).unwrap_or("")).into() + } + #[cfg(windows)] + BytesOrWideString::Wide(wide) => { + use crate::os::windows::prelude::*; + Cow::Owned(crate::ffi::OsString::from_wide(wide).into()) + } + #[cfg(not(windows))] + BytesOrWideString::Wide(_wide) => Path::new("").into(), + }; + if print_fmt == PrintFmt::Short && file.is_absolute() { + if let Some(cwd) = cwd { + if let Ok(stripped) = file.strip_prefix(&cwd) { + if let Some(s) = stripped.to_str() { + return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR); + } + } + } + } + fmt::Display::fmt(&file.display(), fmt) +} + +#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] +pub fn set_image_base() { + let image_base = crate::os::fortanix_sgx::mem::image_base(); + backtrace_rs::set_image_base(crate::ptr::without_provenance_mut(image_base as _)); +} + +#[cfg(not(all(target_vendor = "fortanix", target_env = "sgx")))] +pub fn set_image_base() { + // nothing to do for platforms other than SGX +} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 8f70cefc601..8aa35c40fe0 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -5,6 +5,7 @@ mod pal; mod personality; +pub mod backtrace; pub mod cmath; pub mod os_str; pub mod path; diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs deleted file mode 100644 index 67711dbd5bc..00000000000 --- a/library/std/src/sys_common/backtrace.rs +++ /dev/null @@ -1,227 +0,0 @@ -use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt}; -use crate::borrow::Cow; -/// Common code for printing the backtrace in the same way across the different -/// supported platforms. -use crate::env; -use crate::fmt; -use crate::io; -use crate::io::prelude::*; -use crate::path::{self, Path, PathBuf}; -use crate::sync::{Mutex, PoisonError}; - -/// Max number of frames to print. -const MAX_NB_FRAMES: usize = 100; - -pub fn lock() -> impl Drop { - static LOCK: Mutex<()> = Mutex::new(()); - LOCK.lock().unwrap_or_else(PoisonError::into_inner) -} - -/// Prints the current backtrace. -pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { - // There are issues currently linking libbacktrace into tests, and in - // general during std's own unit tests we're not testing this path. In - // test mode immediately return here to optimize away any references to the - // libbacktrace symbols - if cfg!(test) { - return Ok(()); - } - - // Use a lock to prevent mixed output in multithreading context. - // Some platforms also requires it, like `SymFromAddr` on Windows. - unsafe { - let _lock = lock(); - _print(w, format) - } -} - -unsafe fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { - struct DisplayBacktrace { - format: PrintFmt, - } - impl fmt::Display for DisplayBacktrace { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - unsafe { _print_fmt(fmt, self.format) } - } - } - write!(w, "{}", DisplayBacktrace { format }) -} - -unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result { - // Always 'fail' to get the cwd when running under Miri - - // this allows Miri to display backtraces in isolation mode - let cwd = if !cfg!(miri) { env::current_dir().ok() } else { None }; - - let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| { - output_filename(fmt, bows, print_fmt, cwd.as_ref()) - }; - writeln!(fmt, "stack backtrace:")?; - let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path); - bt_fmt.add_context()?; - let mut idx = 0; - let mut res = Ok(()); - let mut omitted_count: usize = 0; - let mut first_omit = true; - // Start immediately if we're not using a short backtrace. - let mut start = print_fmt != PrintFmt::Short; - set_image_base(); - backtrace_rs::trace_unsynchronized(|frame| { - if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { - return false; - } - - let mut hit = false; - backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { - hit = true; - - // Any frames between `__rust_begin_short_backtrace` and `__rust_end_short_backtrace` - // are omitted from the backtrace in short mode, `__rust_end_short_backtrace` will be - // called before the panic hook, so we won't ignore any frames if there is no - // invoke of `__rust_begin_short_backtrace`. - if print_fmt == PrintFmt::Short { - if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { - if start && sym.contains("__rust_begin_short_backtrace") { - start = false; - return; - } - if sym.contains("__rust_end_short_backtrace") { - start = true; - return; - } - if !start { - omitted_count += 1; - } - } - } - - if start { - 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; - } - 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 && start { - 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; - } - if !hit && start { - res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); - } - - idx += 1; - res.is_ok() - }); - res?; - bt_fmt.finish()?; - if print_fmt == PrintFmt::Short { - writeln!( - fmt, - "note: Some details are omitted, \ - run with `RUST_BACKTRACE=full` for a verbose backtrace." - )?; - } - Ok(()) -} - -/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that -/// this is only inline(never) when backtraces in std are enabled, otherwise -/// it's fine to optimize away. -#[cfg_attr(feature = "backtrace", inline(never))] -pub fn __rust_begin_short_backtrace(f: F) -> T -where - F: FnOnce() -> T, -{ - let result = f(); - - // prevent this frame from being tail-call optimised away - crate::hint::black_box(()); - - result -} - -/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that -/// this is only inline(never) when backtraces in std are enabled, otherwise -/// it's fine to optimize away. -#[cfg_attr(feature = "backtrace", inline(never))] -pub fn __rust_end_short_backtrace(f: F) -> T -where - F: FnOnce() -> T, -{ - let result = f(); - - // prevent this frame from being tail-call optimised away - crate::hint::black_box(()); - - result -} - -/// Prints the filename of the backtrace frame. -/// -/// See also `output`. -pub fn output_filename( - fmt: &mut fmt::Formatter<'_>, - bows: BytesOrWideString<'_>, - print_fmt: PrintFmt, - cwd: Option<&PathBuf>, -) -> fmt::Result { - let file: Cow<'_, Path> = match bows { - #[cfg(unix)] - BytesOrWideString::Bytes(bytes) => { - use crate::os::unix::prelude::*; - Path::new(crate::ffi::OsStr::from_bytes(bytes)).into() - } - #[cfg(not(unix))] - BytesOrWideString::Bytes(bytes) => { - Path::new(crate::str::from_utf8(bytes).unwrap_or("")).into() - } - #[cfg(windows)] - BytesOrWideString::Wide(wide) => { - use crate::os::windows::prelude::*; - Cow::Owned(crate::ffi::OsString::from_wide(wide).into()) - } - #[cfg(not(windows))] - BytesOrWideString::Wide(_wide) => Path::new("").into(), - }; - if print_fmt == PrintFmt::Short && file.is_absolute() { - if let Some(cwd) = cwd { - if let Ok(stripped) = file.strip_prefix(&cwd) { - if let Some(s) = stripped.to_str() { - return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR); - } - } - } - } - fmt::Display::fmt(&file.display(), fmt) -} - -#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] -pub fn set_image_base() { - let image_base = crate::os::fortanix_sgx::mem::image_base(); - backtrace_rs::set_image_base(crate::ptr::without_provenance_mut(image_base as _)); -} - -#[cfg(not(all(target_vendor = "fortanix", target_env = "sgx")))] -pub fn set_image_base() { - // nothing to do for platforms other than SGX -} diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 3a38ba1100f..200ea028a08 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -20,7 +20,6 @@ #[cfg(test)] mod tests; -pub mod backtrace; pub mod fs; pub mod io; pub mod lazy_box; diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 83e27dfb746..c8ee365392f 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -539,7 +539,7 @@ impl Builder { let f = f.into_inner(); set_current(their_thread); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { - crate::sys_common::backtrace::__rust_begin_short_backtrace(f) + crate::sys::backtrace::__rust_begin_short_backtrace(f) })); // SAFETY: `their_packet` as been built just above and moved by the // closure (it is an Arc<...>) and `my_packet` will be stored in the diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index d88781ed225..112a9687837 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -16,7 +16,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index d88781ed225..112a9687837 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -16,7 +16,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr index 447f7cae6ce..8dd76edafea 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr @@ -13,7 +13,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr index bae34149807..55f66a275b6 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr @@ -13,7 +13,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index 3b7a1511fa0..5829c1897bb 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -18,7 +18,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind_nobacktrace` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_in_cleanup` at RUSTLIB/core/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.stderr b/src/tools/miri/tests/fail/panic/panic_abort1.stderr index 7694cc70b22..d4abf19cd1e 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort1.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort1.stderr @@ -14,7 +14,7 @@ LL | ABORT(); = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` --> $DIR/panic_abort1.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.stderr b/src/tools/miri/tests/fail/panic/panic_abort2.stderr index e6a4380ea51..507f17abf4e 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort2.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort2.stderr @@ -14,7 +14,7 @@ LL | ABORT(); = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` --> $DIR/panic_abort2.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.stderr b/src/tools/miri/tests/fail/panic/panic_abort3.stderr index 23e2021eeef..a5d8b4d2eeb 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort3.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort3.stderr @@ -14,7 +14,7 @@ LL | ABORT(); = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` --> $DIR/panic_abort3.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.stderr b/src/tools/miri/tests/fail/panic/panic_abort4.stderr index 20a0ddb9019..62fbbf942cb 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort4.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort4.stderr @@ -14,7 +14,7 @@ LL | ABORT(); = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` --> $DIR/panic_abort4.rs:LL:CC diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr index f737adc561d..a5fa0b3e07a 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.stderr +++ b/src/tools/miri/tests/fail/terminate-terminator.stderr @@ -18,7 +18,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr index 7e722f7be32..547d550d3d0 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.stderr +++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr @@ -16,7 +16,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr index bc24d6de734..c05950ebdc7 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr @@ -4,7 +4,7 @@ $DIR/backtrace-api-v0.rs:LL:CC (func_b) $DIR/backtrace-api-v0.rs:LL:CC (func_a) $DIR/backtrace-api-v0.rs:LL:CC (main) RUSTLIB/core/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) -RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) +RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::sys::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr index 246e54becd8..b56d983d429 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr @@ -4,7 +4,7 @@ $DIR/backtrace-api-v1.rs:LL:CC (func_b) $DIR/backtrace-api-v1.rs:LL:CC (func_a) $DIR/backtrace-api-v1.rs:LL:CC (main) RUSTLIB/core/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) -RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) +RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::sys::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr index c48061d64d0..b06dd1da3c6 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr @@ -2,8 +2,8 @@ at $DIR/backtrace-global-alloc.rs:LL:CC 1: >::call_once - shim(fn()) at RUSTLIB/core/src/ops/function.rs:LL:CC - 2: std::sys_common::backtrace::__rust_begin_short_backtrace - at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + 2: std::sys::backtrace::__rust_begin_short_backtrace + at RUSTLIB/std/src/sys/backtrace.rs:LL:CC 3: std::rt::lang_start::{closure#0} at RUSTLIB/std/src/rt.rs:LL:CC 4: std::ops::function::impls::call_once diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr index 4596cadb958..84bdda59fce 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr @@ -10,8 +10,8 @@ at $DIR/backtrace-std.rs:LL:CC 5: >::call_once - shim(fn()) at RUSTLIB/core/src/ops/function.rs:LL:CC - 6: std::sys_common::backtrace::__rust_begin_short_backtrace - at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + 6: std::sys::backtrace::__rust_begin_short_backtrace + at RUSTLIB/std/src/sys/backtrace.rs:LL:CC 7: std::rt::lang_start::{closure#0} at RUSTLIB/std/src/rt.rs:LL:CC 8: std::ops::function::impls::call_once -- cgit 1.4.1-3-g733a5 From 60a972db83abfa406d48b259b7495d57c98b0c29 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 9 Jun 2024 12:35:27 +0000 Subject: Several fixes to the redox target specs * Allow crt-static for dylibs * Pass -lgcc to the linker --- compiler/rustc_target/src/spec/base/redox.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/base/redox.rs b/compiler/rustc_target/src/spec/base/redox.rs index 468fe478549..9070791e9df 100644 --- a/compiler/rustc_target/src/spec/base/redox.rs +++ b/compiler/rustc_target/src/spec/base/redox.rs @@ -1,4 +1,4 @@ -use crate::spec::{cvs, RelroLevel, TargetOptions}; +use crate::spec::{cvs, Cc, LinkerFlavor, Lld, RelroLevel, TargetOptions}; pub fn opts() -> TargetOptions { TargetOptions { @@ -12,6 +12,8 @@ pub fn opts() -> TargetOptions { has_thread_local: true, crt_static_default: true, crt_static_respected: true, + crt_static_allows_dylibs: true, + late_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-lgcc"]), ..Default::default() } } -- cgit 1.4.1-3-g733a5 From efa213afad8fd60886a78cab73d87e8d31295809 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 12:38:06 +0000 Subject: Add i686-unknown-redox target Co-Authored-By: Jeremy Soller --- compiler/rustc_target/src/spec/mod.rs | 1 + .../src/spec/targets/i686_unknown_redox.rs | 27 ++++++++++++++++++++++ src/doc/rustc/src/platform-support.md | 1 + src/tools/build-manifest/src/main.rs | 1 + tests/assembly/targets/targets-elf.rs | 3 +++ 5 files changed, 33 insertions(+) create mode 100644 compiler/rustc_target/src/spec/targets/i686_unknown_redox.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index adea2caabbe..42860b1059e 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1647,6 +1647,7 @@ supported_targets! { ("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc), ("aarch64-unknown-redox", aarch64_unknown_redox), + ("i686-unknown-redox", i686_unknown_redox), ("x86_64-unknown-redox", x86_64_unknown_redox), ("i386-apple-ios", i386_apple_ios), diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_redox.rs new file mode 100644 index 00000000000..83252fadb78 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_redox.rs @@ -0,0 +1,27 @@ +use crate::spec::{base, Cc, LinkerFlavor, Lld, StackProbeType, Target}; + +pub fn target() -> Target { + let mut base = base::redox::opts(); + base.cpu = "pentiumpro".into(); + base.plt_by_default = false; + base.max_atomic_width = Some(64); + base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; + + Target { + llvm_target: "i686-unknown-redox".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: None, + host_tools: None, + std: None, + }, + pointer_width: 32, + data_layout: + "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128" + .into(), + arch: "x86".into(), + options: base, + } +} diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index e55bb3bd155..4fe5eb802e5 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -300,6 +300,7 @@ target | std | host | notes [`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd [^x86_32-floats-return-ABI] [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2 [^x86_32-floats-return-ABI] [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD [^x86_32-floats-return-ABI] +`i686-unknown-redox` | ? | | i686 Redox OS `i686-uwp-windows-gnu` | ✓ | | [^x86_32-floats-return-ABI] `i686-uwp-windows-msvc` | ✓ | | [^x86_32-floats-return-ABI] [`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index b4d47cba7c5..a709aab7ce2 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -103,6 +103,7 @@ static TARGETS: &[&str] = &[ "i686-unknown-freebsd", "i686-unknown-linux-gnu", "i686-unknown-linux-musl", + "i686-unknown-redox", "i686-unknown-uefi", "loongarch64-unknown-linux-gnu", "loongarch64-unknown-none", diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 4c54fe639e3..b069e667bf5 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -228,6 +228,9 @@ //@ revisions: i686_unknown_openbsd //@ [i686_unknown_openbsd] compile-flags: --target i686-unknown-openbsd //@ [i686_unknown_openbsd] needs-llvm-components: x86 +//@ revisions: i686_unknown_redox +//@ [i686_unknown_redox] compile-flags: --target i686-unknown-redox +//@ [i686_unknown_redox] needs-llvm-components: x86 //@ revisions: i686_wrs_vxworks //@ [i686_wrs_vxworks] compile-flags: --target i686-wrs-vxworks //@ [i686_wrs_vxworks] needs-llvm-components: x86 -- cgit 1.4.1-3-g733a5 From 3cddc042300b3e804de48b278eb37964e642a68f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 11 Feb 2023 18:34:41 -0700 Subject: Use Linux file locking on Redox --- compiler/rustc_data_structures/src/flock.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs index 008565e4c7b..e03962a54ec 100644 --- a/compiler/rustc_data_structures/src/flock.rs +++ b/compiler/rustc_data_structures/src/flock.rs @@ -9,6 +9,10 @@ cfg_match! { mod linux; use linux as imp; } + cfg(target_os = "redox") => { + mod linux; + use linux as imp; + } cfg(unix) => { mod unix; use unix as imp; -- cgit 1.4.1-3-g733a5 From 742a923b28304303b04d10eecb616cec0c557334 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 15:50:58 +0000 Subject: Add dedicated platform support page for Redox OS --- src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 6 ++-- src/doc/rustc/src/platform-support/redox.md | 53 +++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 src/doc/rustc/src/platform-support/redox.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 201ace5ce3a..e76ebb8f8aa 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -71,6 +71,7 @@ - [*-unknown-hermit](platform-support/hermit.md) - [\*-unknown-netbsd\*](platform-support/netbsd.md) - [*-unknown-openbsd](platform-support/openbsd.md) + - [*-unknown-redox](platform-support/redox.md) - [\*-unknown-uefi](platform-support/unknown-uefi.md) - [wasm32-wasip1](platform-support/wasm32-wasip1.md) - [wasm32-wasip1-threads](platform-support/wasm32-wasip1-threads.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 4fe5eb802e5..834e909c065 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -203,7 +203,7 @@ target | std | notes `x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27) [`x86_64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | x86_64 OpenHarmony [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat -`x86_64-unknown-redox` | ✓ | Redox OS +[`x86_64-unknown-redox`](platform-support/redox.md) | ✓ | Redox OS [`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 64-bit UEFI [^x86_32-floats-x87]: Floating-point support on `i586` targets is non-compliant: the `x87` registers and instructions used for these targets do not provide IEEE-754-compliant behavior, in particular when it comes to rounding and NaN payload bits. See [issue #114479][x86-32-float-issue]. @@ -258,7 +258,7 @@ target | std | host | notes `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD -`aarch64-unknown-redox` | ? | | ARM64 Redox OS +[`aarch64-unknown-redox`](platform-support/redox.md) | ✓ | | ARM64 Redox OS `aarch64-uwp-windows-msvc` | ✓ | | `aarch64-wrs-vxworks` | ? | | `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI) @@ -300,7 +300,7 @@ target | std | host | notes [`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd [^x86_32-floats-return-ABI] [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2 [^x86_32-floats-return-ABI] [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD [^x86_32-floats-return-ABI] -`i686-unknown-redox` | ? | | i686 Redox OS +[`i686-unknown-redox`](platform-support/redox.md) | ✓ | | i686 Redox OS `i686-uwp-windows-gnu` | ✓ | | [^x86_32-floats-return-ABI] `i686-uwp-windows-msvc` | ✓ | | [^x86_32-floats-return-ABI] [`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] diff --git a/src/doc/rustc/src/platform-support/redox.md b/src/doc/rustc/src/platform-support/redox.md new file mode 100644 index 00000000000..1b3321956ef --- /dev/null +++ b/src/doc/rustc/src/platform-support/redox.md @@ -0,0 +1,53 @@ +# `*-unknown-redox` + +**Tier: 2/3** + +Targets for the [Redox OS](https://redox-os.org/) operating +system. + +Target triplets available so far: + +- `x86_64-unknown-redox` (tier 2) +- `aarch64-unknown-redox` (tier 3) +- `i686-unknown-redox` (tier 3) + +## Target maintainers + +- Jeremy Soller ([@jackpot51](https://github.com/jackpot51)) + +## Requirements + +These targets are natively compiled and can be cross-compiled. Std is fully supported. + +The targets are only expected to work with the latest version of Redox OS as the ABI is not yet stable. + +`extern "C"` uses the official calling convention of the respective architectures. + +Redox OS binaries use ELF as file format. + +## Building the target + +You can build Rust with support for the targets by adding it to the `target` list in `config.toml`. In addition a copy of [relibc] needs to be present in the linker search path. + +```toml +[build] +build-stage = 1 +target = [ + "", + "x86_64-unknown-redox", + "aarch64-unknown-redox", + "i686-unknown-redox", +] +``` + +[relibc]: https://gitlab.redox-os.org/redox-os/relibc + +## Building Rust programs and testing + +Rust does not yet ship pre-compiled artifacts for Redox OS except for x86_64-unknown-redox. + +The easiest way to build and test programs for Redox OS is using [redoxer](https://gitlab.redox-os.org/redox-os/redoxer) which sets up the required compiler toolchain for building as well as runs programs inside a Redox OS VM using QEMU. + +## Cross-compilation toolchains and C code + +The target supports C code. Pre-compiled C toolchains can be found at . -- cgit 1.4.1-3-g733a5 From ff096f83f7b2f1f5feeeea9f29d23c9dde5393c9 Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Sun, 16 Jun 2024 20:38:08 +0200 Subject: more ice tests --- tests/crashes/126062.rs | 11 +++++++++++ tests/crashes/126148.rs | 23 +++++++++++++++++++++++ tests/crashes/126182.rs | 10 ++++++++++ tests/crashes/126267.rs | 30 ++++++++++++++++++++++++++++++ tests/crashes/126269.rs | 12 ++++++++++++ tests/crashes/126272.rs | 28 ++++++++++++++++++++++++++++ tests/crashes/126359.rs | 9 +++++++++ tests/crashes/126376.rs | 14 ++++++++++++++ tests/crashes/126377.rs | 29 +++++++++++++++++++++++++++++ tests/crashes/126385.rs | 10 ++++++++++ tests/crashes/126389.rs | 15 +++++++++++++++ tests/crashes/126416.rs | 20 ++++++++++++++++++++ tests/crashes/126521.rs | 11 +++++++++++ 13 files changed, 222 insertions(+) create mode 100644 tests/crashes/126062.rs create mode 100644 tests/crashes/126148.rs create mode 100644 tests/crashes/126182.rs create mode 100644 tests/crashes/126267.rs create mode 100644 tests/crashes/126269.rs create mode 100644 tests/crashes/126272.rs create mode 100644 tests/crashes/126359.rs create mode 100644 tests/crashes/126376.rs create mode 100644 tests/crashes/126377.rs create mode 100644 tests/crashes/126385.rs create mode 100644 tests/crashes/126389.rs create mode 100644 tests/crashes/126416.rs create mode 100644 tests/crashes/126521.rs diff --git a/tests/crashes/126062.rs b/tests/crashes/126062.rs new file mode 100644 index 00000000000..9f1bec1d46e --- /dev/null +++ b/tests/crashes/126062.rs @@ -0,0 +1,11 @@ +//@ known-bug: rust-lang/rust#126062 +struct Fail(Fail); +impl Fail { + const C: () = panic!(); +} + +fn f() { + if false { + let _val = &Fail::::C; + } +} diff --git a/tests/crashes/126148.rs b/tests/crashes/126148.rs new file mode 100644 index 00000000000..79f8887b401 --- /dev/null +++ b/tests/crashes/126148.rs @@ -0,0 +1,23 @@ +//@ known-bug: rust-lang/rust#126148 + +#![feature(effects)] +use std::ops::{FromResidual, Try}; + +struct TryMe; +struct Error; + +impl const FromResidual for TryMe {} + +impl const Try for TryMe { + type Output = (); + type Residual = Error; +} + +const fn t() -> TryMe { + TryMe?; + TryMe +} + +const _: () = { + t(); +}; diff --git a/tests/crashes/126182.rs b/tests/crashes/126182.rs new file mode 100644 index 00000000000..2219a6cb5fa --- /dev/null +++ b/tests/crashes/126182.rs @@ -0,0 +1,10 @@ +//@ known-bug: rust-lang/rust#126182 + +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +struct Cond; + +struct Thing>(T); + +impl Thing {} diff --git a/tests/crashes/126267.rs b/tests/crashes/126267.rs new file mode 100644 index 00000000000..c0604b90a67 --- /dev/null +++ b/tests/crashes/126267.rs @@ -0,0 +1,30 @@ +//@ known-bug: rust-lang/rust#126267 + +#![feature(transmutability)] +#![crate_type = "lib"] + +pub enum ApiError {} +pub struct TokioError { + b: bool, +} +pub enum Error { + Api { source: ApiError }, + Ethereum, + Tokio { source: TokioError }, +} + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom, // safety is NOT assumed + { + } +} + +fn test() { + struct Src; + type Dst = Error; + assert::is_transmutable::(); +} diff --git a/tests/crashes/126269.rs b/tests/crashes/126269.rs new file mode 100644 index 00000000000..ca4b76eb930 --- /dev/null +++ b/tests/crashes/126269.rs @@ -0,0 +1,12 @@ +//@ known-bug: rust-lang/rust#126269 +#![feature(coerce_unsized)] + +pub enum Foo { + Bar([T; usize::MAX]), +} + +use std::ops::CoerceUnsized; + +impl CoerceUnsized for T {} + +fn main() {} diff --git a/tests/crashes/126272.rs b/tests/crashes/126272.rs new file mode 100644 index 00000000000..3412c7d8f0f --- /dev/null +++ b/tests/crashes/126272.rs @@ -0,0 +1,28 @@ +//@ known-bug: rust-lang/rust#126272 + +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(Debug, PartialEq, Eq, ConstParamTy)] +struct Foo { + value: i32, + nested: &'static Bar, +} + +#[derive(Debug, PartialEq, Eq, ConstParamTy)] +struct Bar(T); + +struct Test; + +fn main() { + let x: Test< + { + Foo { + value: 3, + nested: &Bar(4), + } + }, + > = Test; +} diff --git a/tests/crashes/126359.rs b/tests/crashes/126359.rs new file mode 100644 index 00000000000..4b28c466b55 --- /dev/null +++ b/tests/crashes/126359.rs @@ -0,0 +1,9 @@ +//@ known-bug: rust-lang/rust#126359 + +struct OppOrder { + arr: [T; N], +} + +fn main() { + let _ = OppOrder::<3, u32> { arr: [0, 0, 0] }; +} diff --git a/tests/crashes/126376.rs b/tests/crashes/126376.rs new file mode 100644 index 00000000000..028dde6d438 --- /dev/null +++ b/tests/crashes/126376.rs @@ -0,0 +1,14 @@ +//@ known-bug: rust-lang/rust#126376 +mod a { + pub mod b { + pub mod c { + pub trait D {} + } + } +} + +use a::*; +use e as b; +use b::c::D as e; + +fn e() {} diff --git a/tests/crashes/126377.rs b/tests/crashes/126377.rs new file mode 100644 index 00000000000..f8b9b693b65 --- /dev/null +++ b/tests/crashes/126377.rs @@ -0,0 +1,29 @@ +//@ known-bug: rust-lang/rust#126377 + +#![feature(effects)] +#![feature(generic_const_exprs)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_transmutable< + Src, + Dst, + const ASSUME_ALIGNMENT: bool, + const ASSUME_LIFETIMES: bool, + const ASSUME_SAFETY: bool, + const ASSUME_VALIDITY: bool, + >() + where + Dst: BikeshedIntrinsicFrom< + Src, + { } + >, + {} +} + +const fn from_options() -> Assume { + #[repr(C)] struct Src; + #[repr(C)] struct Dst; + assert::is_transmutable::(); +} diff --git a/tests/crashes/126385.rs b/tests/crashes/126385.rs new file mode 100644 index 00000000000..9e74e88c1ff --- /dev/null +++ b/tests/crashes/126385.rs @@ -0,0 +1,10 @@ +//@ known-bug: rust-lang/rust#126385 +pub struct MyStruct<'field> { + field: &'_ [u32], +} + +impl MyStruct<'_> { + pub fn _<'a>(field: &'a[u32]) -> Self { + Self{field} + } +} diff --git a/tests/crashes/126389.rs b/tests/crashes/126389.rs new file mode 100644 index 00000000000..7aa6ecad9a3 --- /dev/null +++ b/tests/crashes/126389.rs @@ -0,0 +1,15 @@ +//@ known-bug: rust-lang/rust#126389 + +mod a { + pub mod b { + pub mod c {} + } +} + +use a::*; + +use b::c; + +use c as b; + +fn c() {} diff --git a/tests/crashes/126416.rs b/tests/crashes/126416.rs new file mode 100644 index 00000000000..9b6c5169d44 --- /dev/null +++ b/tests/crashes/126416.rs @@ -0,0 +1,20 @@ +//@ known-bug: rust-lang/rust#126416 + +trait Output<'a, T: 'a> { + type Type; +} + +struct Wrapper; + +impl Wrapper { + fn do_something_wrapper(&mut self, _: F) + where + F: for<'a> FnOnce(>::Type), + { + } +} + +fn main() { + let mut wrapper = Wrapper; + wrapper.do_something_wrapper(|value| ()); +} diff --git a/tests/crashes/126521.rs b/tests/crashes/126521.rs new file mode 100644 index 00000000000..0a025aabcf2 --- /dev/null +++ b/tests/crashes/126521.rs @@ -0,0 +1,11 @@ +//@ known-bug: rust-lang/rust#126521 +macro_rules! foo { + ($val:ident) => { + true; + }; +} + +fn main() { + #[expect(semicolon_in_expressions_from_macros)] + let _ = foo!(x); +} -- cgit 1.4.1-3-g733a5 From dfe69f7259914326fbccbf278d2ad93be4baba70 Mon Sep 17 00:00:00 2001 From: Kalle Wachsmuth Date: Sun, 16 Jun 2024 20:57:48 +0200 Subject: boxed_slice_into_iter: tiny doc correction --- compiler/rustc_lint/src/shadowed_into_iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs index 85006421fdd..da2b5878b19 100644 --- a/compiler/rustc_lint/src/shadowed_into_iter.rs +++ b/compiler/rustc_lint/src/shadowed_into_iter.rs @@ -52,7 +52,7 @@ declare_lint! { /// Since Rust 1.80.0, boxed slices implement `IntoIterator`. However, to avoid /// breakage, `boxed_slice.into_iter()` in Rust 2015, 2018, and 2021 code will still /// behave as `(&boxed_slice).into_iter()`, returning an iterator over - /// references, just like in Rust 1.80.0 and earlier. + /// references, just like in Rust 1.79.0 and earlier. /// This only applies to the method call syntax `boxed_slice.into_iter()`, not to /// any other syntax such as `for _ in boxed_slice` or `IntoIterator::into_iter(boxed_slice)`. pub BOXED_SLICE_INTO_ITER, -- cgit 1.4.1-3-g733a5 From 279bf05ffbd363f7250e8c57667fdac0c629c7f7 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 19 Jun 2024 07:33:12 +0300 Subject: remove `GIT_DIR` handling in pre-push hook This is already handled from bootstrap at https://github.com/rust-lang/rust/blob/a1ca449981e3b8442e358026437b7bedb9a1458e/src/bootstrap/src/utils/helpers.rs#L504-L506. Signed-off-by: onur-ozkan --- src/etc/pre-push.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/etc/pre-push.sh b/src/etc/pre-push.sh index c9e1a2733fd..6f86c7ab8a4 100755 --- a/src/etc/pre-push.sh +++ b/src/etc/pre-push.sh @@ -7,8 +7,6 @@ set -Euo pipefail -# https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570 -unset GIT_DIR ROOT_DIR="$(git rev-parse --show-toplevel)" echo "Running pre-push script $ROOT_DIR/x test tidy" -- cgit 1.4.1-3-g733a5